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}