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.Color;
018    import java.util.Random;
019    
020    /**
021     * Some more useful math functions for image processing.
022     * These are becoming obsolete as we move to Java2D. Use MiscComposite instead.
023     */
024    public class PixelUtils {
025    
026            public final static int REPLACE = 0;
027            public final static int NORMAL = 1;
028            public final static int MIN = 2;
029            public final static int MAX = 3;
030            public final static int ADD = 4;
031            public final static int SUBTRACT = 5;
032            public final static int DIFFERENCE = 6;
033            public final static int MULTIPLY = 7;
034            public final static int HUE = 8;
035            public final static int SATURATION = 9;
036            public final static int VALUE = 10;
037            public final static int COLOR = 11;
038            public final static int SCREEN = 12;
039            public final static int AVERAGE = 13;
040            public final static int OVERLAY = 14;
041            public final static int CLEAR = 15;
042            public final static int EXCHANGE = 16;
043            public final static int DISSOLVE = 17;
044            public final static int DST_IN = 18;
045            public final static int ALPHA = 19;
046            public final static int ALPHA_TO_GRAY = 20;
047    
048            private static Random randomGenerator = new Random();
049    
050            /**
051             * Clamp a value to the range 0..255
052             */
053            public static int clamp(int c) {
054                    if (c < 0)
055                            return 0;
056                    if (c > 255)
057                            return 255;
058                    return c;
059            }
060    
061            public static int interpolate(int v1, int v2, float f) {
062                    return clamp((int)(v1+f*(v2-v1)));
063            }
064            
065            public static int brightness(int rgb) {
066                    int r = (rgb >> 16) & 0xff;
067                    int g = (rgb >> 8) & 0xff;
068                    int b = rgb & 0xff;
069                    return (r+g+b)/3;
070            }
071            
072            public static boolean nearColors(int rgb1, int rgb2, int tolerance) {
073                    int r1 = (rgb1 >> 16) & 0xff;
074                    int g1 = (rgb1 >> 8) & 0xff;
075                    int b1 = rgb1 & 0xff;
076                    int r2 = (rgb2 >> 16) & 0xff;
077                    int g2 = (rgb2 >> 8) & 0xff;
078                    int b2 = rgb2 & 0xff;
079                    return Math.abs(r1-r2) <= tolerance && Math.abs(g1-g2) <= tolerance && Math.abs(b1-b2) <= tolerance;
080            }
081            
082            private final static float hsb1[] = new float[3];//FIXME-not thread safe
083            private final static float hsb2[] = new float[3];//FIXME-not thread safe
084            
085            // Return rgb1 painted onto rgb2
086            public static int combinePixels(int rgb1, int rgb2, int op) {
087                    return combinePixels(rgb1, rgb2, op, 0xff);
088            }
089            
090            public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha, int channelMask) {
091                    return (rgb2 & ~channelMask) | combinePixels(rgb1 & channelMask, rgb2, op, extraAlpha);
092            }
093            
094            public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha) {
095                    if (op == REPLACE)
096                            return rgb1;
097                    int a1 = (rgb1 >> 24) & 0xff;
098                    int r1 = (rgb1 >> 16) & 0xff;
099                    int g1 = (rgb1 >> 8) & 0xff;
100                    int b1 = rgb1 & 0xff;
101                    int a2 = (rgb2 >> 24) & 0xff;
102                    int r2 = (rgb2 >> 16) & 0xff;
103                    int g2 = (rgb2 >> 8) & 0xff;
104                    int b2 = rgb2 & 0xff;
105    
106                    switch (op) {
107                    case NORMAL:
108                            break;
109                    case MIN:
110                            r1 = Math.min(r1, r2);
111                            g1 = Math.min(g1, g2);
112                            b1 = Math.min(b1, b2);
113                            break;
114                    case MAX:
115                            r1 = Math.max(r1, r2);
116                            g1 = Math.max(g1, g2);
117                            b1 = Math.max(b1, b2);
118                            break;
119                    case ADD:
120                            r1 = clamp(r1+r2);
121                            g1 = clamp(g1+g2);
122                            b1 = clamp(b1+b2);
123                            break;
124                    case SUBTRACT:
125                            r1 = clamp(r2-r1);
126                            g1 = clamp(g2-g1);
127                            b1 = clamp(b2-b1);
128                            break;
129                    case DIFFERENCE:
130                            r1 = clamp(Math.abs(r1-r2));
131                            g1 = clamp(Math.abs(g1-g2));
132                            b1 = clamp(Math.abs(b1-b2));
133                            break;
134                    case MULTIPLY:
135                            r1 = clamp(r1*r2/255);
136                            g1 = clamp(g1*g2/255);
137                            b1 = clamp(b1*b2/255);
138                            break;
139                    case DISSOLVE:
140                            if ((randomGenerator.nextInt() & 0xff) <= a1) {
141                                    r1 = r2;
142                                    g1 = g2;
143                                    b1 = b2;
144                            }
145                            break;
146                    case AVERAGE:
147                            r1 = (r1+r2)/2;
148                            g1 = (g1+g2)/2;
149                            b1 = (b1+b2)/2;
150                            break;
151                    case HUE:
152                    case SATURATION:
153                    case VALUE:
154                    case COLOR:
155                            Color.RGBtoHSB(r1, g1, b1, hsb1);
156                            Color.RGBtoHSB(r2, g2, b2, hsb2);
157                            switch (op) {
158                            case HUE:
159                                    hsb2[0] = hsb1[0];
160                                    break;
161                            case SATURATION:
162                                    hsb2[1] = hsb1[1];
163                                    break;
164                            case VALUE:
165                                    hsb2[2] = hsb1[2];
166                                    break;
167                            case COLOR:
168                                    hsb2[0] = hsb1[0];
169                                    hsb2[1] = hsb1[1];
170                                    break;
171                            }
172                            rgb1 = Color.HSBtoRGB(hsb2[0], hsb2[1], hsb2[2]);
173                            r1 = (rgb1 >> 16) & 0xff;
174                            g1 = (rgb1 >> 8) & 0xff;
175                            b1 = rgb1 & 0xff;
176                            break;
177                    case SCREEN:
178                            r1 = 255 - ((255 - r1) * (255 - r2)) / 255;
179                            g1 = 255 - ((255 - g1) * (255 - g2)) / 255;
180                            b1 = 255 - ((255 - b1) * (255 - b2)) / 255;
181                            break;
182                    case OVERLAY:
183                            int m, s;
184                            s = 255 - ((255 - r1) * (255 - r2)) / 255;
185                            m = r1 * r2 / 255;
186                            r1 = (s * r1 + m * (255 - r1)) / 255;
187                            s = 255 - ((255 - g1) * (255 - g2)) / 255;
188                            m = g1 * g2 / 255;
189                            g1 = (s * g1 + m * (255 - g1)) / 255;
190                            s = 255 - ((255 - b1) * (255 - b2)) / 255;
191                            m = b1 * b2 / 255;
192                            b1 = (s * b1 + m * (255 - b1)) / 255;
193                            break;
194                    case CLEAR:
195                            r1 = g1 = b1 = 0xff;
196                            break;
197                    case DST_IN:
198                            r1 = clamp((r2*a1)/255);
199                            g1 = clamp((g2*a1)/255);
200                            b1 = clamp((b2*a1)/255);
201                            a1 = clamp((a2*a1)/255);
202                            return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
203                    case ALPHA:
204                            a1 = a1*a2/255;
205                            return (a1 << 24) | (r2 << 16) | (g2 << 8) | b2;
206                    case ALPHA_TO_GRAY:
207                            int na = 255-a1;
208                            return (a1 << 24) | (na << 16) | (na << 8) | na;
209                    }
210                    if (extraAlpha != 0xff || a1 != 0xff) {
211                            a1 = a1*extraAlpha/255;
212                            int a3 = (255-a1)*a2/255;
213                            r1 = clamp((r1*a1+r2*a3)/255);
214                            g1 = clamp((g1*a1+g2*a3)/255);
215                            b1 = clamp((b1*a1+b2*a3)/255);
216                            a1 = clamp(a1+a3);
217                    }
218                    return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
219            }
220    
221    }