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 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 static final float[] hsb1 = new float[3];//FIXME-not thread safe 086 private static final 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}