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}