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