You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by cf...@apache.org on 2012/10/25 21:01:49 UTC

svn commit: r1402274 [27/31] - in /incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext: ./ awt/ awt/color/ awt/font/ awt/g2d/ awt/geom/ awt/image/ awt/image/codec/ awt/image/codec/jpeg/ awt/image/codec/p...

Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FilterAlphaRed.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FilterAlphaRed.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FilterAlphaRed.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FilterAlphaRed.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,69 @@
+/*
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.image.rendered;
+
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+
+import org.apache.flex.forks.batik.ext.awt.ColorSpaceHintKey;
+
+/**
+ * This strips out the source alpha channel into a one band image.
+ *
+ * @author <a href="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a>
+ * @version $Id: FilterAlphaRed.java 475477 2006-11-15 22:44:28Z cam $ */
+public class FilterAlphaRed extends AbstractRed {
+
+    /**
+     * Construct an alpah channel from the given src, according to
+     * the SVG masking rules.
+     *
+     * @param src The image to convert to an alpha channel (mask image)
+     */
+    public FilterAlphaRed(CachableRed src) {
+        super(src, src.getBounds(), 
+              src.getColorModel(),
+              src.getSampleModel(),
+              src.getTileGridXOffset(),
+              src.getTileGridYOffset(),
+              null);
+
+        props.put(ColorSpaceHintKey.PROPERTY_COLORSPACE,
+                  ColorSpaceHintKey.VALUE_COLORSPACE_ALPHA);
+    }
+
+    public WritableRaster copyData(WritableRaster wr) {
+        // new Exception("FilterAlphaRed: ").printStackTrace();
+        // Get my source.
+        CachableRed srcRed = (CachableRed)getSources().get(0);
+
+        SampleModel sm = srcRed.getSampleModel();
+        if (sm.getNumBands() == 1)
+            // Already one band of data so we just use it...
+            return srcRed.copyData(wr);
+
+        PadRed.ZeroRecter.zeroRect(wr);
+        Raster srcRas = srcRed.getData(wr.getBounds());
+        AbstractRed.copyBand(srcRas, srcRas.getNumBands()-1, wr, 
+                             wr.getNumBands()-1);
+        return wr;
+    }
+
+}    

Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FilterAlphaRed.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FilterAsAlphaRed.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FilterAsAlphaRed.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FilterAsAlphaRed.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FilterAsAlphaRed.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,153 @@
+/*
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.image.rendered;
+
+
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.PixelInterleavedSampleModel;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+
+import org.apache.flex.forks.batik.ext.awt.ColorSpaceHintKey;
+
+/**
+ * This converts any source into a mask according to the SVG masking rules.
+ *
+ * @author <a href="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a>
+ * @version $Id: FilterAsAlphaRed.java 475477 2006-11-15 22:44:28Z cam $ */
+public class FilterAsAlphaRed extends AbstractRed {
+
+    /**
+     * Construct an alpah channel from the given src, according to
+     * the SVG masking rules.
+     *
+     * @param src The image to convert to an alpha channel (mask image)
+     */
+    public FilterAsAlphaRed(CachableRed src) {
+        super(new Any2LumRed(src),src.getBounds(), 
+              new ComponentColorModel
+                  (ColorSpace.getInstance(ColorSpace.CS_GRAY),
+                   new int [] {8}, false, false,
+                   Transparency.OPAQUE, 
+                   DataBuffer.TYPE_BYTE),
+              new PixelInterleavedSampleModel
+                  (DataBuffer.TYPE_BYTE, 
+                   src.getSampleModel().getWidth(),
+                   src.getSampleModel().getHeight(),
+                   1, src.getSampleModel().getWidth(),
+                   new int [] { 0 }),
+              src.getTileGridXOffset(),
+              src.getTileGridYOffset(),
+              null);
+
+        props.put(ColorSpaceHintKey.PROPERTY_COLORSPACE,
+                  ColorSpaceHintKey.VALUE_COLORSPACE_ALPHA);
+    }
+
+    public WritableRaster copyData(WritableRaster wr) {
+        // Get my source.
+        CachableRed srcRed = (CachableRed)getSources().get(0);
+
+        SampleModel sm = srcRed.getSampleModel();
+        if (sm.getNumBands() == 1)
+            // Already one band of data so we just use it...
+            return srcRed.copyData(wr);
+
+        // Two band case so we need to multiply them...
+        // Note: Our source will always have either one or two bands
+        // since we insert an Any2Lum transform before ourself in the
+        // rendering chain.
+
+        Raster srcRas = srcRed.getData(wr.getBounds());
+        PixelInterleavedSampleModel srcSM;
+        srcSM = (PixelInterleavedSampleModel)srcRas.getSampleModel();
+
+        DataBufferByte srcDB = (DataBufferByte)srcRas.getDataBuffer();
+        byte []        src   = srcDB.getData();
+        
+        PixelInterleavedSampleModel dstSM;
+        dstSM = (PixelInterleavedSampleModel)wr.getSampleModel();
+
+        DataBufferByte dstDB = (DataBufferByte)wr.getDataBuffer();
+        byte []        dst   = dstDB.getData();
+
+        int srcX0 = srcRas.getMinX()-srcRas.getSampleModelTranslateX();
+        int srcY0 = srcRas.getMinY()-srcRas.getSampleModelTranslateY();
+
+        int dstX0 = wr.getMinX()-wr.getSampleModelTranslateX();
+        int dstX1 = dstX0+wr.getWidth()-1;
+        int dstY0 = wr.getMinY()-wr.getSampleModelTranslateY();
+
+        int    srcStep = srcSM.getPixelStride();
+        int [] offsets = srcSM.getBandOffsets();
+        int    srcLOff = offsets[0];
+        int    srcAOff = offsets[1];
+
+        if (srcRed.getColorModel().isAlphaPremultiplied()) {
+            // Lum is already multiplied by alpha so we just copy lum channel.
+            for (int y=0; y<srcRas.getHeight(); y++) {
+                int srcI  = srcDB.getOffset() + srcSM.getOffset(srcX0,  srcY0);
+                int dstI  = dstDB.getOffset() + dstSM.getOffset(dstX0,  dstY0);
+                int dstE  = dstDB.getOffset() + dstSM.getOffset(dstX1+1,dstY0);
+
+                srcI += srcLOff; // Go to Lum Channel (already mult by alpha).
+
+                while (dstI < dstE) {
+                    dst[dstI++] = src[srcI];
+                        srcI += srcStep; // Go to next pixel
+                }
+                srcY0++;
+                dstY0++;
+            }
+        }
+        else {
+            // This allows me to pre-adjust my index by srcLOff
+            // Then only add the offset for srcAOff
+            srcAOff = srcAOff-srcLOff;
+
+            for (int y=0; y<srcRas.getHeight(); y++) {
+                int srcI  = srcDB.getOffset() + srcSM.getOffset(srcX0,  srcY0);
+                int dstI  = dstDB.getOffset() + dstSM.getOffset(dstX0,  dstY0);
+                int dstE  = dstDB.getOffset() + dstSM.getOffset(dstX1+1,dstY0);
+
+                srcI += srcLOff;
+
+                while (dstI < dstE) {
+                    int sl = (src[srcI])&0xFF; // LOff already included
+                    int sa = (src[srcI+srcAOff])&0xFF;
+                    // the + 0x80 forces proper rounding.
+                    dst[dstI++] = (byte)((sl*sa+0x80)>>8);
+
+                    srcI+= srcStep; //  next pixel
+                }
+                srcY0++;
+                dstY0++;
+            }
+        }
+
+        return wr;
+    }
+
+}    

Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FilterAsAlphaRed.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FloodRed.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FloodRed.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FloodRed.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FloodRed.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,127 @@
+/*
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.image.rendered;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+
+import org.apache.flex.forks.batik.ext.awt.image.GraphicsUtil;
+
+/**
+ * This implementation of RenderedImage will generate an infinate
+ * field of a single color.  It reports bounds but will in fact render
+ * out to infinity.
+ *
+ * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
+ * @version $Id: FloodRed.java 475477 2006-11-15 22:44:28Z cam $ 
+ */
+public class FloodRed extends AbstractRed {
+
+    /**
+     * A single tile that we move around as needed...
+     */
+    private WritableRaster raster;
+
+    /**
+     * Construct a fully transparent black image <tt>bounds</tt> size.
+     * @param bounds the bounds of the image (in fact will respond with
+     *               any request).
+     */
+    public FloodRed(Rectangle bounds) {
+        this(bounds, new Color(0, 0, 0, 0));
+    }
+
+    /**
+     * Construct a fully transparent image <tt>bounds</tt> size, will
+     * paint one tile with paint.  Thus paint should not be a pattered
+     * paint or gradient but should be a solid color.
+     * @param bounds the bounds of the image (in fact will respond with
+     *               any request).  
+     */
+    public FloodRed(Rectangle bounds,
+                    Paint paint) {
+        super(); // We _must_ call init...
+
+        ColorModel cm = GraphicsUtil.sRGB_Unpre;
+        
+        int defSz = AbstractTiledRed.getDefaultTileSize();
+
+        int tw = bounds.width;
+        if (tw > defSz) tw = defSz;
+        int th = bounds.height;
+        if (th > defSz) th = defSz;
+
+        // fix my sample model so it makes sense given my size.
+        SampleModel sm = cm.createCompatibleSampleModel(tw, th);
+
+        // Finish initializing our base class...
+        init((CachableRed)null, bounds, cm, sm, 0, 0, null);
+
+        raster = Raster.createWritableRaster(sm, new Point(0, 0));
+        BufferedImage offScreen = new BufferedImage(cm, raster,
+                                                    cm.isAlphaPremultiplied(),
+                                                    null);
+
+        Graphics2D g = GraphicsUtil.createGraphics(offScreen);
+        g.setPaint(paint);
+        g.fillRect(0, 0, bounds.width, bounds.height);
+        g.dispose();
+    }
+
+    public Raster getTile(int x, int y) {
+        // We have a Single raster that we translate where needed
+        // position.  So just offest appropriately.
+        int tx = tileGridXOff+x*tileWidth;
+        int ty = tileGridYOff+y*tileHeight;
+        return raster.createTranslatedChild(tx, ty);
+    }
+
+    public WritableRaster copyData(WritableRaster wr) {
+        int tx0 = getXTile(wr.getMinX());
+        int ty0 = getYTile(wr.getMinY());
+        int tx1 = getXTile(wr.getMinX()+wr.getWidth() -1);
+        int ty1 = getYTile(wr.getMinY()+wr.getHeight()-1);
+
+        final boolean is_INT_PACK = 
+            GraphicsUtil.is_INT_PACK_Data(getSampleModel(), false);
+
+        for (int y=ty0; y<=ty1; y++)
+            for (int x=tx0; x<=tx1; x++) {
+                Raster r = getTile(x, y);
+                if (is_INT_PACK)
+                    GraphicsUtil.copyData_INT_PACK(r, wr);
+                else
+                    GraphicsUtil.copyData_FALLBACK(r, wr);
+            }
+
+        return wr;
+    }
+}
+
+
+
+

Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FloodRed.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FormatRed.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FormatRed.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FormatRed.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FormatRed.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,204 @@
+/*
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.image.rendered;
+
+
+import java.awt.Point;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.ComponentSampleModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DirectColorModel;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.WritableRaster;
+
+import org.apache.flex.forks.batik.ext.awt.image.GraphicsUtil;
+
+
+/**
+ * This allows you to specify the ColorModel, Alpha premult and/or
+ * SampleModel to be used for output.  If the input image lacks
+ * Alpha and alpha is included in output then it is filled with
+ * alpha=1.  In all other cases bands are simply copied.
+ *
+ * @author <a href="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a>
+ * @version $Id: FormatRed.java 478363 2006-11-22 23:01:13Z dvholten $
+ */
+public class FormatRed extends AbstractRed {
+
+    public static CachableRed construct(CachableRed src, ColorModel cm) {
+        ColorModel srcCM = src.getColorModel();
+        if ((cm.hasAlpha() != srcCM.hasAlpha()) ||
+            (cm.isAlphaPremultiplied() != srcCM.isAlphaPremultiplied()))
+            return new FormatRed(src, cm);
+
+        if (cm.getNumComponents() != srcCM.getNumComponents())
+            throw new IllegalArgumentException
+                ("Incompatible ColorModel given");
+
+
+        if ((srcCM instanceof ComponentColorModel) &&
+            (cm    instanceof ComponentColorModel))
+            return src;
+
+        if ((srcCM instanceof DirectColorModel) &&
+            (cm    instanceof DirectColorModel))
+            return src;
+
+        return new FormatRed(src, cm);
+    }
+
+    /**
+     * Construct an instance of CachableRed around a BufferedImage.
+     */
+    public FormatRed(CachableRed cr, SampleModel sm) {
+        super(cr, cr.getBounds(),
+              makeColorModel(cr, sm), sm,
+              cr.getTileGridXOffset(),
+              cr.getTileGridYOffset(),
+              null);
+    }
+
+    public FormatRed(CachableRed cr, ColorModel cm) {
+        super(cr, cr.getBounds(),
+              cm, makeSampleModel(cr, cm),
+              cr.getTileGridXOffset(),
+              cr.getTileGridYOffset(),
+              null);
+    }
+
+    /**
+     * fetch the source image for this node.
+     */
+    public CachableRed getSource() {
+        return (CachableRed)getSources().get(0);
+    }
+
+    public Object getProperty(String name) {
+        return getSource().getProperty(name);
+    }
+
+    public String [] getPropertyNames() {
+        return getSource().getPropertyNames();
+    }
+
+    public WritableRaster copyData(WritableRaster wr) {
+        ColorModel  cm    = getColorModel();
+        CachableRed cr    = getSource();
+        ColorModel  srcCM = cr.getColorModel();
+        SampleModel srcSM = cr.getSampleModel();
+        srcSM = srcSM.createCompatibleSampleModel(wr.getWidth(),
+                                                  wr.getHeight());
+        WritableRaster srcWR;
+        srcWR = Raster.createWritableRaster(srcSM, new Point(wr.getMinX(),
+                                                             wr.getMinY()));
+        getSource().copyData(srcWR);
+
+        BufferedImage srcBI = new BufferedImage
+            (srcCM, srcWR.createWritableTranslatedChild(0,0),
+             srcCM.isAlphaPremultiplied(), null);
+        BufferedImage dstBI = new BufferedImage
+            (cm, wr.createWritableTranslatedChild(0,0),
+             cm.isAlphaPremultiplied(), null);
+
+        GraphicsUtil.copyData(srcBI, dstBI);
+
+        return wr;
+    }
+
+    public static SampleModel makeSampleModel(CachableRed cr, ColorModel cm) {
+        SampleModel srcSM = cr.getSampleModel();
+        return cm.createCompatibleSampleModel(srcSM.getWidth(),
+                                              srcSM.getHeight());
+    }
+
+    public static ColorModel makeColorModel(CachableRed cr, SampleModel sm) {
+        ColorModel srcCM = cr.getColorModel();
+        ColorSpace cs    = srcCM.getColorSpace();
+
+        int bands = sm.getNumBands();
+
+        int bits;
+        int dt = sm.getDataType();
+        switch (dt) {
+        case DataBuffer.TYPE_BYTE:   bits=8;  break;
+        case DataBuffer.TYPE_SHORT:  bits=16; break;
+        case DataBuffer.TYPE_USHORT: bits=16; break;
+        case DataBuffer.TYPE_INT:    bits=32; break;
+        default:
+            throw new IllegalArgumentException
+                ("Unsupported DataBuffer type: " + dt);
+        }
+
+        boolean hasAlpha = srcCM.hasAlpha();
+        if (hasAlpha){
+            // if Src has Alpha then our out bands must
+            // either be one less than the source (no out alpha)
+            // or equal (still has alpha)
+            if (bands == srcCM.getNumComponents()-1)
+                hasAlpha = false;
+            else if (bands != srcCM.getNumComponents())
+                throw new IllegalArgumentException
+                    ("Incompatible number of bands in and out");
+        } else {
+            if (bands == srcCM.getNumComponents()+1)
+                hasAlpha = true;
+            else if (bands != srcCM.getNumComponents())
+                throw new IllegalArgumentException
+                    ("Incompatible number of bands in and out");
+        }
+
+        boolean preMult  = srcCM.isAlphaPremultiplied();
+        if (!hasAlpha)
+            preMult = false;
+
+        if (sm instanceof ComponentSampleModel) {
+            int [] bitsPer = new int[bands];
+            for (int i=0; i<bands; i++)
+                bitsPer[i] = bits;
+
+            return new ComponentColorModel
+                (cs, bitsPer, hasAlpha, preMult,
+                 hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE,
+                 dt);
+        } else if (sm instanceof SinglePixelPackedSampleModel) {
+            SinglePixelPackedSampleModel sppsm;
+            sppsm = (SinglePixelPackedSampleModel)sm;
+            int[] masks  = sppsm.getBitMasks();
+            if (bands == 4)
+                return new DirectColorModel
+                    (cs, bits, masks[0], masks[1], masks[2], masks[3],
+                     preMult, dt);
+            else if (bands == 3)
+                return new DirectColorModel
+                    (cs, bits, masks[0], masks[1], masks[2], 0x0,
+                     preMult, dt);
+            else
+                throw new IllegalArgumentException
+                    ("Incompatible number of bands out for ColorModel");
+        }
+        throw new IllegalArgumentException
+            ("Unsupported SampleModel Type");
+    }
+}

Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/FormatRed.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/GaussianBlurRed8Bit.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/GaussianBlurRed8Bit.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/GaussianBlurRed8Bit.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/GaussianBlurRed8Bit.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,578 @@
+/*
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.image.rendered;
+
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.color.ColorSpace;
+import java.awt.image.ColorModel;
+import java.awt.image.ConvolveOp;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferInt;
+import java.awt.image.DirectColorModel;
+import java.awt.image.Kernel;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.WritableRaster;
+
+import org.apache.flex.forks.batik.ext.awt.image.GraphicsUtil;
+
+/**
+ * This implementation of RenderableImage will render its input
+ * GraphicsNode on demand for tiles.
+ *
+ * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
+ * @version $Id: GaussianBlurRed8Bit.java 478276 2006-11-22 18:33:37Z dvholten $
+ */
+public class GaussianBlurRed8Bit extends AbstractRed {
+
+    int xinset, yinset;
+    double stdDevX, stdDevY;
+    RenderingHints hints;
+    ConvolveOp [] convOp = new ConvolveOp [2];
+    int dX, dY;
+
+    /**
+     * Construct a blurred version of <tt>src</tt>, by blurring with a
+     * gaussian kernel with standard Deviation of <tt>stdDev</tt> pixels.
+     * @param src The source image to blur
+     * @param stdDev The Standard Deviation of the Gaussian kernel.
+     * @param rh     Rendering hints.
+     */
+    public GaussianBlurRed8Bit(CachableRed    src,
+                               double         stdDev,
+                               RenderingHints rh) {
+        this(src, stdDev, stdDev, rh);
+    }
+
+    /**
+     * Construct a blurred version of <tt>src</tt>, by blurring with a
+     * gaussian kernel with standard Deviation of <tt>stdDev</tt> pixels.
+     * @param src The source image to blur
+     * @param stdDevX The Standard Deviation of the Gaussian kernel in X
+     * @param stdDevY The Standard Deviation of the Gaussian kernel in Y
+     * @param rh     Rendering hints.
+     */
+    public GaussianBlurRed8Bit(CachableRed src,
+                               double stdDevX, double stdDevY,
+                               RenderingHints rh) {
+        super(); // Remember to call super.init()
+
+        this.stdDevX = stdDevX;
+        this.stdDevY = stdDevY;
+        this.hints   = rh;
+
+        xinset = surroundPixels(stdDevX, rh);
+        yinset = surroundPixels(stdDevY, rh);
+
+        Rectangle myBounds = src.getBounds();
+        myBounds.x      += xinset;
+        myBounds.y      += yinset;
+        myBounds.width  -= 2*xinset;
+        myBounds.height -= 2*yinset;
+        if ((myBounds.width <= 0) ||
+            (myBounds.height <= 0)) {
+            myBounds.width=0;
+            myBounds.height=0;
+        }
+
+        ColorModel cm  = fixColorModel(src);
+        SampleModel sm = src.getSampleModel();
+        int tw = sm.getWidth();
+        int th = sm.getHeight();
+        if (tw > myBounds.width)  tw = myBounds.width;
+        if (th > myBounds.height) th = myBounds.height;
+        sm = cm.createCompatibleSampleModel(tw, th);
+
+        init(src, myBounds, cm, sm,
+             src.getTileGridXOffset()+xinset,
+             src.getTileGridYOffset()+yinset, null);
+
+        boolean highQuality = ((hints != null) &&
+                               RenderingHints.VALUE_RENDER_QUALITY.equals
+                               (hints.get(RenderingHints.KEY_RENDERING)));
+
+        // System.out.println("StdDev: " + stdDevX + "x" + stdDevY);
+        if ((xinset != 0) && ((stdDevX < 2) || highQuality))
+            convOp[0] = new ConvolveOp(makeQualityKernelX(xinset*2+1));
+        else
+            dX = (int)Math.floor(DSQRT2PI*stdDevX+0.5f);
+
+        if ((yinset != 0) && ((stdDevY < 2) || highQuality))
+            convOp[1] = new ConvolveOp(makeQualityKernelY(yinset*2+1));
+        else
+            dY = (int)Math.floor(DSQRT2PI*stdDevY+0.5f);
+    }
+
+    /**
+     * Constant: sqrt(2*PI)
+     */
+    static final float SQRT2PI = (float)Math.sqrt(2*Math.PI);
+
+    /**
+     * Constant: 3*sqrt(2*PI)/4
+     */
+    static final float DSQRT2PI = SQRT2PI*3f/4f;
+
+    /**
+     * Constant: precision used in computation of the Kernel radius
+     */
+    static final float precision = 0.499f;
+
+    /**
+     * Calculate the number of surround pixels required for a given
+     * standard Deviation.
+     */
+    public static int surroundPixels(double stdDev) {
+        return surroundPixels(stdDev, null);
+    }
+
+    /**
+     * Calculate the number of surround pixels required for a given
+     * standard Deviation.  Also takes into account rendering quality
+     * hint.
+     */
+    public static int surroundPixels(double stdDev, RenderingHints hints) {
+        boolean highQuality = ((hints != null) &&
+                               RenderingHints.VALUE_RENDER_QUALITY.equals
+                               (hints.get(RenderingHints.KEY_RENDERING)));
+
+        if ((stdDev < 2) || highQuality) {
+            // Start with 1/2 the zero box enery.
+            float areaSum = (float)(0.5/(stdDev*SQRT2PI));
+            int i=0;
+            while (areaSum < precision) {
+                areaSum += (float)(Math.pow(Math.E, -i*i/(2*stdDev*stdDev)) /
+                                   (stdDev*SQRT2PI));
+                i++;
+            }
+
+            return i;
+        }
+
+        //compute d
+        int diam = (int)Math.floor(DSQRT2PI*stdDev+0.5f);
+        if (diam%2 == 0)
+            return diam-1 + diam/2; // even case
+        else
+            return diam-2 + diam/2;   // Odd case
+    }
+
+    /*
+     * Here we compute the data for the one-dimensional kernel of
+     * length '2*(radius-1) + 1'
+     *
+     * @param radius stdDeviationX or stdDeviationY.
+     * @see #makeQualityKernels */
+    private float [] computeQualityKernelData(int len, double stdDev){
+        final float[] kernelData = new float [len];
+
+        int mid = len/2;
+        float sum = 0; // Used to normalise the kernel
+        for(int i=0; i<len; i++){
+            kernelData[i] = (float)(Math.pow(Math.E, -(i-mid)*(i-mid)/
+                                             (2*stdDev*stdDev)) /
+                                    (SQRT2PI*stdDev));
+            sum += kernelData[i];
+        }
+
+        // Normalise: make elements sum to 1
+        for (int i=0; i<len; i++)
+            kernelData[i] /= sum;
+
+        return kernelData;
+    }
+
+    private Kernel makeQualityKernelX(int len) {
+        return new Kernel(len, 1, computeQualityKernelData(len, stdDevX));
+    }
+
+    private Kernel makeQualityKernelY(int len) {
+        return new Kernel(1, len, computeQualityKernelData(len, stdDevY));
+    }
+
+    public WritableRaster copyData(WritableRaster wr) {
+        // Get my source.
+        CachableRed src = (CachableRed)getSources().get(0);
+
+        Rectangle r = wr.getBounds();
+        r.x      -=   xinset;
+        r.y      -=   yinset;
+        r.width  += 2*xinset;
+        r.height += 2*yinset;
+
+        // System.out.println("Gaussian GenR: " + wr);
+        // System.out.println("SrcReq: " + r);
+
+        ColorModel srcCM = src.getColorModel();
+
+        WritableRaster tmpR1=null, tmpR2=null;
+
+        tmpR1 = srcCM.createCompatibleWritableRaster(r.width, r.height);
+        {
+            WritableRaster fill;
+            fill = tmpR1.createWritableTranslatedChild(r.x, r.y);
+            src.copyData(fill);
+        }
+        if (srcCM.hasAlpha() && !srcCM.isAlphaPremultiplied())
+            GraphicsUtil.coerceData(tmpR1, srcCM, true);
+
+        // For the blur box approx we can use dest as our intermediate
+        // otherwise we let it default to null which means we create a new
+        // one...
+
+        // this lets the Vertical conv know how much is junk, so it
+        // doesn't bother to convolve the top and bottom edges
+        int skipX;
+        // long t1 = System.currentTimeMillis();
+        if (xinset == 0) {
+            skipX = 0;
+        } else if (convOp[0] != null) {
+            tmpR2 = getColorModel().createCompatibleWritableRaster
+                (r.width, r.height);
+            tmpR2 = convOp[0].filter(tmpR1, tmpR2);
+            skipX = convOp[0].getKernel().getXOrigin();
+
+            // Swap them...
+            WritableRaster tmp = tmpR1;
+            tmpR1 = tmpR2;
+            tmpR2 = tmp;
+        } else {
+            if ((dX&0x01) == 0){
+                tmpR1 = boxFilterH(tmpR1, tmpR1, 0,    0,   dX,   dX/2);
+                tmpR1 = boxFilterH(tmpR1, tmpR1, dX/2, 0,   dX,   dX/2-1);
+                tmpR1 = boxFilterH(tmpR1, tmpR1, dX-1, 0,   dX+1, dX/2);
+                skipX = dX-1 + dX/2;
+            } else {
+                tmpR1 = boxFilterH(tmpR1, tmpR1, 0,    0,   dX, dX/2);
+                tmpR1 = boxFilterH(tmpR1, tmpR1, dX/2, 0,   dX, dX/2);
+                tmpR1 = boxFilterH(tmpR1, tmpR1, dX-2, 0,   dX, dX/2);
+                skipX = dX-2 + dX/2;
+            }
+        }
+
+        if (yinset == 0) {
+            tmpR2 = tmpR1;
+        } else if (convOp[1] != null) {
+            if (tmpR2 == null) {
+                tmpR2 = getColorModel().createCompatibleWritableRaster
+                    (r.width, r.height);
+            }
+            tmpR2 = convOp[1].filter(tmpR1, tmpR2);
+        } else {
+            if ((dY&0x01) == 0){
+                tmpR1 = boxFilterV(tmpR1, tmpR1, skipX, 0,    dY,   dY/2);
+                tmpR1 = boxFilterV(tmpR1, tmpR1, skipX, dY/2, dY,   dY/2-1);
+                tmpR1 = boxFilterV(tmpR1, tmpR1, skipX, dY-1, dY+1, dY/2);
+            }
+            else {
+                tmpR1 = boxFilterV(tmpR1, tmpR1, skipX, 0,    dY, dY/2);
+                tmpR1 = boxFilterV(tmpR1, tmpR1, skipX, dY/2, dY, dY/2);
+                tmpR1 = boxFilterV(tmpR1, tmpR1, skipX, dY-2, dY, dY/2);
+            }
+            tmpR2 = tmpR1;
+        }
+        // long t2 = System.currentTimeMillis();
+        // System.out.println("Time: " + (t2-t1) +
+        //                       (((convOp[0] != null) || (convOp[1] != null))?
+        //                        " ConvOp":""));
+        // System.out.println("Rasters  WR :" + wr.getBounds());
+        // System.out.println("         tmp:" + tmpR2.getBounds());
+        // System.out.println("      bounds:" + getBounds());
+        // System.out.println("       skipX:" + skipX +
+        //                    " dx:" + dX + " Dy: " + dY);
+        tmpR2 = tmpR2.createWritableTranslatedChild(r.x, r.y);
+        GraphicsUtil.copyData(tmpR2, wr);
+
+        return wr;
+    }
+
+    private WritableRaster boxFilterH(Raster src, WritableRaster dest,
+                                      int skipX, int skipY,
+                                      int boxSz, int loc) {
+
+        final int w = src.getWidth();
+        final int h = src.getHeight();
+
+          // Check if the raster is wide enough to do _any_ work
+        if (w < (2*skipX)+boxSz) return dest;
+        if (h < (2*skipY))       return dest;
+
+        final SinglePixelPackedSampleModel srcSPPSM =
+            (SinglePixelPackedSampleModel)src.getSampleModel();
+
+        final SinglePixelPackedSampleModel dstSPPSM =
+            (SinglePixelPackedSampleModel)dest.getSampleModel();
+
+        // Stride is the distance between two consecutive column elements,
+        // in the one-dimention dataBuffer
+        final int srcScanStride = srcSPPSM.getScanlineStride();
+        final int dstScanStride = dstSPPSM.getScanlineStride();
+
+        // Access the integer buffer for each image.
+        DataBufferInt srcDB = (DataBufferInt)src.getDataBuffer();
+        DataBufferInt dstDB = (DataBufferInt)dest.getDataBuffer();
+
+        // Offset defines where in the stack the real data begin
+        final int srcOff
+            = (srcDB.getOffset() +
+               srcSPPSM.getOffset
+               (src.getMinX()-src.getSampleModelTranslateX(),
+                src.getMinY()-src.getSampleModelTranslateY()));
+        final int dstOff
+            = (dstDB.getOffset() +
+               dstSPPSM.getOffset
+               (dest.getMinX()-dest.getSampleModelTranslateX(),
+                dest.getMinY()-dest.getSampleModelTranslateY()));
+
+        // Access the pixel value array
+        final int[] srcPixels  = srcDB.getBankData()[0];
+        final int[] destPixels = dstDB.getBankData()[0];
+
+        final int [] buffer = new int [boxSz];
+        int curr, prev;
+
+          // Fixed point normalization factor (8.24)
+        int scale = (1<<24)/boxSz;
+
+        /*
+         * System.out.println("Info: srcOff: " + srcOff +
+         *                    " x: " + skipX +
+         *                    " y: " + skipY +
+         *                    " w: " + w +
+         *                    " h: " + h +
+         *                    " boxSz " + boxSz +
+         *                    " srcStride: " + srcScanStride);
+         */
+
+        for (int y=skipY; y<(h-skipY); y++) {
+            int sp     = srcOff + y*srcScanStride;
+            int dp     = dstOff + y*dstScanStride;
+            int rowEnd = sp + (w-skipX);
+
+            int k    = 0;
+            int sumA = 0;
+            int sumR = 0;
+            int sumG = 0;
+            int sumB = 0;
+
+            sp += skipX;
+            int end  = sp+boxSz;
+
+            while (sp < end) {
+                curr = buffer[k] = srcPixels[sp];
+                sumA += (curr>>> 24);
+                sumR += (curr >> 16)&0xFF;
+                sumG += (curr >>  8)&0xFF;
+                sumB += (curr      )&0xFF;
+                k++;
+                sp++;
+            }
+
+            dp += skipX + loc;
+            prev = destPixels[dp] = (( (sumA*scale)&0xFF000000)       |
+                                     (((sumR*scale)&0xFF000000)>>>8)  |
+                                     (((sumG*scale)&0xFF000000)>>>16) |
+                                     (((sumB*scale)&0xFF000000)>>>24));
+            dp++;
+            k=0;
+            while (sp < rowEnd) {
+                curr = buffer[k];
+                if (curr == srcPixels[sp]) {
+                    destPixels[dp] = prev;
+                } else {
+                    sumA -= (curr>>> 24);
+                    sumR -= (curr >> 16)&0xFF;
+                    sumG -= (curr >>  8)&0xFF;
+                    sumB -= (curr      )&0xFF;
+
+                    curr = buffer[k] = srcPixels[sp];
+
+                    sumA += (curr>>> 24);
+                    sumR += (curr >> 16)&0xFF;
+                    sumG += (curr >>  8)&0xFF;
+                    sumB += (curr      )&0xFF;
+                    prev = destPixels[dp] = (( (sumA*scale)&0xFF000000)       |
+                                             (((sumR*scale)&0xFF000000)>>>8)  |
+                                             (((sumG*scale)&0xFF000000)>>>16) |
+                                             (((sumB*scale)&0xFF000000)>>>24));
+                }
+                k = (k+1)%boxSz;
+                sp++;
+                dp++;
+            }
+        }
+        return dest;
+    }
+
+    private WritableRaster boxFilterV(Raster src, WritableRaster dest,
+                                      int skipX, int skipY,
+                                      int boxSz, int loc) {
+
+        final int w = src.getWidth();
+        final int h = src.getHeight();
+
+          // Check if the raster is wide enough to do _any_ work
+        if (w < (2*skipX))       return dest;
+        if (h < (2*skipY)+boxSz) return dest;
+
+        final SinglePixelPackedSampleModel srcSPPSM =
+            (SinglePixelPackedSampleModel)src.getSampleModel();
+
+        final SinglePixelPackedSampleModel dstSPPSM =
+            (SinglePixelPackedSampleModel)dest.getSampleModel();
+
+        // Stride is the distance between two consecutive column elements,
+        // in the one-dimention dataBuffer
+        final int srcScanStride = srcSPPSM.getScanlineStride();
+        final int dstScanStride = dstSPPSM.getScanlineStride();
+
+        // Access the integer buffer for each image.
+        DataBufferInt srcDB = (DataBufferInt)src.getDataBuffer();
+        DataBufferInt dstDB = (DataBufferInt)dest.getDataBuffer();
+
+        // Offset defines where in the stack the real data begin
+        final int srcOff
+            = (srcDB.getOffset() +
+               srcSPPSM.getOffset
+               (src.getMinX()-src.getSampleModelTranslateX(),
+                src.getMinY()-src.getSampleModelTranslateY()));
+        final int dstOff
+            = (dstDB.getOffset() +
+               dstSPPSM.getOffset
+               (dest.getMinX()-dest.getSampleModelTranslateX(),
+                dest.getMinY()-dest.getSampleModelTranslateY()));
+
+
+        // Access the pixel value array
+        final int[] srcPixels  = srcDB.getBankData()[0];
+        final int[] destPixels = dstDB.getBankData()[0];
+
+        final int [] buffer = new int [boxSz];
+        int curr, prev;
+
+          // Fixed point normalization factor (8.24)
+        final int scale = (1<<24)/boxSz;
+
+        /*
+         * System.out.println("Info: srcOff: " + srcOff +
+         *                    " x: " + skipX +
+         *                    " y: " + skipY +
+         *                    " w: " + w +
+         *                    " h: " + h +
+         *                    " boxSz " + boxSz +
+         *                    " srcStride: " + srcScanStride);
+         */
+
+        for (int x=skipX; x<(w-skipX); x++) {
+            int sp = srcOff + x;
+            int dp = dstOff + x;
+            int colEnd = sp + (h-skipY)*srcScanStride;
+
+            int k=0;
+            int sumA = 0;
+            int sumR = 0;
+            int sumG = 0;
+            int sumB = 0;
+
+            sp += skipY*srcScanStride;
+            int end  = sp+(boxSz*srcScanStride);
+
+            while (sp < end) {
+                curr = buffer[k] = srcPixels[sp];
+                sumA += (curr>>> 24);
+                sumR += (curr >> 16)&0xFF;
+                sumG += (curr >>  8)&0xFF;
+                sumB += (curr      )&0xFF;
+                k++;
+                sp+=srcScanStride;
+            }
+
+
+            dp += (skipY + loc)*dstScanStride;
+            prev = destPixels[dp] = (( (sumA*scale)&0xFF000000)       |
+                                     (((sumR*scale)&0xFF000000)>>>8)  |
+                                     (((sumG*scale)&0xFF000000)>>>16) |
+                                     (((sumB*scale)&0xFF000000)>>>24));
+            dp+=dstScanStride;
+            k=0;
+            while (sp < colEnd) {
+                curr = buffer[k];
+                if (curr == srcPixels[sp]) {
+                    destPixels[dp] = prev;
+                } else {
+                    sumA -= (curr>>> 24);
+                    sumR -= (curr >> 16)&0xFF;
+                    sumG -= (curr >>  8)&0xFF;
+                    sumB -= (curr      )&0xFF;
+
+                    curr = buffer[k] = srcPixels[sp];
+
+                    sumA += (curr>>> 24);
+                    sumR += (curr >> 16)&0xFF;
+                    sumG += (curr >>  8)&0xFF;
+                    sumB += (curr      )&0xFF;
+                    prev = destPixels[dp] = (( (sumA*scale)&0xFF000000)       |
+                                             (((sumR*scale)&0xFF000000)>>>8)  |
+                                             (((sumG*scale)&0xFF000000)>>>16) |
+                                             (((sumB*scale)&0xFF000000)>>>24));
+                }
+                k = (k+1)%boxSz;
+                sp+=srcScanStride;
+                dp+=dstScanStride;
+            }
+        }
+        return dest;
+    }
+
+    protected static ColorModel fixColorModel(CachableRed src) {
+        ColorModel  cm = src.getColorModel();
+
+        int b = src.getSampleModel().getNumBands();
+        int [] masks = new int[4];
+        switch (b) {
+        case 1:
+            masks[0] = 0xFF;
+            break;
+        case 2:
+            masks[0] = 0x00FF;
+            masks[3] = 0xFF00;
+            break;
+        case 3:
+            masks[0] = 0xFF0000;
+            masks[1] = 0x00FF00;
+            masks[2] = 0x0000FF;
+            break;
+        case 4:
+            masks[0] = 0x00FF0000;
+            masks[1] = 0x0000FF00;
+            masks[2] = 0x000000FF;
+            masks[3] = 0xFF000000;
+            break;
+        default:
+            throw new IllegalArgumentException
+                ("GaussianBlurRed8Bit only supports one to four band images");
+        }
+        ColorSpace cs = cm.getColorSpace();
+        return new DirectColorModel(cs, 8*b, masks[0], masks[1],
+                                    masks[2], masks[3],
+                                    true, DataBuffer.TYPE_INT);
+    }
+}

Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/GaussianBlurRed8Bit.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/IndexImage.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/IndexImage.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/IndexImage.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/IndexImage.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,800 @@
+/*
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.image.rendered;
+
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.IndexColorModel;
+import java.awt.image.MultiPixelPackedSampleModel;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.flex.forks.batik.ext.awt.image.GraphicsUtil;
+
+/**
+ * This class implements an adaptive palette generator to reduce images to a
+ * specified number of colors.
+ *
+ * Ideally this would also support a better dither option than just 
+ * the JDK's pattern dither.
+ *
+ * The algorithm used is the 'Median Cut Algorithm' published by
+ * Paul Heckbert in early '80s.
+ *
+ * @author <a href="mailto:deweese@apache.org">Thomas DeWeese</a>
+ * @author <a href="mailto:jun@oop-reserch.com">Jun Inamori</a>
+ * @version $Id: IndexImage.java 489226 2006-12-21 00:05:36Z cam $ 
+ */
+
+public class IndexImage{
+
+    /**
+     * Used to track a color and the number of pixels of that colors
+     */
+    private static class Counter {
+
+        /**
+         * contains the 'packed' rgb-color for this point.
+         * Must not change after construction!
+         */
+        final int val;
+
+        /**
+         * the number of image-pixels with this color.
+         */
+        int count=1;
+
+        Counter(int val) {  this.val = val; }
+
+        boolean add(int val) {
+            // See if the value matches us...
+            if (this.val != val)
+                return false;
+            count++;
+            return true;
+        }
+
+        /**
+         * convert the color-point of this counter to an rgb-array.
+         * To avoid creating lots of arrays, the caller passes the
+         * array to store the result.
+         *
+         * @param rgb an int[ 3 ] to store the result.
+         * @return an int-array with rgb-color-values (same as rgb-parameter)
+         */
+        int[] getRgb( int[] rgb ){
+            rgb[ Cube.RED ] = (val&0xFF0000)>>16;
+            rgb[ Cube.GRN ] = (val&0x00FF00)>>8;
+            rgb[ Cube.BLU ] = (val&0x0000FF);
+            return rgb;
+        }
+   }
+
+    /**
+     * Used to define a cube of the colorspace.  The cube can be split
+     * approximagely in half to generate two cubes.
+     */
+    private static class Cube {
+        static final byte[] RGB_BLACK= new byte[]{ 0, 0, 0 };
+
+        int[] min = {0, 0, 0}, max={255,255,255};
+
+        boolean done = false;
+        
+
+        /**
+         * the colors-array is not modified - in fact, all cubes use
+         * the same colors-array.  The Counter contains the
+         * rgb-color-code and the count of pixels with this color.
+         */
+        final Counter[][] colors;
+
+        /**
+         * the number of color-points in this cube.
+         */
+        int count=0;
+
+        static final int RED = 0;
+        static final int GRN = 1;
+        static final int BLU = 2;
+
+        /**
+         * Define a new cube.
+         * @param colors contains the 3D color histogram to be subdivided
+         * @param count the total number of pixels in the 3D histogram.
+         */
+        Cube( Counter[][] colors, int count) {
+            this.colors = colors;
+            this.count = count;
+        }
+
+        /**
+         * If this returns true then the cube can not be subdivided any
+         * further
+         */
+        public boolean isDone() { return done; }
+
+        /**
+         * check, if the color defined by val[] is inside this cube.
+         *
+         * @param val int[ 3 ] containing r,g,b-values
+         * @return true when color is inside this cube
+         */
+        private boolean contains( int[] val ){
+
+            int vRed = val[ RED ]; // just save some array-accesses
+            int vGrn = val[ GRN ];
+            int vBlu = val[ BLU ];
+
+            return (
+                ( ( min[ RED ] <= vRed ) && ( vRed <= max[ RED ]))&&
+                ( ( min[ GRN ] <= vGrn ) && ( vGrn <= max[ GRN ]))&&
+                ( ( min[ BLU ] <= vBlu ) && ( vBlu <= max[ BLU ])));
+        }
+
+        /**
+         * Splits the cube into two parts.  This cube is
+         * changed to be one half and the returned cube is the other half.
+         * This tries to pick the right channel to split on.
+         */
+        Cube split() {
+            int dr = max[ RED ]-min[ RED ]+1;
+            int dg = max[ GRN ]-min[ GRN ]+1;
+            int db = max[ BLU ]-min[ BLU ]+1;
+            int c0, c1, splitChannel;
+
+            // Figure out which axis is the longest and split along
+            // that axis (this tries to keep cubes square-ish).
+            if (dr >= dg) {
+                if (dr >= db) { splitChannel = RED; c0=GRN; c1=BLU; }
+                else          { splitChannel = BLU; c0=RED; c1=GRN; }
+            } else if (dg >= db) {
+                splitChannel = GRN;
+                c0=RED;
+                c1=BLU;
+            } else {
+                splitChannel = BLU;
+                c0=GRN;
+                c1=RED;
+            }
+
+//            System.out.println("Red:" + dr
+//                    + " Grn:" + dg
+//                    + " Blu:" + db
+//                    + " Split:" + splitChannel
+//                    + " c0:" + c0
+//                    + " c1:" + c1 );
+
+            Cube ret;
+
+            // try to split the longest axis
+            ret = splitChannel(splitChannel, c0, c1);
+            if (ret != null ) return ret;
+
+            // try to split along the 2nd longest axis
+            ret = splitChannel(c0, splitChannel, c1);
+            if (ret != null ) return ret;
+
+            // only one left
+            ret = splitChannel(c1, splitChannel, c0);
+            if (ret != null) return ret;
+
+            // so far, no split was possible trying all 3 colors: this
+            // cube can't be split further
+            done = true;
+            return null;
+        }
+
+        /**
+         * Adjust (normalize) min/max of this cube so that they span
+         * the actual content.  This method is called on the two cubes
+         * resulting from a split.  <br> We search the counts[] from
+         * min to max for the leftmost non-null entry.  That is the
+         * new min.  Then we search counts[] from max to min for the
+         * rightmost non-null entry.  That is the new max.  <br>This
+         * requires, that {@link #computeCounts } really computes
+         * <i>all</i> counts-values (and does not stop after the
+         * necessary number of points for a split is found, as it was
+         * done in the previous version of this class).
+         *
+         * @param splitChannel the color used for the last split
+         * @param counts contains the number of points along the splitChannel
+         *        - only counts[ min .. max ] is valid.
+         */
+        private void normalize( int splitChannel, int[] counts ){
+
+            if ( count == 0 ){
+                // empty cube: nothing to normalize
+                return;
+            }
+
+            int iMin = min[ splitChannel ];
+            int iMax = max[ splitChannel ];
+            int loBound = -1;
+            int hiBound = -1;
+
+            // we search from left to right for the first non-null
+            // entry in counts[]
+            for( int i = iMin; i <= iMax; i++ ){
+                if ( counts[ i ] == 0 ){
+                    // this entry is 0: search more
+                    continue;
+                }
+
+                // we reached a non-null entry: stop looking further
+                loBound = i;
+                break;
+            }
+
+            // we search from right to left for the first non-null
+            // entry in counts[]
+            for( int i= iMax; i >= iMin; i-- ){
+                if ( counts[ i ] == 0 ){
+                    // this entry is 0: search more
+                    continue;
+                }
+                // we reached a non-null entry: stop looking further
+                hiBound = i;
+                break;
+            }
+
+            boolean flagChangedLo = (loBound != -1 ) && ( iMin != loBound );
+            boolean flagChangedHi = (hiBound != -1 ) && ( iMax != hiBound );
+//            if ( flagChangedLo || flagChangedHi ){
+//                System.out.println("old min:" + min[ splitChannel ] + "/max:" + max[ splitChannel ]
+//                + " new: " + loBound + "/" + hiBound );
+//                StringBuffer buff = new StringBuffer( 100 );
+//                for( int i= min[ splitChannel ]; i <= max[ splitChannel]; i++ ){
+//                    buff.append( counts[ i ] );
+//                    buff.append( ',' );
+//                }
+//                System.out.println("Counts:" + buff );
+//            }
+
+            if ( flagChangedLo ){
+                min[ splitChannel ]= loBound;
+            }
+            if ( flagChangedHi ){
+                max[ splitChannel ]= hiBound;
+            }
+        }
+
+
+        /**
+         * Splits the image according to the parameters.  It tries
+         * to find a location where half the pixels are on one side
+         * and half the pixels are on the other.
+         */
+        Cube splitChannel(int splitChannel, int c0, int c1) {
+
+            if (min[splitChannel] == max[splitChannel]) {
+                // thickness along the splitChannel is only one point: cannot split
+                return null;
+            }
+
+            if ( count == 0 ){
+                // this Cube has no points: cannot split
+                return null;
+            }
+
+            // System.out.println( toString() );
+
+            int half = count/2;
+            // Each entry is the number of pixels that have that value
+            // in the split channel within the cube (so pixels
+            // that have that value in the split channel aren't counted
+            // if they are outside the cube in the other color channels.
+            int[] counts = computeCounts( splitChannel, c0, c1 );
+
+            int tcount=0;
+            int lastAdd=-1;
+            // These indicate what the top value for the low cube and
+            // the low value of the high cube should be in the split channel
+            // (they may not be one off if there are 'dead' spots in the
+            // counts array.
+            int splitLo=min[splitChannel];
+            int splitHi=max[splitChannel];
+            for (int i=min[splitChannel]; i<=max[splitChannel]; i++) {
+                int c = counts[i];
+                if (c == 0) {
+                    // No counts below this so move up bottom of cube.
+                    if ((tcount == 0) && (i < max[splitChannel]))
+                        min[splitChannel] = i+1;
+                    continue;
+                }
+
+                if (tcount+c < half) {
+                    lastAdd = i;
+                    tcount+=c;
+                    continue;
+                }
+                if ((half-tcount) <= ((tcount+c)-half)) {
+                    // Then lastAdd is a better top idx for this then i.
+                    if (lastAdd == -1) {
+                        // No lower place to break.
+                        if (c == count) {
+                            // All pixels are at this value so make min/max
+                            // reflect that.
+                            max[splitChannel] = i;
+                            return null; // no split to make.
+                        } else {
+                            // There are values about this one so
+                            // split above.
+                            splitLo = i;
+                            splitHi = i+1;
+                            tcount += c;    // fix 35683
+                            break;
+                        }
+                    }
+                    splitLo = lastAdd;
+                    splitHi = i;
+                } else {
+                    if (i == max[splitChannel]) {
+                        if ( c == count) {
+                            // would move min up but that should
+                            // have happened already.
+                            return null; // no split to make.
+                        } else {
+                            // Would like to break between i and i+1
+                            // but no i+1 so use lastAdd and i;
+                            splitLo = lastAdd;
+                            splitHi = i;
+                            break;
+                        }
+                    }
+                    // Include c in counts
+                    tcount += c;
+                    splitLo = i;
+                    splitHi = i+1;
+                }
+                break;
+            }
+
+            // System.out.println("Split: " + splitChannel + "@"
+            //                    + splitLo + "-"+splitHi +
+            //                    " Count: " + tcount  + " of " + count +
+            //                    " LA: " + lastAdd);
+
+            // Create the new cube and update everyone's bounds & counts.
+            Cube ret = new Cube(colors, tcount);
+            count = count-tcount;
+            ret.min[splitChannel] = min[splitChannel];
+            ret.max[splitChannel] = splitLo;
+            min[splitChannel] = splitHi;
+
+            // the cube was split along splitChannel, the other
+            // dimensions dont change
+            ret.min[c0] = min[c0];
+            ret.max[c0] = max[c0];
+            ret.min[c1] = min[c1];
+            ret.max[c1] = max[c1];
+
+//            if ( count <= 0 ){
+//                System.out.println("This cube has no points after split:" + toString() );
+//            }
+//            if ( ret.count <= 0 ){
+//                System.out.println("That cube has no points after split:" + ret.toString() + "    this:" + toString() );
+//                System.out.println("SplitLo:"  + splitLo + "  SplitHi:" + splitHi );
+//            }
+
+            // after a split we 'normalize' both cubes, so that their
+            // min/max reflect the actual bounds of the cube.  comment
+            // the next two lines when you want to see the impact of
+            // using non-normalized cubes
+            normalize( splitChannel, counts );
+            ret.normalize( splitChannel, counts );
+
+            return ret;
+        }
+
+        /**
+         * create an array, which contains the number of pixels for
+         * each point along the splitChannel (between min and max of
+         * this cube).
+         *
+         * @param splitChannel one of RED | GRN | BLU
+         * @param c0 one of the other channels
+         * @param c1 the third channel
+         * @return an int[ 255 ] where only int[ min .. max ] contain
+         *         valid counts.
+         */
+        private int[] computeCounts( int splitChannel, int c0, int c1) {
+
+            int splitSh4 = (2-splitChannel)*4;
+            int c0Sh4    = (2-c0)*4;
+            int c1Sh4    = (2-c1)*4;
+
+            // after split, each half should have half of the cube's points
+            int half = count/2;
+
+            // Each entry is the number of pixels that have that value
+            // in the split channel within the cube (so pixels
+            // that have that value in the split channel aren't counted
+            // if they are outside the cube in the other color channels.
+            int[] counts = new int[256];
+            int tcount = 0;
+
+            int minR=min[0], minG=min[1], minB=min[2];
+            int maxR=max[0], maxG=max[1], maxB=max[2];
+
+            int[] minIdx = { minR >> 4, minG >> 4, minB >> 4 };
+            int[] maxIdx = { maxR >> 4, maxG >> 4, maxB >> 4 };
+
+            int [] vals = {0, 0, 0};
+            for (int i=minIdx[splitChannel]; i<=maxIdx[splitChannel]; i++) {
+                int idx1 = i<<splitSh4;
+                for (int j=minIdx[c0]; j <=maxIdx[c0]; j++) {
+                    int idx2 = idx1 | (j<<c0Sh4);
+                    for (int k=minIdx[c1]; k<=maxIdx[c1]; k++) {
+                        int idx = idx2 | (k<<c1Sh4);
+                        Counter[] v = colors[idx];
+                        for( int iColor = 0; iColor < v.length; iColor++ ){
+                            Counter c = v[ iColor ];
+                            vals = c.getRgb( vals );
+                            if ( contains( vals )){
+                                // The vals[] lies completly within
+                                // this cube so count it.
+                                counts[ vals[splitChannel] ] += c.count;
+                                tcount += c.count;
+                            }
+                        }
+                    }
+                }
+                // the next statement-line stops the loop after we
+                // found the split-point.  however, we continue to
+                // fill the counts[] because that is needed for
+                // normalization
+//                // We've found the half way point.  Note that the
+//                // rest of counts is not filled out.
+//                if (( tcount > 0 ) && (tcount >= half)) break;  // fix 35683
+            }
+
+            // the result so far is the filled counts[]
+            return counts;
+        }
+
+
+        /**
+         * convert the cube-content to String-representation for logging.
+         * @return the min/max-boundarys of the rgb-channels and
+         *         pixel-count of this Cube.
+         */
+        public String toString() {
+            return "Cube: [" +
+                    min[ RED ] + '-' + max[ RED ] + "] [" +
+                    min[ GRN ] + '-' + max[ GRN ] + "] [" +
+                    min[ BLU ] + '-' + max[ BLU ] + "] n:" + count;
+        }
+
+
+        /**
+         * Returns the average color for this cube (no alpha).
+         */
+        public int averageColor() {
+            if (count == 0) {
+                // cube is empty: return black
+                return 0;
+            }
+
+            byte[] rgb = averageColorRGB( null );
+
+            return (( rgb[ RED ] << 16 ) & 0x00FF0000)
+                 | (( rgb[ GRN ] <<  8 ) & 0x0000FF00)
+                 | (( rgb[ BLU ]       ) & 0x000000FF);
+        }
+
+        /**
+         * Returns the average color for this cube
+         */
+        public byte[] averageColorRGB( byte[] rgb ) {
+
+            if (count == 0) return RGB_BLACK;
+
+            float red=0, grn=0, blu=0;
+
+            // the boundarys of this cube
+            int minR=min[0], minG=min[1], minB=min[2];
+            int maxR=max[0], maxG=max[1], maxB=max[2];
+            int [] minIdx = {minR>>4, minG>>4, minB>>4};
+            int [] maxIdx = {maxR>>4, maxG>>4, maxB>>4};
+            int[] vals = new int[3];
+
+            for (int i=minIdx[0]; i<=maxIdx[0]; i++) {
+                int idx1 = i<<8;
+                for (int j=minIdx[1]; j<=maxIdx[1]; j++) {
+                    int idx2 = idx1 | (j<<4);
+                    for (int k=minIdx[2]; k<=maxIdx[2]; k++) {
+                        int idx = idx2 | k;
+                        Counter[] v = colors[idx];
+                        for( int iColor = 0; iColor < v.length; iColor++ ){
+                            Counter c = v[ iColor ];
+                            vals = c.getRgb( vals );
+                            if ( contains( vals ) ) {
+                                float weight = (c.count/(float)count);
+                                red += (vals[0]*weight);
+                                grn += (vals[1]*weight);
+                                blu += (vals[2]*weight);
+                            }
+                        }
+                    }
+                }
+            }
+            byte[] result = (rgb == null) ? new byte[3] : rgb;
+            result[ RED ] = (byte)(red + 0.5f);
+            result[ GRN ] = (byte)(grn + 0.5f);
+            result[ BLU ] = (byte)(blu + 0.5f);
+
+            return result;
+        }
+
+    }
+
+    /**
+     * create an array of rgb-colors from the cubes-array.
+     * The color of each cube is computed as the sum of all colors in the cube,
+     * where each pixel is weighted according to it's count.
+     *
+     * @param nCubes number of entries to use in cubes
+     * @param cubes contains the Cubes resulting from running the split-algorithm.
+     * @return a byte[][] which is arranged as [ r|g|b ][ 0..nCubes-1 ]
+     */
+    static byte[][] computeRGB( int nCubes, Cube[] cubes ){
+
+        byte[] r = new byte[nCubes];
+        byte[] g = new byte[nCubes];
+        byte[] b = new byte[nCubes];
+
+        byte[] rgb = new byte[3];
+        for (int i=0; i<nCubes; i++) {
+            rgb = cubes[i].averageColorRGB( rgb );
+            r[i] = rgb[ Cube.RED ];
+            g[i] = rgb[ Cube.GRN ];
+            b[i] = rgb[ Cube.BLU ];
+        }
+
+        byte[][] result = new byte[3][];
+        result[ Cube.RED ] = r;
+        result[ Cube.GRN ] = g;
+        result[ Cube.BLU ] = b;
+
+//        logRGB( r, g, b );
+
+        return result;
+    }
+
+    /**
+     * helper-method to print the complete rgb-arrays.
+     * @param r
+     * @param g
+     * @param b
+     */
+    static void logRGB( byte[] r, byte[] g, byte[] b ){
+
+        StringBuffer buff = new StringBuffer( 100 );
+        int nColors = r.length;
+        for( int i= 0; i < nColors; i++ ) {
+            String rgbStr= "(" + (r[i]+128) + ',' + (g[i] +128 ) + ',' + (b[i] + 128) + ")," ;
+            buff.append( rgbStr );
+        }
+        System.out.println("RGB:" + nColors + buff );
+    }
+
+
+    /**
+     * step 1: fill a data-structure with the count of each color in the image.
+     * @param bi input-image
+     * @return a List[] where each slot is a List of Counters (or null)
+     */
+    static List[] createColorList( BufferedImage bi ){
+
+        int w= bi.getWidth();
+        int h= bi.getHeight();
+
+        // Using 4 bits from RG & B.
+        List[] colors = new ArrayList[1<<12];
+
+        for(int i_w=0; i_w<w; i_w++){
+            for(int i_h=0; i_h<h; i_h++){
+                int rgb=(bi.getRGB(i_w,i_h) & 0x00FFFFFF);  // mask away alpha
+                // Get index from high four bits of each component.
+                int idx = (((rgb&0xF00000)>>> 12) |
+                           ((rgb&0x00F000)>>>  8) |
+                           ((rgb&0x0000F0)>>>  4));
+
+                // Get the 'hash vector' for that key.
+                List v = colors[idx];
+                if (v == null) {
+                    // No colors in this bin yet so create list and
+                    // add color.
+                    v = new ArrayList();
+                    v.add(new Counter(rgb));
+                    colors[idx] = v;
+                } else {
+                    // find our color in the bin or create a counter for it.
+                    Iterator i = v.iterator();
+                    while (true) {
+                        if (i.hasNext()) {
+                            // try adding our color to each counter...
+                            if (((Counter)i.next()).add(rgb)) break;
+                        } else {
+                            v.add(new Counter(rgb));
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        return colors;
+    }
+
+
+    /**
+     * step 2: convert the result of step 1 to an Cube[][] which is
+     * more efficient in the following iterations. All slots in the
+     * result are filled with at least an empty array - thus we avoid
+     * tests for null.  <br>Note: the converted slots in colors are no
+     * longer needed and removed.
+     *
+     * @param colors the data-structure to convert. Note that it is
+     * empty after conversion!
+     * @return same data as in colors, but Lists are converted to arrays.
+     */
+    static Counter[][] convertColorList( List[] colors ){
+
+        // used to fill empty slots
+        final Counter[] EMPTY_COUNTER = new Counter[0];
+
+        Counter[][] colorTbl= new Counter[ 1<< 12 ][];
+        for( int i= 0; i < colors.length; i++ ){
+            List cl = colors[ i ];
+            if ( cl == null ){
+                colorTbl[ i ] = EMPTY_COUNTER;
+                continue;
+            }
+            int nSlots = cl.size();
+            colorTbl[i] = (Counter[])cl.toArray( new Counter[ nSlots ] );
+
+            // the colors[ i ] - data is no longer needed: discard
+            colors[ i ] = null;
+        }
+
+        return colorTbl;
+    }
+
+    /**
+     * Converts the input image (must be TYPE_INT_RGB or
+     * TYPE_INT_ARGB) to an indexed image.  Generating an adaptive
+     * palette with number of colors specified.
+     * @param bi the image to be processed.
+     * @param nColors number of colors in the palette
+     */
+    public static BufferedImage getIndexedImage( BufferedImage bi, int nColors) {
+        int w=bi.getWidth();
+        int h=bi.getHeight();
+
+        // Using 4 bits from RG & B.
+        List[] colors = createColorList( bi );
+
+        // now we have initialized the colors[] with lists of Counters.
+        // from now on, this data-structure is just read, not modified.
+        // convert it to Counter[][] for faster iteration
+        Counter[][] colorTbl = convertColorList( colors );
+
+        // this is no longer needed: discard
+        colors = null;
+
+        int nCubes=1;
+        int fCube=0;
+        Cube [] cubes = new Cube[nColors];
+        cubes[0] = new Cube(colorTbl, w*h);
+
+        while (nCubes < nColors) {
+            while (cubes[fCube].isDone()) {
+                fCube++;
+                if (fCube == nCubes) break;
+            }
+            if (fCube == nCubes) {
+                // System.out.println("fCube == nCubes" + fCube );
+                break;
+            }
+            Cube c = cubes[fCube];
+            Cube nc = c.split();
+            if (nc != null) {
+                // store the cube with less points towards the end of
+                // the array, so that fat cubes get more splits
+                if (nc.count > c.count) {
+                    // new cube has more points: swap
+                    Cube tmp = c; c= nc; nc = tmp;
+                }
+                int j = fCube;
+                int cnt = c.count;
+                for (int i=fCube+1; i<nCubes; i++) {
+                    if (cubes[i].count < cnt)
+                        break;
+                    cubes[j++] = cubes[i];
+                }
+                cubes[j++] = c;
+
+                cnt = nc.count;
+                while (j<nCubes) {
+                    if (cubes[j].count < cnt)
+                        break;
+                    j++;
+                }
+                for (int i=nCubes; i>j; i--)
+                    cubes[i] = cubes[i-1];
+                cubes[j++] = nc;
+                nCubes++;
+            }
+        }
+
+        // convert the remaining cubes to the colors they represent
+        byte[][] rgbTbl = computeRGB( nCubes, cubes );
+
+        // The JDK doesn't seem to dither the image correctly if I go
+        // below 8bits per pixel.  So I dither to an 8bit palette
+        // image that only has nCubes colors.  Then I copy the data to
+        // a lower bit depth image that I return.
+        IndexColorModel icm= new IndexColorModel( 8, nCubes, rgbTbl[0], rgbTbl[1], rgbTbl[2] );
+
+        BufferedImage indexed =new BufferedImage
+            (w, h, BufferedImage.TYPE_BYTE_INDEXED, icm);
+        Graphics2D g2d=indexed.createGraphics();
+        g2d.setRenderingHint
+            (RenderingHints.KEY_DITHERING,
+             RenderingHints.VALUE_DITHER_ENABLE);
+        g2d.drawImage(bi, 0, 0, null);
+        g2d.dispose();
+
+
+        int bits;
+        for (bits=1; bits <=8; bits++) {
+            if ((1<<bits) >= nCubes) break;
+        }
+//        System.out.println("Bits: " + bits + " Cubes: " + nCubes);
+
+        if (bits > 4) {
+            // 8 bit image we are done...
+            return indexed;
+        }
+
+        // Create our low bit depth image...
+        if (bits ==3) bits = 4;
+        ColorModel cm = new IndexColorModel(bits,nCubes, 
+                                            rgbTbl[0], rgbTbl[1], rgbTbl[2] );
+        SampleModel sm;
+        sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, w, h, bits);
+        WritableRaster ras = Raster.createWritableRaster( sm, new Point(0,0));
+
+        // Copy the data to the low bitdepth image.
+        bi = indexed;
+        indexed = new BufferedImage(cm, ras, bi.isAlphaPremultiplied(), null);
+        GraphicsUtil.copyData(bi, indexed);
+        return indexed;
+    }
+}

Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/IndexImage.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/LRUCache.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/LRUCache.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/LRUCache.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/LRUCache.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,161 @@
+/*
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.image.rendered;
+
+import org.apache.flex.forks.batik.util.DoublyLinkedList;
+
+/**
+ *
+ * @version $Id: LRUCache.java 498740 2007-01-22 18:35:57Z dvholten $
+ */
+public class LRUCache {
+
+    /**
+     * Interface for object participating in the LRU Cache.  These
+     * inform the object of key events in the status of the object in
+     * the LRU cache.
+     */
+        public interface LRUObj {
+        /**
+         * Called when the object first becomes active in the LRU cache.
+         * @param nde The LRU cache node associated with this object.
+         *            should be remembered so it can be returned by
+         *            <tt>lruGet</tt>.
+         */
+        void    lruSet(LRUNode nde);
+        /**
+         * Called to get the LRU node for this object.  Should return the
+         * node passed in to lruSet.
+         */
+        LRUNode lruGet();
+        /**
+         * Called to inform the object that it is no longer in the cache.
+         */
+        void    lruRemove();
+        }
+
+    /**
+     * Interface for nodes in the LRU cache, basicly nodes in a doubly
+     * linked list.
+     */
+        public class LRUNode extends DoublyLinkedList.Node {
+                private   LRUObj  obj  = null;
+                public    LRUObj  getObj ()               { return obj; }
+                protected void    setObj (LRUObj  newObj) {
+                        if (obj != null) obj.lruRemove();
+
+                        obj = newObj;
+                        if (obj != null) obj.lruSet(this);
+                }
+        }
+
+        private DoublyLinkedList free    = null;
+        private DoublyLinkedList used    = null;
+        private int     maxSize = 0;
+
+        public LRUCache(int size) {
+                if (size <= 0) size=1;
+                maxSize = size;
+
+                free = new DoublyLinkedList();
+                used = new DoublyLinkedList();
+
+                while (size > 0) {
+                        free.add(new LRUNode());
+                        size--;
+                }
+        }
+
+        public int getUsed() {
+                return used.getSize();
+        }
+
+        public synchronized void setSize(int newSz) {
+
+                if (maxSize < newSz) {  // list grew...
+
+                        for (int i=maxSize; i<newSz; i++)
+                                free.add(new LRUNode());
+
+                } else if (maxSize > newSz) {
+
+                        for (int i=used.getSize(); i>newSz; i--) {
+                                LRUNode nde = (LRUNode)used.getTail();
+                                used.remove(nde);
+                                nde.setObj(null);
+                        }
+                }
+
+                maxSize = newSz;
+        }
+
+        public synchronized void flush() {
+                while (used.getSize() > 0) {
+                        LRUNode nde = (LRUNode)used.pop();
+                        nde.setObj(null);
+                        free.add(nde);
+                }
+        }
+
+        public synchronized void remove(LRUObj obj) {
+                LRUNode nde = obj.lruGet();
+                if (nde == null) return;
+                used.remove(nde);
+                nde.setObj(null);
+                free.add(nde);
+        }
+
+        public synchronized void touch(LRUObj obj) {
+                LRUNode nde = obj.lruGet();
+                if (nde == null) return;
+                used.touch(nde);
+        }
+
+        public synchronized void add(LRUObj obj) {
+                LRUNode nde = obj.lruGet();
+
+                // already linked in...
+                if (nde != null) {
+                        used.touch(nde);
+                        return;
+                }
+
+                if (free.getSize() > 0) {
+                        nde = (LRUNode)free.pop();
+                        nde.setObj(obj);
+                        used.add(nde);
+                } else {
+                        nde = (LRUNode)used.getTail();
+                        nde.setObj(obj);
+                        used.touch(nde);
+                }
+        }
+
+        protected synchronized void print() {
+                System.out.println("In Use: " + used.getSize() +
+                                                   " Free: " + free.getSize());
+                LRUNode nde = (LRUNode)used.getHead();
+        if (nde == null) return;
+                do {
+                        System.out.println(nde.getObj());
+                        nde = (LRUNode)nde.getNext();
+                } while (nde != used.getHead());
+        }
+
+}

Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/rendered/LRUCache.java
------------------------------------------------------------------------------
    svn:eol-style = native