2014-02-19 10:38:30 +01:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* Copyright 2006 Jerry Huxtable
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
2014-08-20 00:25:57 +02:00
|
|
|
package org.jivesoftware.smackx.jingleold.mediaimpl.sshare.api;
|
2007-05-02 21:55:59 +02:00
|
|
|
|
2014-08-15 23:16:18 +02:00
|
|
|
import java.awt.Color;
|
2007-05-02 21:55:59 +02:00
|
|
|
import java.util.Random;
|
|
|
|
|
2014-08-15 23:16:18 +02:00
|
|
|
|
2007-05-02 21:55:59 +02:00
|
|
|
/**
|
|
|
|
* Some more useful math functions for image processing.
|
|
|
|
* These are becoming obsolete as we move to Java2D. Use MiscComposite instead.
|
|
|
|
*/
|
|
|
|
public class PixelUtils {
|
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
public final static int REPLACE = 0;
|
|
|
|
public final static int NORMAL = 1;
|
|
|
|
public final static int MIN = 2;
|
|
|
|
public final static int MAX = 3;
|
|
|
|
public final static int ADD = 4;
|
|
|
|
public final static int SUBTRACT = 5;
|
|
|
|
public final static int DIFFERENCE = 6;
|
|
|
|
public final static int MULTIPLY = 7;
|
|
|
|
public final static int HUE = 8;
|
|
|
|
public final static int SATURATION = 9;
|
|
|
|
public final static int VALUE = 10;
|
|
|
|
public final static int COLOR = 11;
|
|
|
|
public final static int SCREEN = 12;
|
|
|
|
public final static int AVERAGE = 13;
|
|
|
|
public final static int OVERLAY = 14;
|
|
|
|
public final static int CLEAR = 15;
|
|
|
|
public final static int EXCHANGE = 16;
|
|
|
|
public final static int DISSOLVE = 17;
|
|
|
|
public final static int DST_IN = 18;
|
|
|
|
public final static int ALPHA = 19;
|
|
|
|
public final static int ALPHA_TO_GRAY = 20;
|
2007-05-02 21:55:59 +02:00
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
private static Random randomGenerator = new Random();
|
2007-05-02 21:55:59 +02:00
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
/**
|
|
|
|
* Clamp a value to the range 0..255.
|
|
|
|
*/
|
|
|
|
public static int clamp(int c) {
|
|
|
|
if (c < 0)
|
|
|
|
return 0;
|
|
|
|
if (c > 255)
|
|
|
|
return 255;
|
|
|
|
return c;
|
|
|
|
}
|
2007-05-02 21:55:59 +02:00
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
public static int interpolate(int v1, int v2, float f) {
|
2017-05-23 16:45:04 +02:00
|
|
|
return clamp((int) (v1 + f * (v2 - v1)));
|
2017-02-07 22:02:40 +01:00
|
|
|
}
|
2015-03-17 11:33:02 +01:00
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
public static int brightness(int rgb) {
|
|
|
|
int r = (rgb >> 16) & 0xff;
|
|
|
|
int g = (rgb >> 8) & 0xff;
|
|
|
|
int b = rgb & 0xff;
|
2017-05-23 16:45:04 +02:00
|
|
|
return (r + g + b) / 3;
|
2017-02-07 22:02:40 +01:00
|
|
|
}
|
2015-03-17 11:33:02 +01:00
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
public static boolean nearColors(int rgb1, int rgb2, int tolerance) {
|
|
|
|
int r1 = (rgb1 >> 16) & 0xff;
|
|
|
|
int g1 = (rgb1 >> 8) & 0xff;
|
|
|
|
int b1 = rgb1 & 0xff;
|
|
|
|
int r2 = (rgb2 >> 16) & 0xff;
|
|
|
|
int g2 = (rgb2 >> 8) & 0xff;
|
|
|
|
int b2 = rgb2 & 0xff;
|
2017-05-23 16:45:04 +02:00
|
|
|
return Math.abs(r1 - r2) <= tolerance && Math.abs(g1 - g2) <= tolerance && Math.abs(b1 - b2) <= tolerance;
|
2017-02-07 22:02:40 +01:00
|
|
|
}
|
2015-03-17 11:33:02 +01:00
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
private final static float[] hsb1 = new float[3];//FIXME-not thread safe
|
|
|
|
private final static float[] hsb2 = new float[3];//FIXME-not thread safe
|
2015-03-17 11:33:02 +01:00
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
// Return rgb1 painted onto rgb2
|
|
|
|
public static int combinePixels(int rgb1, int rgb2, int op) {
|
|
|
|
return combinePixels(rgb1, rgb2, op, 0xff);
|
|
|
|
}
|
2015-03-17 11:33:02 +01:00
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha, int channelMask) {
|
|
|
|
return (rgb2 & ~channelMask) | combinePixels(rgb1 & channelMask, rgb2, op, extraAlpha);
|
|
|
|
}
|
2015-03-17 11:33:02 +01:00
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha) {
|
|
|
|
if (op == REPLACE)
|
|
|
|
return rgb1;
|
|
|
|
int a1 = (rgb1 >> 24) & 0xff;
|
|
|
|
int r1 = (rgb1 >> 16) & 0xff;
|
|
|
|
int g1 = (rgb1 >> 8) & 0xff;
|
|
|
|
int b1 = rgb1 & 0xff;
|
|
|
|
int a2 = (rgb2 >> 24) & 0xff;
|
|
|
|
int r2 = (rgb2 >> 16) & 0xff;
|
|
|
|
int g2 = (rgb2 >> 8) & 0xff;
|
|
|
|
int b2 = rgb2 & 0xff;
|
2007-05-02 21:55:59 +02:00
|
|
|
|
2017-02-07 22:02:40 +01:00
|
|
|
switch (op) {
|
|
|
|
case NORMAL:
|
|
|
|
break;
|
|
|
|
case MIN:
|
|
|
|
r1 = Math.min(r1, r2);
|
|
|
|
g1 = Math.min(g1, g2);
|
|
|
|
b1 = Math.min(b1, b2);
|
|
|
|
break;
|
|
|
|
case MAX:
|
|
|
|
r1 = Math.max(r1, r2);
|
|
|
|
g1 = Math.max(g1, g2);
|
|
|
|
b1 = Math.max(b1, b2);
|
|
|
|
break;
|
|
|
|
case ADD:
|
2017-05-23 16:45:04 +02:00
|
|
|
r1 = clamp(r1 + r2);
|
|
|
|
g1 = clamp(g1 + g2);
|
|
|
|
b1 = clamp(b1 + b2);
|
2017-02-07 22:02:40 +01:00
|
|
|
break;
|
|
|
|
case SUBTRACT:
|
2017-05-23 16:45:04 +02:00
|
|
|
r1 = clamp(r2 - r1);
|
|
|
|
g1 = clamp(g2 - g1);
|
|
|
|
b1 = clamp(b2 - b1);
|
2017-02-07 22:02:40 +01:00
|
|
|
break;
|
|
|
|
case DIFFERENCE:
|
2017-05-23 16:45:04 +02:00
|
|
|
r1 = clamp(Math.abs(r1 - r2));
|
|
|
|
g1 = clamp(Math.abs(g1 - g2));
|
|
|
|
b1 = clamp(Math.abs(b1 - b2));
|
2017-02-07 22:02:40 +01:00
|
|
|
break;
|
|
|
|
case MULTIPLY:
|
2017-05-23 16:45:04 +02:00
|
|
|
r1 = clamp(r1 * r2 / 255);
|
|
|
|
g1 = clamp(g1 * g2 / 255);
|
|
|
|
b1 = clamp(b1 * b2 / 255);
|
2017-02-07 22:02:40 +01:00
|
|
|
break;
|
|
|
|
case DISSOLVE:
|
|
|
|
if ((randomGenerator.nextInt() & 0xff) <= a1) {
|
|
|
|
r1 = r2;
|
|
|
|
g1 = g2;
|
|
|
|
b1 = b2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AVERAGE:
|
2017-05-23 16:45:04 +02:00
|
|
|
r1 = (r1 + r2) / 2;
|
|
|
|
g1 = (g1 + g2) / 2;
|
|
|
|
b1 = (b1 + b2) / 2;
|
2017-02-07 22:02:40 +01:00
|
|
|
break;
|
|
|
|
case HUE:
|
|
|
|
case SATURATION:
|
|
|
|
case VALUE:
|
|
|
|
case COLOR:
|
|
|
|
Color.RGBtoHSB(r1, g1, b1, hsb1);
|
|
|
|
Color.RGBtoHSB(r2, g2, b2, hsb2);
|
|
|
|
switch (op) {
|
|
|
|
case HUE:
|
|
|
|
hsb2[0] = hsb1[0];
|
|
|
|
break;
|
|
|
|
case SATURATION:
|
|
|
|
hsb2[1] = hsb1[1];
|
|
|
|
break;
|
|
|
|
case VALUE:
|
|
|
|
hsb2[2] = hsb1[2];
|
|
|
|
break;
|
|
|
|
case COLOR:
|
|
|
|
hsb2[0] = hsb1[0];
|
|
|
|
hsb2[1] = hsb1[1];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
rgb1 = Color.HSBtoRGB(hsb2[0], hsb2[1], hsb2[2]);
|
|
|
|
r1 = (rgb1 >> 16) & 0xff;
|
|
|
|
g1 = (rgb1 >> 8) & 0xff;
|
|
|
|
b1 = rgb1 & 0xff;
|
|
|
|
break;
|
|
|
|
case SCREEN:
|
|
|
|
r1 = 255 - ((255 - r1) * (255 - r2)) / 255;
|
|
|
|
g1 = 255 - ((255 - g1) * (255 - g2)) / 255;
|
|
|
|
b1 = 255 - ((255 - b1) * (255 - b2)) / 255;
|
|
|
|
break;
|
|
|
|
case OVERLAY:
|
|
|
|
int m, s;
|
|
|
|
s = 255 - ((255 - r1) * (255 - r2)) / 255;
|
|
|
|
m = r1 * r2 / 255;
|
|
|
|
r1 = (s * r1 + m * (255 - r1)) / 255;
|
|
|
|
s = 255 - ((255 - g1) * (255 - g2)) / 255;
|
|
|
|
m = g1 * g2 / 255;
|
|
|
|
g1 = (s * g1 + m * (255 - g1)) / 255;
|
|
|
|
s = 255 - ((255 - b1) * (255 - b2)) / 255;
|
|
|
|
m = b1 * b2 / 255;
|
|
|
|
b1 = (s * b1 + m * (255 - b1)) / 255;
|
|
|
|
break;
|
|
|
|
case CLEAR:
|
|
|
|
r1 = g1 = b1 = 0xff;
|
|
|
|
break;
|
|
|
|
case DST_IN:
|
2017-05-23 16:45:04 +02:00
|
|
|
r1 = clamp((r2 * a1) / 255);
|
|
|
|
g1 = clamp((g2 * a1) / 255);
|
|
|
|
b1 = clamp((b2 * a1) / 255);
|
|
|
|
a1 = clamp((a2 * a1) / 255);
|
2017-02-07 22:02:40 +01:00
|
|
|
return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
|
|
|
|
case ALPHA:
|
2017-05-23 16:45:04 +02:00
|
|
|
a1 = a1 * a2 / 255;
|
2017-02-07 22:02:40 +01:00
|
|
|
return (a1 << 24) | (r2 << 16) | (g2 << 8) | b2;
|
|
|
|
case ALPHA_TO_GRAY:
|
2017-05-23 16:45:04 +02:00
|
|
|
int na = 255 - a1;
|
2017-02-07 22:02:40 +01:00
|
|
|
return (a1 << 24) | (na << 16) | (na << 8) | na;
|
|
|
|
}
|
|
|
|
if (extraAlpha != 0xff || a1 != 0xff) {
|
2017-05-23 16:45:04 +02:00
|
|
|
a1 = a1 * extraAlpha / 255;
|
|
|
|
int a3 = (255 - a1) * a2 / 255;
|
|
|
|
r1 = clamp((r1 * a1 + r2 * a3) / 255);
|
|
|
|
g1 = clamp((g1 * a1 + g2 * a3) / 255);
|
|
|
|
b1 = clamp((b1 * a1 + b2 * a3) / 255);
|
|
|
|
a1 = clamp(a1 + a3);
|
2017-02-07 22:02:40 +01:00
|
|
|
}
|
|
|
|
return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
|
|
|
|
}
|
2007-05-02 21:55:59 +02:00
|
|
|
|
|
|
|
}
|