001/**
002 *
003 * Copyright 2006 Jerry Huxtable
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smackx.jingleold.mediaimpl.sshare.api;
018
019import java.awt.Color;
020import java.util.Random;
021
022
023/**
024 * Some more useful math functions for image processing.
025 * These are becoming obsolete as we move to Java2D. Use MiscComposite instead.
026 */
027public class PixelUtils {
028
029        public final static int REPLACE = 0;
030        public final static int NORMAL = 1;
031        public final static int MIN = 2;
032        public final static int MAX = 3;
033        public final static int ADD = 4;
034        public final static int SUBTRACT = 5;
035        public final static int DIFFERENCE = 6;
036        public final static int MULTIPLY = 7;
037        public final static int HUE = 8;
038        public final static int SATURATION = 9;
039        public final static int VALUE = 10;
040        public final static int COLOR = 11;
041        public final static int SCREEN = 12;
042        public final static int AVERAGE = 13;
043        public final static int OVERLAY = 14;
044        public final static int CLEAR = 15;
045        public final static int EXCHANGE = 16;
046        public final static int DISSOLVE = 17;
047        public final static int DST_IN = 18;
048        public final static int ALPHA = 19;
049        public final static int ALPHA_TO_GRAY = 20;
050
051        private static Random randomGenerator = new Random();
052
053        /**
054         * Clamp a value to the range 0..255
055         */
056        public static int clamp(int c) {
057                if (c < 0)
058                        return 0;
059                if (c > 255)
060                        return 255;
061                return c;
062        }
063
064        public static int interpolate(int v1, int v2, float f) {
065                return clamp((int)(v1+f*(v2-v1)));
066        }
067        
068        public static int brightness(int rgb) {
069                int r = (rgb >> 16) & 0xff;
070                int g = (rgb >> 8) & 0xff;
071                int b = rgb & 0xff;
072                return (r+g+b)/3;
073        }
074        
075        public static boolean nearColors(int rgb1, int rgb2, int tolerance) {
076                int r1 = (rgb1 >> 16) & 0xff;
077                int g1 = (rgb1 >> 8) & 0xff;
078                int b1 = rgb1 & 0xff;
079                int r2 = (rgb2 >> 16) & 0xff;
080                int g2 = (rgb2 >> 8) & 0xff;
081                int b2 = rgb2 & 0xff;
082                return Math.abs(r1-r2) <= tolerance && Math.abs(g1-g2) <= tolerance && Math.abs(b1-b2) <= tolerance;
083        }
084        
085        private final static float[] hsb1 = new float[3];//FIXME-not thread safe
086        private final static float[] hsb2 = new float[3];//FIXME-not thread safe
087        
088        // Return rgb1 painted onto rgb2
089        public static int combinePixels(int rgb1, int rgb2, int op) {
090                return combinePixels(rgb1, rgb2, op, 0xff);
091        }
092        
093        public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha, int channelMask) {
094                return (rgb2 & ~channelMask) | combinePixels(rgb1 & channelMask, rgb2, op, extraAlpha);
095        }
096        
097        public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha) {
098                if (op == REPLACE)
099                        return rgb1;
100                int a1 = (rgb1 >> 24) & 0xff;
101                int r1 = (rgb1 >> 16) & 0xff;
102                int g1 = (rgb1 >> 8) & 0xff;
103                int b1 = rgb1 & 0xff;
104                int a2 = (rgb2 >> 24) & 0xff;
105                int r2 = (rgb2 >> 16) & 0xff;
106                int g2 = (rgb2 >> 8) & 0xff;
107                int b2 = rgb2 & 0xff;
108
109                switch (op) {
110                case NORMAL:
111                        break;
112                case MIN:
113                        r1 = Math.min(r1, r2);
114                        g1 = Math.min(g1, g2);
115                        b1 = Math.min(b1, b2);
116                        break;
117                case MAX:
118                        r1 = Math.max(r1, r2);
119                        g1 = Math.max(g1, g2);
120                        b1 = Math.max(b1, b2);
121                        break;
122                case ADD:
123                        r1 = clamp(r1+r2);
124                        g1 = clamp(g1+g2);
125                        b1 = clamp(b1+b2);
126                        break;
127                case SUBTRACT:
128                        r1 = clamp(r2-r1);
129                        g1 = clamp(g2-g1);
130                        b1 = clamp(b2-b1);
131                        break;
132                case DIFFERENCE:
133                        r1 = clamp(Math.abs(r1-r2));
134                        g1 = clamp(Math.abs(g1-g2));
135                        b1 = clamp(Math.abs(b1-b2));
136                        break;
137                case MULTIPLY:
138                        r1 = clamp(r1*r2/255);
139                        g1 = clamp(g1*g2/255);
140                        b1 = clamp(b1*b2/255);
141                        break;
142                case DISSOLVE:
143                        if ((randomGenerator.nextInt() & 0xff) <= a1) {
144                                r1 = r2;
145                                g1 = g2;
146                                b1 = b2;
147                        }
148                        break;
149                case AVERAGE:
150                        r1 = (r1+r2)/2;
151                        g1 = (g1+g2)/2;
152                        b1 = (b1+b2)/2;
153                        break;
154                case HUE:
155                case SATURATION:
156                case VALUE:
157                case COLOR:
158                        Color.RGBtoHSB(r1, g1, b1, hsb1);
159                        Color.RGBtoHSB(r2, g2, b2, hsb2);
160                        switch (op) {
161                        case HUE:
162                                hsb2[0] = hsb1[0];
163                                break;
164                        case SATURATION:
165                                hsb2[1] = hsb1[1];
166                                break;
167                        case VALUE:
168                                hsb2[2] = hsb1[2];
169                                break;
170                        case COLOR:
171                                hsb2[0] = hsb1[0];
172                                hsb2[1] = hsb1[1];
173                                break;
174                        }
175                        rgb1 = Color.HSBtoRGB(hsb2[0], hsb2[1], hsb2[2]);
176                        r1 = (rgb1 >> 16) & 0xff;
177                        g1 = (rgb1 >> 8) & 0xff;
178                        b1 = rgb1 & 0xff;
179                        break;
180                case SCREEN:
181                        r1 = 255 - ((255 - r1) * (255 - r2)) / 255;
182                        g1 = 255 - ((255 - g1) * (255 - g2)) / 255;
183                        b1 = 255 - ((255 - b1) * (255 - b2)) / 255;
184                        break;
185                case OVERLAY:
186                        int m, s;
187                        s = 255 - ((255 - r1) * (255 - r2)) / 255;
188                        m = r1 * r2 / 255;
189                        r1 = (s * r1 + m * (255 - r1)) / 255;
190                        s = 255 - ((255 - g1) * (255 - g2)) / 255;
191                        m = g1 * g2 / 255;
192                        g1 = (s * g1 + m * (255 - g1)) / 255;
193                        s = 255 - ((255 - b1) * (255 - b2)) / 255;
194                        m = b1 * b2 / 255;
195                        b1 = (s * b1 + m * (255 - b1)) / 255;
196                        break;
197                case CLEAR:
198                        r1 = g1 = b1 = 0xff;
199                        break;
200                case DST_IN:
201                        r1 = clamp((r2*a1)/255);
202                        g1 = clamp((g2*a1)/255);
203                        b1 = clamp((b2*a1)/255);
204                        a1 = clamp((a2*a1)/255);
205                        return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
206                case ALPHA:
207                        a1 = a1*a2/255;
208                        return (a1 << 24) | (r2 << 16) | (g2 << 8) | b2;
209                case ALPHA_TO_GRAY:
210                        int na = 255-a1;
211                        return (a1 << 24) | (na << 16) | (na << 8) | na;
212                }
213                if (extraAlpha != 0xff || a1 != 0xff) {
214                        a1 = a1*extraAlpha/255;
215                        int a3 = (255-a1)*a2/255;
216                        r1 = clamp((r1*a1+r2*a3)/255);
217                        g1 = clamp((g1*a1+g2*a3)/255);
218                        b1 = clamp((b1*a1+b2*a3)/255);
219                        a1 = clamp(a1+a3);
220                }
221                return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
222        }
223
224}