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.composite; 018 019import java.awt.*; 020import java.awt.geom.*; 021import java.awt.image.*; 022import java.awt.color.*; 023import java.net.*; 024import java.io.*; 025 026public class MiscCompositeContext implements CompositeContext { 027 028 private int rule; 029 private float alpha; 030 private ColorModel srcColorModel; 031 private ColorModel dstColorModel; 032 private ColorSpace srcColorSpace; 033 private ColorSpace dstColorSpace; 034 private boolean srcNeedsConverting; 035 private boolean dstNeedsConverting; 036 037 public MiscCompositeContext(int rule, 038 float alpha, 039 ColorModel srcColorModel, 040 ColorModel dstColorModel) { 041 this.rule = rule; 042 this.alpha = alpha; 043 this.srcColorModel = srcColorModel; 044 this.dstColorModel = dstColorModel; 045 this.srcColorSpace = srcColorModel.getColorSpace(); 046 this.dstColorSpace = dstColorModel.getColorSpace(); 047 ColorModel srgbCM = ColorModel.getRGBdefault(); 048// srcNeedsConverting = !srcColorModel.equals(srgbCM); 049// dstNeedsConverting = !dstColorModel.equals(srgbCM); 050 } 051 052 public void dispose() { 053 } 054 055 // Multiply two numbers in the range 0..255 such that 255*255=255 056 static int multiply255( int a, int b ) { 057 int t = a * b + 0x80; 058 return ((t >> 8) + t) >> 8; 059 } 060 061 static int clamp( int a ) { 062 return a < 0 ? 0 : a > 255 ? 255 : a; 063 } 064 065 public void compose(Raster src, Raster dstIn, WritableRaster dstOut) { 066 float a=0, ac=0; 067 float alpha = this.alpha; 068 int t; 069 070 float[] sHsv = null, diHsv = null, doHsv = null; 071 switch ( rule ) { 072 case MiscComposite.HUE: 073 case MiscComposite.SATURATION: 074 case MiscComposite.VALUE: 075 case MiscComposite.COLOR: 076 sHsv = new float[3]; 077 diHsv = new float[3]; 078 doHsv = new float[3]; 079 break; 080 } 081 082 int[] srcPix = null; 083 int[] dstPix = null; 084 085 int x = dstOut.getMinX(); 086 int w = dstOut.getWidth(); 087 088 int y0 = dstOut.getMinY(); 089 int y1 = y0 + dstOut.getHeight(); 090 091 for ( int y = y0; y < y1; y++ ) { 092 srcPix = src.getPixels(x, y, w, 1, srcPix); 093 dstPix = dstIn.getPixels(x, y, w, 1, dstPix); 094 int i = 0; 095 int end = w*4; 096 097 while ( i < end ) { 098 int sr = srcPix[i]; 099 int dir = dstPix[i]; 100 int sg = srcPix[i+1]; 101 int dig = dstPix[i+1]; 102 int sb = srcPix[i+2]; 103 int dib = dstPix[i+2]; 104 int sa = srcPix[i+3]; 105 int dia = dstPix[i+3]; 106 int dor, dog, dob, doa; 107 108 switch ( rule ) { 109 case MiscComposite.ADD: 110 default: 111 dor = dir + sr; 112 if ( dor > 255 ) 113 dor = 255; 114 dog = dig + sg; 115 if ( dog > 255 ) 116 dog = 255; 117 dob = dib + sb; 118 if ( dob > 255 ) 119 dob = 255; 120 break; 121 122 case MiscComposite.SUBTRACT: 123 dor = dir - sr; 124 if ( dor < 0 ) 125 dor = 0; 126 dog = dig - sg; 127 if ( dog < 0 ) 128 dog = 0; 129 dob = dib - sb; 130 if ( dob < 0 ) 131 dob = 0; 132 break; 133 134 case MiscComposite.DIFFERENCE: 135 dor = dir - sr; 136 if ( dor < 0 ) 137 dor = -dor; 138 dog = dig - sg; 139 if ( dog < 0 ) 140 dog = -dog; 141 dob = dib - sb; 142 if ( dob < 0 ) 143 dob = -dob; 144 break; 145 146 case MiscComposite.MULTIPLY: 147 t = dir * sr + 0x80; 148 dor = ((t >> 8) + t) >> 8; 149 t = dig * sg + 0x80; 150 dog = ((t >> 8) + t) >> 8; 151 t = dib * sb + 0x80; 152 dob = ((t >> 8) + t) >> 8; 153 break; 154 155 case MiscComposite.SCREEN: 156 t = (255-dir) * (255-sr) + 0x80; 157 dor = 255 - ( ((t >> 8) + t) >> 8 ); 158 t = (255-dig) * (255-sg) + 0x80; 159 dog = 255 - ( ((t >> 8) + t) >> 8 ); 160 t = (255-dib) * (255-sb) + 0x80; 161 dob = 255 - ( ((t >> 8) + t) >> 8 ); 162 break; 163 164 case MiscComposite.OVERLAY: 165 if ( dir < 128 ) { 166 t = dir * sr + 0x80; 167 dor = 2 * (((t >> 8) + t) >> 8); 168 } else { 169 t = (255-dir) * (255-sr) + 0x80; 170 dor = 2 * (255 - ( ((t >> 8) + t) >> 8 )); 171 } 172 if ( dig < 128 ) { 173 t = dig * sg + 0x80; 174 dog = 2 * (((t >> 8) + t) >> 8); 175 } else { 176 t = (255-dig) * (255-sg) + 0x80; 177 dog = 2 * (255 - ( ((t >> 8) + t) >> 8 )); 178 } 179 if ( dib < 128 ) { 180 t = dib * sb + 0x80; 181 dob = 2 * (((t >> 8) + t) >> 8); 182 } else { 183 t = (255-dib) * (255-sb) + 0x80; 184 dob = 2 * (255 - ( ((t >> 8) + t) >> 8 )); 185 } 186 break; 187 188 case MiscComposite.DARKEN: 189 dor = dir < sr ? dir : sr; 190 dog = dig < sg ? dig : sg; 191 dob = dib < sb ? dib : sb; 192 break; 193 194 case MiscComposite.LIGHTEN: 195 dor = dir > sr ? dir : sr; 196 dog = dig > sg ? dig : sg; 197 dob = dib > sb ? dib : sb; 198 break; 199 200 case MiscComposite.AVERAGE: 201 dor = (dir + sr) / 2; 202 dog = (dig + sg) / 2; 203 dob = (dib + sb) / 2; 204 break; 205 206 case MiscComposite.HUE: 207 case MiscComposite.SATURATION: 208 case MiscComposite.VALUE: 209 case MiscComposite.COLOR: 210 Color.RGBtoHSB(sr, sg, sb, sHsv); 211 Color.RGBtoHSB(dir, dig, dib, diHsv); 212 213 switch(rule) { 214 case MiscComposite.HUE: 215 doHsv[0] = sHsv[0]; 216 doHsv[1] = diHsv[1]; 217 doHsv[2] = diHsv[2]; 218 break; 219 case MiscComposite.SATURATION: 220 doHsv[0] = diHsv[0]; 221 doHsv[1] = sHsv[1]; 222 doHsv[2] = diHsv[2]; 223 break; 224 case MiscComposite.VALUE: 225 doHsv[0] = diHsv[0]; 226 doHsv[1] = diHsv[1]; 227 doHsv[2] = sHsv[2]; 228 break; 229 case MiscComposite.COLOR: 230 doHsv[0] = sHsv[0]; 231 doHsv[1] = sHsv[1]; 232 doHsv[2] = diHsv[2]; 233 break; 234 } 235 236 int doRGB = Color.HSBtoRGB(doHsv[0], doHsv[1], doHsv[2]); 237 dor = (doRGB&0xff0000)>>16; 238 dog = (doRGB&0xff00)>>8; 239 dob = (doRGB&0xff); 240 break; 241 242 case MiscComposite.BURN: 243 if (dir != 255) 244 dor = clamp(255-(((int)(255-sr) << 8) / (dir+1))); 245 else 246 dor = sr; 247 if (dig != 255) 248 dog = clamp(255-(((int)(255-sg) << 8) / (dig+1))); 249 else 250 dog = sg; 251 if (dib != 255) 252 dob = clamp(255-(((int)(255-sb) << 8) / (dib+1))); 253 else 254 dob = sb; 255 break; 256 257 case MiscComposite.COLOR_BURN: 258 if (sr != 0) 259 dor = Math.max(255 - (((int)(255-dir) << 8) / sr), 0); 260 else 261 dor = sr; 262 if (sg != 0) 263 dog = Math.max(255 - (((int)(255-dig) << 8) / sg), 0); 264 else 265 dog = sg; 266 if (sb != 0) 267 dob = Math.max(255 - (((int)(255-dib) << 8) / sb), 0); 268 else 269 dob = sb; 270 break; 271 272 case MiscComposite.DODGE: 273 dor = clamp((sr << 8) / (256-dir)); 274 dog = clamp((sg << 8) / (256-dig)); 275 dob = clamp((sb << 8) / (256-dib)); 276 break; 277 278 case MiscComposite.COLOR_DODGE: 279 if (sr != 255) 280 dor = Math.min((dir << 8) / (255-sr), 255); 281 else 282 dor = sr; 283 if (sg != 255) 284 dog = Math.min((dig << 8) / (255-sg), 255); 285 else 286 dog = sg; 287 if (sb != 255) 288 dob = Math.min((dib << 8) / (255-sb), 255); 289 else 290 dob = sb; 291 break; 292 293 case MiscComposite.SOFT_LIGHT: 294 int d; 295 d = multiply255(sr, dir); 296 dor = d + multiply255(dir, 255 - multiply255(255-dir, 255-sr)-d); 297 d = multiply255(sg, dig); 298 dog = d + multiply255(dig, 255 - multiply255(255-dig, 255-sg)-d); 299 d = multiply255(sb, dib); 300 dob = d + multiply255(dib, 255 - multiply255(255-dib, 255-sb)-d); 301 break; 302 303 case MiscComposite.HARD_LIGHT: 304 if (sr > 127) 305 dor = 255 - 2*multiply255(255 - sr, 255 - dir); 306 else 307 dor = 2*multiply255(sr, dir); 308 if (sg > 127) 309 dog = 255 - 2*multiply255(255 - sg, 255 - dig); 310 else 311 dog = 2*multiply255(sg, dig); 312 if (sb > 127) 313 dob = 255 - 2*multiply255(255 - sb, 255 - dib); 314 else 315 dob = 2*multiply255(sb, dib); 316 break; 317 318 case MiscComposite.PIN_LIGHT: 319 dor = sr > 127 ? Math.max(sr, dir) : Math.min(sr, dir); 320 dog = sg > 127 ? Math.max(sg, dig) : Math.min(sg, dig); 321 dob = sb > 127 ? Math.max(sb, dib) : Math.min(sb, dib); 322 break; 323 324 case MiscComposite.EXCLUSION: 325 dor = dir+multiply255(sr, (255-dir-dir)); 326 dog = dig+multiply255(sg, (255-dig-dig)); 327 dob = dib+multiply255(sb, (255-dib-dib)); 328 break; 329 330 case MiscComposite.NEGATION: 331 dor = 255 - Math.abs(255-sr-dir); 332 dog = 255 - Math.abs(255-sg-dig); 333 dob = 255 - Math.abs(255-sb-dib); 334 break; 335 } 336 337 a = alpha*sa/255f; 338 ac = 1-a; 339 340 dstPix[i] = (int)(a*dor + ac*dir); 341 dstPix[i+1] = (int)(a*dog + ac*dig); 342 dstPix[i+2] = (int)(a*dob + ac*dib); 343 dstPix[i+3] = (int)(sa*alpha + dia*ac); 344 i += 4; 345 } 346 dstOut.setPixels(x, y, w, 1, dstPix); 347 } 348 } 349 350}