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