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.Composite;
020    import java.awt.CompositeContext;
021    import java.awt.RenderingHints;
022    import java.awt.image.ColorModel;
023    import java.awt.image.Raster;
024    import java.awt.image.WritableRaster;
025    
026    /**
027     * A special Composite used for drawing "marching ants". It draws the ants at the 127 contour of the alpha channel of the source.
028     * This can only be used on TYPE_INT_RGBA images.
029     */
030    public final class ContourComposite implements Composite {
031    
032            private int offset;
033    
034            public ContourComposite( int offset ) {
035                    this.offset = offset;
036            }
037    
038            public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints) {
039                    return new ContourCompositeContext( offset, srcColorModel, dstColorModel );
040            }
041    
042            public int hashCode() {
043                    return 0;
044            }
045    
046            public boolean equals(Object o) {
047                    if (!(o instanceof ContourComposite))
048                            return false;
049                    return true;
050            }
051    
052    }
053    
054    class ContourCompositeContext implements CompositeContext {
055    
056            private int offset;
057    
058            public ContourCompositeContext( int offset, ColorModel srcColorModel, ColorModel dstColorModel ) {
059                    this.offset = offset;
060            }
061    
062            public void dispose() {
063            }
064            
065            public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
066                    int x = src.getMinX();
067                    int y = src.getMinY();
068                    int w = src.getWidth();
069                    int h = src.getHeight();
070    
071                    int[] srcPix = null;
072                    int[] srcPix2 = null;
073                    int[] dstInPix = null;
074                    int[] dstOutPix = new int[w*4];
075    
076                    for ( int i = 0; i < h; i++ ) {
077                            srcPix = src.getPixels(x, y, w, 1, srcPix);
078                            dstInPix = dstIn.getPixels(x, y, w, 1, dstInPix);
079    
080                            int lastAlpha = 0;
081                            int k = 0;
082                            for ( int j = 0; j < w; j++ ) {
083                                    int alpha = srcPix[k+3];
084                                    int alphaAbove = i != 0 ? srcPix2[k+3] : alpha;
085    
086                                    if ( i != 0 && j != 0 && ((alpha ^ lastAlpha) & 0x80) != 0 || ((alpha ^ alphaAbove) & 0x80) != 0 ) {
087                                            if ((offset+i+j)%10 > 4) {
088                                                    dstOutPix[k] = 0x00;
089                                                    dstOutPix[k+1] = 0x00;
090                                                    dstOutPix[k+2] = 0x00;
091                                            } else {
092                                                    dstOutPix[k] = 0xff;
093                                                    dstOutPix[k+1] = 0xff;
094                                                    dstOutPix[k+2] = 0x7f;
095                                            }
096                                            dstOutPix[k+3] = 0xff;
097                                    } else {
098                                            dstOutPix[k] = dstInPix[k];
099                                            dstOutPix[k+1] = dstInPix[k+1];
100                                            dstOutPix[k+2] = dstInPix[k+2];
101    //                                      if ( dstOut == dstIn )
102                                                    dstOutPix[k] = 0xff;
103                                                    dstOutPix[k+1] = 0;
104                                                    dstOutPix[k+2] = 0;
105                                                    dstOutPix[k+3] = 0;
106    //                                      else
107    //                                              dstOutPix[k+3] = dstInPix[k+3];
108                                    }
109    
110                                    lastAlpha = alpha;
111                                    k += 4;
112                            }
113    
114                            dstOut.setPixels(x, y, w, 1, dstOutPix);
115    
116                            int[] t = srcPix;
117                            srcPix = srcPix2;
118                            srcPix2 = t;
119                            y++;
120                    }
121            }
122    
123    }