001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019/* 020* 021 022Licensed under the Apache License, Version 2.0 (the "License"); 023you may not use this file except in compliance with the License. 024You may obtain a copy of the License at 025 026 http://www.apache.org/licenses/LICENSE-2.0 027 028Unless required by applicable law or agreed to in writing, software 029distributed under the License is distributed on an "AS IS" BASIS, 030WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 031See the License for the specific language governing permissions and 032limitations under the License. 033*/ 034 035package lucee.runtime.img.composite; 036 037import java.awt.Color; 038import java.awt.CompositeContext; 039import java.awt.color.ColorSpace; 040import java.awt.image.ColorModel; 041import java.awt.image.Raster; 042import java.awt.image.WritableRaster; 043 044public class MiscCompositeContext implements CompositeContext { 045 046 private int rule; 047 private float alpha; 048 private ColorModel srcColorModel; 049 private ColorModel dstColorModel; 050 private ColorSpace srcColorSpace; 051 private ColorSpace dstColorSpace; 052 private boolean srcNeedsConverting; 053 private boolean dstNeedsConverting; 054 055 public MiscCompositeContext(int rule, 056 float alpha, 057 ColorModel srcColorModel, 058 ColorModel dstColorModel) { 059 this.rule = rule; 060 this.alpha = alpha; 061 this.srcColorModel = srcColorModel; 062 this.dstColorModel = dstColorModel; 063 this.srcColorSpace = srcColorModel.getColorSpace(); 064 this.dstColorSpace = dstColorModel.getColorSpace(); 065 //ColorModel srgbCM = ColorModel.getRGBdefault(); 066// srcNeedsConverting = !srcColorModel.equals(srgbCM); 067// dstNeedsConverting = !dstColorModel.equals(srgbCM); 068 } 069 070 public void dispose() { 071 } 072 073 // Multiply two numbers in the range 0..255 such that 255*255=255 074 static int multiply255( int a, int b ) { 075 int t = a * b + 0x80; 076 return ((t >> 8) + t) >> 8; 077 } 078 079 static int clamp( int a ) { 080 return a < 0 ? 0 : a > 255 ? 255 : a; 081 } 082 083 public void compose(Raster src, Raster dstIn, WritableRaster dstOut) { 084 float a=0, ac=0; 085 float alpha = this.alpha; 086 int t; 087 088 float[] sHsv = null, diHsv = null, doHsv = null; 089 switch ( rule ) { 090 case MiscComposite.HUE: 091 case MiscComposite.SATURATION: 092 case MiscComposite.VALUE: 093 case MiscComposite.COLOR: 094 sHsv = new float[3]; 095 diHsv = new float[3]; 096 doHsv = new float[3]; 097 break; 098 } 099 100 int[] srcPix = null; 101 int[] dstPix = null; 102 103 int x = dstOut.getMinX(); 104 int w = dstOut.getWidth(); 105 106 int y0 = dstOut.getMinY(); 107 int y1 = y0 + dstOut.getHeight(); 108 109 for ( int y = y0; y < y1; y++ ) { 110 srcPix = src.getPixels(x, y, w, 1, srcPix); 111 dstPix = dstIn.getPixels(x, y, w, 1, dstPix); 112 int i = 0; 113 int end = w*4; 114 115 while ( i < end ) { 116 int sr = srcPix[i]; 117 int dir = dstPix[i]; 118 int sg = srcPix[i+1]; 119 int dig = dstPix[i+1]; 120 int sb = srcPix[i+2]; 121 int dib = dstPix[i+2]; 122 int sa = srcPix[i+3]; 123 int dia = dstPix[i+3]; 124 int dor, dog, dob; 125 126 switch ( rule ) { 127 case MiscComposite.ADD: 128 default: 129 dor = dir + sr; 130 if ( dor > 255 ) 131 dor = 255; 132 dog = dig + sg; 133 if ( dog > 255 ) 134 dog = 255; 135 dob = dib + sb; 136 if ( dob > 255 ) 137 dob = 255; 138 break; 139 140 case MiscComposite.SUBTRACT: 141 dor = dir - sr; 142 if ( dor < 0 ) 143 dor = 0; 144 dog = dig - sg; 145 if ( dog < 0 ) 146 dog = 0; 147 dob = dib - sb; 148 if ( dob < 0 ) 149 dob = 0; 150 break; 151 152 case MiscComposite.DIFFERENCE: 153 dor = dir - sr; 154 if ( dor < 0 ) 155 dor = -dor; 156 dog = dig - sg; 157 if ( dog < 0 ) 158 dog = -dog; 159 dob = dib - sb; 160 if ( dob < 0 ) 161 dob = -dob; 162 break; 163 164 case MiscComposite.MULTIPLY: 165 t = dir * sr + 0x80; 166 dor = ((t >> 8) + t) >> 8; 167 t = dig * sg + 0x80; 168 dog = ((t >> 8) + t) >> 8; 169 t = dib * sb + 0x80; 170 dob = ((t >> 8) + t) >> 8; 171 break; 172 173 case MiscComposite.SCREEN: 174 t = (255-dir) * (255-sr) + 0x80; 175 dor = 255 - ( ((t >> 8) + t) >> 8 ); 176 t = (255-dig) * (255-sg) + 0x80; 177 dog = 255 - ( ((t >> 8) + t) >> 8 ); 178 t = (255-dib) * (255-sb) + 0x80; 179 dob = 255 - ( ((t >> 8) + t) >> 8 ); 180 break; 181 182 case MiscComposite.OVERLAY: 183 if ( dir < 128 ) { 184 t = dir * sr + 0x80; 185 dor = 2 * (((t >> 8) + t) >> 8); 186 } else { 187 t = (255-dir) * (255-sr) + 0x80; 188 dor = 2 * (255 - ( ((t >> 8) + t) >> 8 )); 189 } 190 if ( dig < 128 ) { 191 t = dig * sg + 0x80; 192 dog = 2 * (((t >> 8) + t) >> 8); 193 } else { 194 t = (255-dig) * (255-sg) + 0x80; 195 dog = 2 * (255 - ( ((t >> 8) + t) >> 8 )); 196 } 197 if ( dib < 128 ) { 198 t = dib * sb + 0x80; 199 dob = 2 * (((t >> 8) + t) >> 8); 200 } else { 201 t = (255-dib) * (255-sb) + 0x80; 202 dob = 2 * (255 - ( ((t >> 8) + t) >> 8 )); 203 } 204 break; 205 206 case MiscComposite.DARKEN: 207 dor = dir < sr ? dir : sr; 208 dog = dig < sg ? dig : sg; 209 dob = dib < sb ? dib : sb; 210 break; 211 212 case MiscComposite.LIGHTEN: 213 dor = dir > sr ? dir : sr; 214 dog = dig > sg ? dig : sg; 215 dob = dib > sb ? dib : sb; 216 break; 217 218 case MiscComposite.AVERAGE: 219 dor = (dir + sr) / 2; 220 dog = (dig + sg) / 2; 221 dob = (dib + sb) / 2; 222 break; 223 224 case MiscComposite.HUE: 225 case MiscComposite.SATURATION: 226 case MiscComposite.VALUE: 227 case MiscComposite.COLOR: 228 Color.RGBtoHSB(sr, sg, sb, sHsv); 229 Color.RGBtoHSB(dir, dig, dib, diHsv); 230 231 switch(rule) { 232 case MiscComposite.HUE: 233 doHsv[0] = sHsv[0]; 234 doHsv[1] = diHsv[1]; 235 doHsv[2] = diHsv[2]; 236 break; 237 case MiscComposite.SATURATION: 238 doHsv[0] = diHsv[0]; 239 doHsv[1] = sHsv[1]; 240 doHsv[2] = diHsv[2]; 241 break; 242 case MiscComposite.VALUE: 243 doHsv[0] = diHsv[0]; 244 doHsv[1] = diHsv[1]; 245 doHsv[2] = sHsv[2]; 246 break; 247 case MiscComposite.COLOR: 248 doHsv[0] = sHsv[0]; 249 doHsv[1] = sHsv[1]; 250 doHsv[2] = diHsv[2]; 251 break; 252 } 253 254 int doRGB = Color.HSBtoRGB(doHsv[0], doHsv[1], doHsv[2]); 255 dor = (doRGB&0xff0000)>>16; 256 dog = (doRGB&0xff00)>>8; 257 dob = (doRGB&0xff); 258 break; 259 260 case MiscComposite.BURN: 261 if (dir != 255) 262 dor = clamp(255-(((255-sr) << 8) / (dir+1))); 263 else 264 dor = sr; 265 if (dig != 255) 266 dog = clamp(255-(((255-sg) << 8) / (dig+1))); 267 else 268 dog = sg; 269 if (dib != 255) 270 dob = clamp(255-(((255-sb) << 8) / (dib+1))); 271 else 272 dob = sb; 273 break; 274 275 case MiscComposite.COLOR_BURN: 276 if (sr != 0) 277 dor = Math.max(255 - (((255-dir) << 8) / sr), 0); 278 else 279 dor = sr; 280 if (sg != 0) 281 dog = Math.max(255 - (((255-dig) << 8) / sg), 0); 282 else 283 dog = sg; 284 if (sb != 0) 285 dob = Math.max(255 - (((255-dib) << 8) / sb), 0); 286 else 287 dob = sb; 288 break; 289 290 case MiscComposite.DODGE: 291 dor = clamp((sr << 8) / (256-dir)); 292 dog = clamp((sg << 8) / (256-dig)); 293 dob = clamp((sb << 8) / (256-dib)); 294 break; 295 296 case MiscComposite.COLOR_DODGE: 297 if (sr != 255) 298 dor = Math.min((dir << 8) / (255-sr), 255); 299 else 300 dor = sr; 301 if (sg != 255) 302 dog = Math.min((dig << 8) / (255-sg), 255); 303 else 304 dog = sg; 305 if (sb != 255) 306 dob = Math.min((dib << 8) / (255-sb), 255); 307 else 308 dob = sb; 309 break; 310 311 case MiscComposite.SOFT_LIGHT: 312 int d; 313 d = multiply255(sr, dir); 314 dor = d + multiply255(dir, 255 - multiply255(255-dir, 255-sr)-d); 315 d = multiply255(sg, dig); 316 dog = d + multiply255(dig, 255 - multiply255(255-dig, 255-sg)-d); 317 d = multiply255(sb, dib); 318 dob = d + multiply255(dib, 255 - multiply255(255-dib, 255-sb)-d); 319 break; 320 321 case MiscComposite.HARD_LIGHT: 322 if (sr > 127) 323 dor = 255 - 2*multiply255(255 - sr, 255 - dir); 324 else 325 dor = 2*multiply255(sr, dir); 326 if (sg > 127) 327 dog = 255 - 2*multiply255(255 - sg, 255 - dig); 328 else 329 dog = 2*multiply255(sg, dig); 330 if (sb > 127) 331 dob = 255 - 2*multiply255(255 - sb, 255 - dib); 332 else 333 dob = 2*multiply255(sb, dib); 334 break; 335 336 case MiscComposite.PIN_LIGHT: 337 dor = sr > 127 ? Math.max(sr, dir) : Math.min(sr, dir); 338 dog = sg > 127 ? Math.max(sg, dig) : Math.min(sg, dig); 339 dob = sb > 127 ? Math.max(sb, dib) : Math.min(sb, dib); 340 break; 341 342 case MiscComposite.EXCLUSION: 343 dor = dir+multiply255(sr, (255-dir-dir)); 344 dog = dig+multiply255(sg, (255-dig-dig)); 345 dob = dib+multiply255(sb, (255-dib-dib)); 346 break; 347 348 case MiscComposite.NEGATION: 349 dor = 255 - Math.abs(255-sr-dir); 350 dog = 255 - Math.abs(255-sg-dig); 351 dob = 255 - Math.abs(255-sb-dib); 352 break; 353 } 354 355 a = alpha*sa/255f; 356 ac = 1-a; 357 358 dstPix[i] = (int)(a*dor + ac*dir); 359 dstPix[i+1] = (int)(a*dog + ac*dig); 360 dstPix[i+2] = (int)(a*dob + ac*dib); 361 dstPix[i+3] = (int)(sa*alpha + dia*ac); 362 i += 4; 363 } 364 dstOut.setPixels(x, y, w, 1, dstPix); 365 } 366 } 367 368}