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.composite;
018    
019    import java.awt.Color;
020    import java.awt.CompositeContext;
021    import java.awt.color.ColorSpace;
022    import java.awt.image.ColorModel;
023    import java.awt.image.Raster;
024    import java.awt.image.WritableRaster;
025    
026    public 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-(((255-sr) << 8) / (dir+1)));
245                                            else
246                                                    dor = sr;
247                                            if (dig != 255)
248                                                    dog = clamp(255-(((255-sg) << 8) / (dig+1)));
249                                            else
250                                                    dog = sg;
251                                            if (dib != 255)
252                                                    dob = clamp(255-(((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 - (((255-dir) << 8) / sr), 0);
260                                            else
261                                                    dor = sr;
262                                            if (sg != 0)
263                                                    dog = Math.max(255 - (((255-dig) << 8) / sg), 0);
264                                            else
265                                                    dog = sg;
266                                            if (sb != 0)
267                                                    dob = Math.max(255 - (((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    }