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 }