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