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    }