001    /*
002    *
003    
004    Licensed under the Apache License, Version 2.0 (the "License");
005    you may not use this file except in compliance with the License.
006    You may obtain a copy of the License at
007    
008       http://www.apache.org/licenses/LICENSE-2.0
009    
010    Unless required by applicable law or agreed to in writing, software
011    distributed under the License is distributed on an "AS IS" BASIS,
012    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013    See the License for the specific language governing permissions and
014    limitations under the License.
015    */
016    
017    package railo.runtime.img.filter;import java.awt.image.BufferedImage;
018    
019    import railo.runtime.engine.ThreadLocalPageContext;
020    import railo.runtime.exp.FunctionException;
021    import railo.runtime.exp.PageException;
022    import railo.runtime.img.ImageUtil;
023    import railo.runtime.type.KeyImpl;
024    import railo.runtime.type.Struct;
025    import railo.runtime.type.util.CollectionUtil;
026    
027    
028    
029    /**
030     * A filter which applies a crystallizing effect to an image, by producing Voronoi cells filled with colours from the image.
031     */
032    public class CrystallizeFilter extends CellularFilter  implements DynFiltering {
033    
034            private float edgeThickness = 0.4f;
035            private boolean fadeEdges = false;
036            private int edgeColor = 0xff000000;
037    
038            public CrystallizeFilter() {
039                    setScale(16);
040                    setRandomness(0.0f);
041            }
042            
043            public void setEdgeThickness(float edgeThickness) {
044                    this.edgeThickness = edgeThickness;
045            }
046    
047            public float getEdgeThickness() {
048                    return edgeThickness;
049            }
050    
051            public void setFadeEdges(boolean fadeEdges) {
052                    this.fadeEdges = fadeEdges;
053            }
054    
055            public boolean getFadeEdges() {
056                    return fadeEdges;
057            }
058    
059            public void setEdgeColor(int edgeColor) {
060                    this.edgeColor = edgeColor;
061            }
062    
063            public int getEdgeColor() {
064                    return edgeColor;
065            }
066    
067            public int getPixel(int x, int y, int[] inPixels, int width, int height) {
068                    float nx = m00*x + m01*y;
069                    float ny = m10*x + m11*y;
070                    nx /= scale;
071                    ny /= scale * stretch;
072                    nx += 1000;
073                    ny += 1000;     // Reduce artifacts around 0,0
074                    float f = evaluate(nx, ny);
075    
076                    float f1 = results[0].distance;
077                    float f2 = results[1].distance;
078                    int srcx = ImageMath.clamp((int)((results[0].x-1000)*scale), 0, width-1);
079                    int srcy = ImageMath.clamp((int)((results[0].y-1000)*scale), 0, height-1);
080                    int v = inPixels[srcy * width + srcx];
081                    f = (f2 - f1) / edgeThickness;
082                    f = ImageMath.smoothStep(0, edgeThickness, f);
083                    if (fadeEdges) {
084                            srcx = ImageMath.clamp((int)((results[1].x-1000)*scale), 0, width-1);
085                            srcy = ImageMath.clamp((int)((results[1].y-1000)*scale), 0, height-1);
086                            int v2 = inPixels[srcy * width + srcx];
087                            v2 = ImageMath.mixColors(0.5f, v2, v);
088                            v = ImageMath.mixColors(f, v2, v);
089                    } else
090                            v = ImageMath.mixColors(f, edgeColor, v);
091                    return v;
092            }
093    
094            public String toString() {
095                    return "Stylize/Crystallize...";
096            }
097            
098            public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
099                    Object o;
100                    if((o=parameters.removeEL(KeyImpl.init("EdgeThickness")))!=null)setEdgeThickness(ImageFilterUtil.toFloatValue(o,"EdgeThickness"));
101                    if((o=parameters.removeEL(KeyImpl.init("FadeEdges")))!=null)setFadeEdges(ImageFilterUtil.toBooleanValue(o,"FadeEdges"));
102                    if((o=parameters.removeEL(KeyImpl.init("EdgeColor")))!=null)setEdgeColor(ImageFilterUtil.toColorRGB(o,"EdgeColor"));
103                    if((o=parameters.removeEL(KeyImpl.init("Colormap")))!=null)setColormap(ImageFilterUtil.toColormap(o,"Colormap"));
104                    if((o=parameters.removeEL(KeyImpl.init("Amount")))!=null)setAmount(ImageFilterUtil.toFloatValue(o,"Amount"));
105                    if((o=parameters.removeEL(KeyImpl.init("Turbulence")))!=null)setTurbulence(ImageFilterUtil.toFloatValue(o,"Turbulence"));
106                    if((o=parameters.removeEL(KeyImpl.init("Stretch")))!=null)setStretch(ImageFilterUtil.toFloatValue(o,"Stretch"));
107                    if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle"));
108                    if((o=parameters.removeEL(KeyImpl.init("AngleCoefficient")))!=null)setAngleCoefficient(ImageFilterUtil.toFloatValue(o,"AngleCoefficient"));
109                    if((o=parameters.removeEL(KeyImpl.init("GradientCoefficient")))!=null)setGradientCoefficient(ImageFilterUtil.toFloatValue(o,"GradientCoefficient"));
110                    if((o=parameters.removeEL(KeyImpl.init("F1")))!=null)setF1(ImageFilterUtil.toFloatValue(o,"F1"));
111                    if((o=parameters.removeEL(KeyImpl.init("F2")))!=null)setF2(ImageFilterUtil.toFloatValue(o,"F2"));
112                    if((o=parameters.removeEL(KeyImpl.init("F3")))!=null)setF3(ImageFilterUtil.toFloatValue(o,"F3"));
113                    if((o=parameters.removeEL(KeyImpl.init("F4")))!=null)setF4(ImageFilterUtil.toFloatValue(o,"F4"));
114                    if((o=parameters.removeEL(KeyImpl.init("Randomness")))!=null)setRandomness(ImageFilterUtil.toFloatValue(o,"Randomness"));
115                    if((o=parameters.removeEL(KeyImpl.init("GridType")))!=null)setGridType(ImageFilterUtil.toString(o,"GridType"));
116                    if((o=parameters.removeEL(KeyImpl.init("DistancePower")))!=null)setDistancePower(ImageFilterUtil.toFloatValue(o,"DistancePower"));
117                    if((o=parameters.removeEL(KeyImpl.init("Scale")))!=null)setScale(ImageFilterUtil.toFloatValue(o,"Scale"));
118    
119                    // check for arguments not supported
120                    if(parameters.size()>0) {
121                            throw new FunctionException(ThreadLocalPageContext.get(), "ImageFilter", 3, "parameters", "the parameter"+(parameters.size()>1?"s":"")+" ["+CollectionUtil.getKeyList(parameters,", ")+"] "+(parameters.size()>1?"are":"is")+" not allowed, only the following parameters are supported [EdgeThickness, FadeEdges, EdgeColor, Colormap, Amount, Turbulence, Stretch, Angle, Coefficient, AngleCoefficient, GradientCoefficient, F1, F2, F3, F4, Randomness, GridType, DistancePower, Scale]");
122                    }
123    
124                    return filter(src, dst);
125            }
126    }