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    }