001 package railo.runtime.functions.image; 002 003 import java.awt.Composite; 004 import java.awt.Font; 005 import java.awt.Paint; 006 import java.awt.Point; 007 import java.awt.geom.AffineTransform; 008 import java.awt.geom.Point2D; 009 import java.awt.image.BufferedImage; 010 import java.awt.image.Kernel; 011 import java.lang.reflect.Method; 012 import java.util.ArrayList; 013 import java.util.Arrays; 014 import java.util.HashMap; 015 import java.util.Map; 016 017 import railo.commons.lang.StringUtil; 018 import railo.runtime.PageContext; 019 import railo.runtime.exp.FunctionException; 020 import railo.runtime.exp.PageException; 021 import railo.runtime.img.Image; 022 import railo.runtime.img.filter.*; 023 import railo.runtime.img.math.BinaryFunction; 024 import railo.runtime.img.math.Function2D; 025 import railo.runtime.op.Caster; 026 import railo.runtime.type.Struct; 027 import railo.runtime.type.StructImpl; 028 import railo.runtime.type.util.ListUtil; 029 030 public class ImageFilter { 031 private static final Struct EMPTY_STRUCT = new StructImpl(); 032 private static Map<String,Class> filters=new HashMap<String, Class>(); 033 static { 034 filters.put("applymask",ApplyMaskFilter.class); 035 filters.put("average",AverageFilter.class); 036 filters.put("bicubicscale",BicubicScaleFilter.class); 037 filters.put("block",BlockFilter.class); 038 filters.put("blur",BlurFilter.class); 039 filters.put("border",BorderFilter.class); 040 filters.put("boxblur",BoxBlurFilter.class); 041 filters.put("brushedmetal",BrushedMetalFilter.class); 042 filters.put("bump",BumpFilter.class); 043 filters.put("caustics",CausticsFilter.class); 044 filters.put("cellular",CellularFilter.class); 045 filters.put("channelmix",ChannelMixFilter.class); 046 filters.put("check",CheckFilter.class); 047 filters.put("chromakey",ChromaKeyFilter.class); 048 filters.put("chrome",ChromeFilter.class); 049 filters.put("circle",CircleFilter.class); 050 ////////filters.put("composite",CompositeFilter.class); 051 //filters.put("compound",CompoundFilter.class); 052 filters.put("contour",ContourFilter.class); 053 filters.put("contrast",ContrastFilter.class); 054 filters.put("convolve",ConvolveFilter.class); 055 filters.put("crop",CropFilter.class); 056 filters.put("crystallize",CrystallizeFilter.class); 057 filters.put("curl",CurlFilter.class); 058 filters.put("curves",CurvesFilter.class); 059 filters.put("despeckle",DespeckleFilter.class); 060 filters.put("diffuse",DiffuseFilter.class); 061 filters.put("diffusion",DiffusionFilter.class); 062 filters.put("dilate",DilateFilter.class); 063 filters.put("displace",DisplaceFilter.class); 064 filters.put("dissolve",DissolveFilter.class); 065 filters.put("dither",DitherFilter.class); 066 filters.put("edge",EdgeFilter.class); 067 filters.put("emboss",EmbossFilter.class); 068 filters.put("equalize",EqualizeFilter.class); 069 filters.put("erodealpha",ErodeAlphaFilter.class); 070 filters.put("erode",ErodeFilter.class); 071 filters.put("exposure",ExposureFilter.class); 072 filters.put("fade",FadeFilter.class); 073 filters.put("fbm",FBMFilter.class); 074 filters.put("feedback",FeedbackFilter.class); 075 filters.put("fieldwarp",FieldWarpFilter.class); 076 filters.put("fill",FillFilter.class); 077 filters.put("flare",FlareFilter.class); 078 filters.put("flip",FlipFilter.class); 079 filters.put("flush3d",Flush3DFilter.class); 080 filters.put("fourcolor",FourColorFilter.class); 081 filters.put("gain",GainFilter.class); 082 filters.put("gamma",GammaFilter.class); 083 filters.put("gaussian",GaussianFilter.class); 084 filters.put("glint",GlintFilter.class); 085 filters.put("glow",GlowFilter.class); 086 filters.put("gradient",GradientFilter.class); 087 filters.put("gradientwipe",GradientWipeFilter.class); 088 filters.put("gray",GrayFilter.class); 089 filters.put("grayscale",GrayscaleFilter.class); 090 filters.put("halftone",HalftoneFilter.class); 091 filters.put("hsbadjust",HSBAdjustFilter.class); 092 filters.put("interpolate",InterpolateFilter.class); 093 filters.put("invertalpha",InvertAlphaFilter.class); 094 filters.put("invert",InvertFilter.class); 095 //filters.put("iterated",IteratedFilter.class); 096 filters.put("javalnf",JavaLnFFilter.class); 097 filters.put("kaleidoscope",KaleidoscopeFilter.class); 098 //filters.put("key",KeyFilter.class); 099 filters.put("lensblur",LensBlurFilter.class); 100 filters.put("levels",LevelsFilter.class); 101 filters.put("life",LifeFilter.class); 102 filters.put("light",LightFilter.class); 103 filters.put("lookup",LookupFilter.class); 104 filters.put("mapcolors",MapColorsFilter.class); 105 filters.put("map",MapFilter.class); 106 filters.put("marble",MarbleFilter.class); 107 filters.put("marbletex",MarbleTexFilter.class); 108 filters.put("mask",MaskFilter.class); 109 filters.put("maximum",MaximumFilter.class); 110 filters.put("median",MedianFilter.class); 111 filters.put("minimum",MinimumFilter.class); 112 filters.put("mirror",MirrorFilter.class); 113 filters.put("motionblur",MotionBlurFilter.class); 114 //filters.put("mutatable",MutatableFilter.class); 115 filters.put("noise",NoiseFilter.class); 116 filters.put("offset",OffsetFilter.class); 117 filters.put("oil",OilFilter.class); 118 filters.put("opacity",OpacityFilter.class); 119 filters.put("outline",OutlineFilter.class); 120 filters.put("perspective",PerspectiveFilter.class); 121 filters.put("pinch",PinchFilter.class); 122 filters.put("plasma",PlasmaFilter.class); 123 filters.put("pointillize",PointillizeFilter.class); 124 filters.put("polar",PolarFilter.class); 125 filters.put("posterize",PosterizeFilter.class); 126 //filters.put("premultiply",PremultiplyFilter.class); 127 filters.put("quantize",QuantizeFilter.class); 128 filters.put("quilt",QuiltFilter.class); 129 filters.put("rays",RaysFilter.class); 130 filters.put("reducenoise",ReduceNoiseFilter.class); 131 filters.put("rendertext",RenderTextFilter.class); 132 filters.put("rescale",RescaleFilter.class); 133 filters.put("rgbadjust",RGBAdjustFilter.class); 134 filters.put("ripple",RippleFilter.class); 135 filters.put("rotate",RotateFilter.class); 136 filters.put("saturation",SaturationFilter.class); 137 filters.put("scale",ScaleFilter.class); 138 filters.put("scratch",ScratchFilter.class); 139 filters.put("shade",ShadeFilter.class); 140 filters.put("shadow",ShadowFilter.class); 141 filters.put("shape",ShapeFilter.class); 142 filters.put("sharpen",SharpenFilter.class); 143 filters.put("shatter",ShatterFilter.class); 144 filters.put("shear",ShearFilter.class); 145 filters.put("shine",ShineFilter.class); 146 filters.put("skeleton",SkeletonFilter.class); 147 //filters.put("sky",SkyFilter.class); 148 filters.put("smartblur",SmartBlurFilter.class); 149 filters.put("smear",SmearFilter.class); 150 filters.put("solarize",SolarizeFilter.class); 151 filters.put("sparkle",SparkleFilter.class); 152 filters.put("sphere",SphereFilter.class); 153 filters.put("stamp",StampFilter.class); 154 filters.put("swim",SwimFilter.class); 155 filters.put("texture",TextureFilter.class); 156 filters.put("threshold",ThresholdFilter.class); 157 filters.put("tileimage",TileImageFilter.class); 158 //filters.put("transfer",TransferFilter.class); 159 //filters.put("transform",TransformFilter.class); 160 //filters.put("transition",TransitionFilter.class); 161 filters.put("twirl",TwirlFilter.class); 162 //filters.put("unpremultiply",UnpremultiplyFilter.class); 163 filters.put("unsharp",UnsharpFilter.class); 164 filters.put("variableblur",VariableBlurFilter.class); 165 //filters.put("warp",WarpFilter.class); 166 filters.put("water",WaterFilter.class); 167 filters.put("weave",WeaveFilter.class); 168 filters.put("wholeimage",WholeImageFilter.class); 169 filters.put("wood",WoodFilter.class); 170 } 171 172 173 174 public static String call(PageContext pc, Object name, String filterName) throws PageException { 175 return call(pc, name, filterName, EMPTY_STRUCT); 176 } 177 public static String call(PageContext pc, Object name, String filterName, Struct parameters) throws PageException { 178 if(name instanceof String) name=pc.getVariable(Caster.toString(name)); 179 Image img = Image.toImage(name); 180 String lcFilterName = filterName.trim().toLowerCase(); 181 182 // get filter class 183 Class clazz = filters.get(lcFilterName); 184 if(clazz==null) { 185 String[] keys = filters.keySet().toArray(new String[filters.size()]); 186 Arrays.sort(keys); 187 String list=ListUtil.arrayToList(keys, ", "); 188 189 String soundex = StringUtil.soundex(filterName); 190 java.util.List<String> similar=new ArrayList<String>(); 191 for(int i=0;i<keys.length;i++){ 192 if(StringUtil.soundex(keys[i]).equals(soundex)) 193 similar.add(keys[i]); 194 } 195 if(similar.size()>0) { 196 list=ListUtil.arrayToList(similar.toArray(new String[similar.size()]), ", "); 197 throw new FunctionException(pc, "ImageFilter", 2, "filtername", "invalid filter name ["+filterName+"], did you mean ["+list+"]"); 198 } 199 throw new FunctionException(pc, "ImageFilter", 2, "filtername", "invalid filter name ["+filterName+"], valid filter names are ["+list+"]"); 200 } 201 202 // load filter 203 DynFiltering filter=null; 204 try { 205 filter=(DynFiltering) clazz.newInstance(); 206 } catch (Throwable t) { 207 throw Caster.toPageException(t); 208 } 209 210 // execute filter 211 BufferedImage bi = img.getBufferedImage(); 212 //BufferedImage empty = bi;//ImageUtil.createBufferedImage(bi); 213 img.image(filter.filter(bi, parameters)); 214 215 return null; 216 } 217 218 private static void setters(String key, Class clazz, StringBuilder sb) { 219 220 //sb.append("Object o;\n"); 221 sb.append(" public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);\n"); 222 sb.append(" Object o;\n"); 223 224 Method[] methods = clazz.getMethods(); 225 Method method; 226 StringBuilder names=new StringBuilder(); 227 for(int i=0;i<methods.length;i++){ 228 method=methods[i]; 229 if(method.getName().startsWith("set") && !method.getName().equals("setRGB") && !method.getName().equals("setDestination")){ 230 String name=method.getName().substring(3); 231 args(key,name,method,sb,i); 232 if(names.length()>0) names.append(", "); 233 names.append(name); 234 235 } 236 } 237 sb.append("\n"); 238 sb.append(" // check for arguments not supported\n"); 239 sb.append(" if(parameters.size()>0) {\n"); 240 sb.append(" throw new FunctionException(ThreadLocalPageContext.get(), \"ImageFilter\", 3, \"parameters\", \"the parameter\"+(parameters.size()>1?\"s\":\"\")+\" [\"+List.arrayToList(parameters.keys(),\", \")+\"] \"+(parameters.size()>1?\"are\":\"is\")+\" not allowed, only the following parameters are supported ["+names+"]\");\n"); 241 sb.append(" }\n"); 242 sb.append("\n"); 243 244 245 246 247 248 249 sb.append(" return filter(src, dst);\n"); 250 sb.append(" }\n"); 251 252 253 } 254 private static void args(String className, String name, Method method, StringBuilder sb, int methodIndex) { 255 Class[] params = method.getParameterTypes(); 256 257 258 if(params.length==1){ 259 sb.append(" if((o=parameters.removeEL(KeyImpl.init(\""+name+"\")))!=null)"); 260 sb.append(method.getName()+"("); 261 arg(name, params[0], method,sb,methodIndex); 262 263 sb.append(");\n"); 264 } 265 else if(params.length==2 && name.equals("Dimensions")){ 266 sb.append(" if((o=parameters.removeEL(KeyImpl.init(\""+name+"\")))!=null){\n"); 267 sb.append(" int[] dim=ImageFilterUtil.toDimensions(o,\"Dimensions\");\n"); 268 sb.append(" "+method.getName()+"(dim[0],dim[1]"); 269 sb.append(");\n"); 270 sb.append(" }\n"); 271 } 272 //else print.e(className+"->"+method); 273 274 } 275 private static void arg(String name, Class param, Method method, StringBuilder sb, int methodIndex) { 276 277 278 sb.append("ImageFilterUtil."); 279 if(param==float.class) sb.append("toFloatValue"); 280 else if(param==boolean.class) sb.append("toBooleanValue"); 281 else if(param==int.class) sb.append("toIntValue"); 282 else if(param==Point2D.class) sb.append("toPoint2D"); 283 else if(param==WarpGrid.class) sb.append("toWarpGrid"); 284 else if(param==Kernel.class) sb.append("toKernel"); 285 else if(param==Colormap.class) sb.append("toColormap"); 286 else if(param==Function2D.class) sb.append("toFunction2D"); 287 else if(param==BufferedImage.class) sb.append("toBufferedImage"); 288 else if(param==BinaryFunction.class) sb.append("toBinaryFunction"); 289 else if(param==String.class) sb.append("toString"); 290 else if(param==Paint.class) sb.append("toPaint"); 291 else if(param==Font.class) sb.append("toFont"); 292 else if(param==AffineTransform.class) sb.append("toAffineTransform"); 293 else if(param==Composite.class) sb.append("toComposite"); 294 else if(param==LightFilter.Material.class) sb.append("toLightFilter$Material"); 295 //else if(param==FieldWarpFilter.Line.class) sb.append("toFieldWarpFilter$Line"); 296 else if(param==FieldWarpFilter.Line[].class) sb.append("toAFieldWarpFilter$Line"); 297 else if(param==CurvesFilter.Curve.class) sb.append("toCurvesFilter$Curve"); 298 else if(param==CurvesFilter.Curve[].class) sb.append("toACurvesFilter$Curve"); 299 else if(param==Point.class) sb.append("toPoint"); 300 301 302 else if(param==int[].class) sb.append("toAInt"); 303 else if(param==int[][].class) sb.append("toAAInt"); 304 else if(param==float[].class) sb.append("toAFloat"); 305 306 else { 307 new RuntimeException(name+"!!!!!!!!!!!!!"+param.getName()).printStackTrace(); 308 } 309 sb.append("(o,\""+name+"\")"); 310 311 } 312 313 314 }