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 [13/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/codec/png/PNGImageEncoder.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/png/PNGImageEncoder.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/png/PNGImageEncoder.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/png/PNGImageEncoder.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,1038 @@
+/*
+
+   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.codec.png;
+
+import org.apache.flex.forks.batik.ext.awt.image.codec.util.ImageEncoderImpl;
+
+import java.awt.Rectangle;
+import java.awt.image.ColorModel;
+import java.awt.image.IndexColorModel;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+
+class CRC {
+
+    private static int[] crcTable = new int[256];
+
+    static {
+        // Initialize CRC table
+        for (int n = 0; n < 256; n++) {
+            int c = n;
+            for (int k = 0; k < 8; k++) {
+                if ((c & 1) == 1) {
+                    c = 0xedb88320 ^ (c >>> 1);
+                } else {
+                    c >>>= 1;
+                }
+
+                crcTable[n] = c;
+            }
+        }
+    }
+
+    public static int updateCRC(int crc, byte[] data, int off, int len) {
+        int c = crc;
+
+        for (int n = 0; n < len; n++) {
+             c = crcTable[(c ^ data[off + n]) & 0xff] ^ (c >>> 8);
+        }
+
+        return c;
+    }
+}
+
+
+class ChunkStream extends OutputStream implements DataOutput {
+
+    private String type;
+    private ByteArrayOutputStream baos;
+    private DataOutputStream dos;
+
+    ChunkStream(String type) throws IOException {
+        this.type = type;
+
+        this.baos = new ByteArrayOutputStream();
+        this.dos = new DataOutputStream(baos);
+    }
+
+    public void write(byte[] b) throws IOException {
+        dos.write(b);
+    }
+
+    public void write(byte[] b, int off, int len) throws IOException {
+        dos.write(b, off, len);
+    }
+
+    public void write(int b) throws IOException {
+        dos.write(b);
+    }
+
+    public void writeBoolean(boolean v) throws IOException {
+        dos.writeBoolean(v);
+    }
+
+    public void writeByte(int v) throws IOException {
+        dos.writeByte(v);
+    }
+
+    public void writeBytes(String s) throws IOException {
+        dos.writeBytes(s);
+    }
+
+    public void writeChar(int v) throws IOException {
+        dos.writeChar(v);
+    }
+
+    public void writeChars(String s) throws IOException {
+        dos.writeChars(s);
+    }
+
+    public void writeDouble(double v) throws IOException {
+        dos.writeDouble(v);
+    }
+
+    public void writeFloat(float v) throws IOException {
+        dos.writeFloat(v);
+    }
+
+    public void writeInt(int v) throws IOException {
+        dos.writeInt(v);
+    }
+
+    public void writeLong(long v) throws IOException {
+        dos.writeLong(v);
+    }
+
+    public void writeShort(int v) throws IOException {
+        dos.writeShort(v);
+    }
+
+    public void writeUTF(String str) throws IOException {
+        dos.writeUTF(str);
+    }
+
+    public void writeToStream(DataOutputStream output) throws IOException {
+        byte[] typeSignature = new byte[4];
+        typeSignature[0] = (byte)type.charAt(0);
+        typeSignature[1] = (byte)type.charAt(1);
+        typeSignature[2] = (byte)type.charAt(2);
+        typeSignature[3] = (byte)type.charAt(3);
+
+        dos.flush();
+        baos.flush();
+
+        byte[] data = baos.toByteArray();
+        int len = data.length;
+
+        output.writeInt(len);
+        output.write(typeSignature);
+        output.write(data, 0, len);
+
+        int crc = 0xffffffff;
+        crc = CRC.updateCRC(crc, typeSignature, 0, 4);
+        crc = CRC.updateCRC(crc, data, 0, len);
+        output.writeInt(crc ^ 0xffffffff);
+    }
+
+    /**
+     * this doesnt do much, its main purpose is to stop complaints
+     * about 'outputStream not closed...'.
+     * 
+     * @throws IOException
+     */
+    public void close() throws IOException {
+
+        if ( baos != null ) {
+            baos.close();
+            baos = null;
+        }
+        if( dos != null ) {
+            dos.close();
+            dos= null;
+        }
+    }
+}
+
+
+class IDATOutputStream extends FilterOutputStream {
+
+    private static final byte[] typeSignature =
+      {(byte)'I', (byte)'D', (byte)'A', (byte)'T'};
+
+    private int bytesWritten = 0;
+    private int segmentLength;
+    byte[] buffer;
+
+    public IDATOutputStream(OutputStream output,
+                            int segmentLength) {
+        super(output);
+        this.segmentLength = segmentLength;
+        this.buffer = new byte[segmentLength];
+    }
+
+    public void close() throws IOException {
+        flush();
+    }
+
+    private void writeInt(int x) throws IOException {
+        out.write(x >> 24);
+        out.write((x >> 16) & 0xff);
+        out.write((x >> 8) & 0xff);
+        out.write(x & 0xff);
+    }
+
+    public void flush() throws IOException {
+        // Length
+        writeInt(bytesWritten);
+        // 'IDAT' signature
+        out.write(typeSignature);
+        // Data
+        out.write(buffer, 0, bytesWritten);
+
+        int crc = 0xffffffff;
+        crc = CRC.updateCRC(crc, typeSignature, 0, 4);
+        crc = CRC.updateCRC(crc, buffer, 0, bytesWritten);
+
+        // CRC
+        writeInt(crc ^ 0xffffffff);
+
+        // Reset buffer
+        bytesWritten = 0;
+    }
+
+    public void write(byte[] b) throws IOException {
+        this.write(b, 0, b.length);
+    }
+
+    public void write(byte[] b, int off, int len) throws IOException {
+        while (len > 0) {
+            int bytes = Math.min(segmentLength - bytesWritten, len);
+            System.arraycopy(b, off, buffer, bytesWritten, bytes);
+            off += bytes;
+            len -= bytes;
+            bytesWritten += bytes;
+
+            if (bytesWritten == segmentLength) {
+                flush();
+            }
+        }
+    }
+
+    public void write(int b) throws IOException {
+        buffer[bytesWritten++] = (byte)b;
+        if (bytesWritten == segmentLength) {
+            flush();
+        }
+    }
+}
+
+/**
+ * An ImageEncoder for the PNG file format.
+ *
+ * @since EA4
+ * @version $Id: PNGImageEncoder.java 501844 2007-01-31 13:54:05Z dvholten $
+ */
+public class PNGImageEncoder extends ImageEncoderImpl {
+
+    private static final int PNG_COLOR_GRAY = 0;
+    private static final int PNG_COLOR_RGB = 2;
+    private static final int PNG_COLOR_PALETTE = 3;
+    private static final int PNG_COLOR_GRAY_ALPHA = 4;
+    private static final int PNG_COLOR_RGB_ALPHA = 6;
+
+    private static final byte[] magic = {
+        (byte)137, (byte) 80, (byte) 78, (byte) 71,
+        (byte) 13, (byte) 10, (byte) 26, (byte) 10
+    };
+
+    private PNGEncodeParam param;
+
+    private RenderedImage image;
+    private int width;
+    private int height;
+    private int bitDepth;
+    private int bitShift;
+    private int numBands;
+    private int colorType;
+
+    private int bpp; // bytes per pixel, rounded up
+
+    private boolean skipAlpha = false;
+    private boolean compressGray = false;
+
+    private boolean interlace;
+
+    private byte[] redPalette = null;
+    private byte[] greenPalette = null;
+    private byte[] bluePalette = null;
+    private byte[] alphaPalette = null;
+
+    private DataOutputStream dataOutput;
+
+    public PNGImageEncoder(OutputStream output,
+                           PNGEncodeParam param) {
+        super(output, param);
+
+        if (param != null) {
+            this.param = param;
+        }
+        this.dataOutput = new DataOutputStream(output);
+    }
+
+    private void writeMagic() throws IOException {
+        dataOutput.write(magic);
+    }
+
+    private void writeIHDR() throws IOException {
+        ChunkStream cs = new ChunkStream("IHDR");
+        cs.writeInt(width);
+        cs.writeInt(height);
+        cs.writeByte((byte)bitDepth);
+        cs.writeByte((byte)colorType);
+        cs.writeByte((byte)0);
+        cs.writeByte((byte)0);
+        cs.writeByte(interlace ? (byte)1 : (byte)0);
+
+        cs.writeToStream(dataOutput);
+        cs.close();
+    }
+
+    private byte[] prevRow = null;
+    private byte[] currRow = null;
+
+    private byte[][] filteredRows = null;
+
+    private static int clamp(int val, int maxValue) {
+        return (val > maxValue) ? maxValue : val;
+    }
+
+    private void encodePass(OutputStream os, Raster ras,
+                            int xOffset,     int yOffset,
+                            int xSkip,       int ySkip)
+        throws IOException {
+        int minX   = ras.getMinX();
+        int minY   = ras.getMinY();
+        int width  = ras.getWidth();
+        int height = ras.getHeight();
+
+        xOffset *= numBands;
+        xSkip   *= numBands;
+
+        int samplesPerByte = 8/bitDepth;
+
+        int numSamples = width*numBands;
+        int[] samples = new int[numSamples];
+
+        int pixels = (numSamples - xOffset + xSkip - 1)/xSkip;
+        int bytesPerRow = pixels*numBands;
+        if (bitDepth < 8) {
+            bytesPerRow = (bytesPerRow + samplesPerByte - 1)/samplesPerByte;
+        } else if (bitDepth == 16) {
+            bytesPerRow *= 2;
+        }
+
+        if (bytesPerRow == 0) {
+            return;
+        }
+
+        currRow = new byte[bytesPerRow + bpp];
+        prevRow = new byte[bytesPerRow + bpp];
+
+        filteredRows = new byte[5][bytesPerRow + bpp];
+
+        int maxValue = (1 << bitDepth) - 1;
+
+        for (int row = minY + yOffset; row < minY + height; row += ySkip) {
+            ras.getPixels(minX, row, width, 1, samples);
+
+            if (compressGray) {
+                int shift = 8 - bitDepth;
+                for (int i = 0; i < width; i++) {
+                    samples[i] >>= shift;
+                }
+            }
+
+            int count = bpp; // leave first 'bpp' bytes zero
+            int pos = 0;
+            int tmp = 0;
+
+            switch (bitDepth) {
+            case 1: case 2: case 4:
+                // Image can only have a single band
+
+                int mask = samplesPerByte - 1;
+                for (int s = xOffset; s < numSamples; s += xSkip) {
+                    int val = clamp(samples[s] >> bitShift, maxValue);
+                    tmp = (tmp << bitDepth) | val;
+
+                    if (pos++  == mask) {
+                        currRow[count++] = (byte)tmp;
+                        tmp = 0;
+                        pos = 0;
+                    }
+                }
+
+                // Left shift the last byte
+                if (pos != 0) {
+                    tmp <<= (samplesPerByte - pos)*bitDepth;
+                    currRow[count++] = (byte)tmp;
+                }
+                break;
+
+            case 8:
+                for (int s = xOffset; s < numSamples; s += xSkip) {
+                    for (int b = 0; b < numBands; b++) {
+                        currRow[count++] =
+                            (byte)clamp(samples[s + b] >> bitShift, maxValue);
+                    }
+                }
+                break;
+
+            case 16:
+                for (int s = xOffset; s < numSamples; s += xSkip) {
+                    for (int b = 0; b < numBands; b++) {
+                        int val = clamp(samples[s + b] >> bitShift, maxValue);
+                        currRow[count++] = (byte)(val >> 8);
+                        currRow[count++] = (byte)(val & 0xff);
+                    }
+                }
+                break;
+            }
+
+            // Perform filtering
+            int filterType = param.filterRow(currRow, prevRow,
+                                             filteredRows,
+                                             bytesPerRow, bpp);
+
+            os.write(filterType);
+            os.write(filteredRows[filterType], bpp, bytesPerRow);
+
+            // Swap current and previous rows
+            byte[] swap = currRow;
+            currRow = prevRow;
+            prevRow = swap;
+        }
+    }
+
+    private void writeIDAT() throws IOException {
+        IDATOutputStream ios = new IDATOutputStream(dataOutput, 8192);
+        DeflaterOutputStream dos =
+            new DeflaterOutputStream(ios, new Deflater(9));
+
+        // Future work - don't convert entire image to a Raster It
+        // might seem that you could just call image.getData() but
+        // 'BufferedImage.subImage' doesn't appear to set the Width
+        // and height properly of the Child Raster, so the Raster
+        // you get back here appears larger than it should.
+        // This solves that problem by bounding the raster to the
+        // image's bounds...
+        Raster ras = image.getData(new Rectangle(image.getMinX(),
+                                                 image.getMinY(),
+                                                 image.getWidth(),
+                                                 image.getHeight()));
+        // System.out.println("Image: [" +
+        //                    image.getMinY()  + ", " +
+        //                    image.getMinX()  + ", " +
+        //                    image.getWidth()  + ", " +
+        //                    image.getHeight() + "]");
+        // System.out.println("Ras: [" +
+        //                    ras.getMinX()  + ", " +
+        //                    ras.getMinY()  + ", " +
+        //                    ras.getWidth()  + ", " +
+        //                    ras.getHeight() + "]");
+
+        if (skipAlpha) {
+            int numBands = ras.getNumBands() - 1;
+            int[] bandList = new int[numBands];
+            for (int i = 0; i < numBands; i++) {
+                bandList[i] = i;
+            }
+            ras = ras.createChild(0, 0,
+                                  ras.getWidth(), ras.getHeight(),
+                                  0, 0,
+                                  bandList);
+        }
+
+        if (interlace) {
+            // Interlacing pass 1
+            encodePass(dos, ras, 0, 0, 8, 8);
+            // Interlacing pass 2
+            encodePass(dos, ras, 4, 0, 8, 8);
+            // Interlacing pass 3
+            encodePass(dos, ras, 0, 4, 4, 8);
+            // Interlacing pass 4
+            encodePass(dos, ras, 2, 0, 4, 4);
+            // Interlacing pass 5
+            encodePass(dos, ras, 0, 2, 2, 4);
+            // Interlacing pass 6
+            encodePass(dos, ras, 1, 0, 2, 2);
+            // Interlacing pass 7
+            encodePass(dos, ras, 0, 1, 1, 2);
+        } else {
+            encodePass(dos, ras, 0, 0, 1, 1);
+        }
+
+        dos.finish();
+        ios.flush();
+    }
+
+    private void writeIEND() throws IOException {
+        ChunkStream cs = new ChunkStream("IEND");
+        cs.writeToStream(dataOutput);
+        cs.close();
+    }
+
+    private static final float[] srgbChroma = {
+        0.31270F, 0.329F, 0.64F, 0.33F, 0.3F, 0.6F, 0.15F, 0.06F
+    };
+
+    private void writeCHRM() throws IOException {
+        if (param.isChromaticitySet() || param.isSRGBIntentSet()) {
+            ChunkStream cs = new ChunkStream("cHRM");
+
+            float[] chroma;
+            if (!param.isSRGBIntentSet()) {
+                chroma = param.getChromaticity();
+            } else {
+                chroma = srgbChroma; // SRGB chromaticities
+            }
+
+            for (int i = 0; i < 8; i++) {
+                cs.writeInt((int)(chroma[i]*100000));
+            }
+            cs.writeToStream(dataOutput);
+            cs.close();
+        }
+    }
+
+    private void writeGAMA() throws IOException {
+        if (param.isGammaSet() || param.isSRGBIntentSet()) {
+            ChunkStream cs = new ChunkStream("gAMA");
+
+            float gamma;
+            if (!param.isSRGBIntentSet()) {
+                gamma = param.getGamma();
+            } else {
+                gamma = 1.0F/2.2F; // SRGB gamma
+            }
+            // TD should include the .5 but causes regard to say
+            // everything is different.
+            cs.writeInt((int)(gamma*100000/*+0.5*/));
+            cs.writeToStream(dataOutput);
+            cs.close();
+        }
+    }
+
+    private void writeICCP() throws IOException {
+        if (param.isICCProfileDataSet()) {
+            ChunkStream cs = new ChunkStream("iCCP");
+            byte[] ICCProfileData = param.getICCProfileData();
+            cs.write(ICCProfileData);
+            cs.writeToStream(dataOutput);
+            cs.close();
+        }
+    }
+
+    private void writeSBIT() throws IOException {
+        if (param.isSignificantBitsSet()) {
+            ChunkStream cs = new ChunkStream("sBIT");
+            int[] significantBits = param.getSignificantBits();
+            int len = significantBits.length;
+            for (int i = 0; i < len; i++) {
+                cs.writeByte(significantBits[i]);
+            }
+            cs.writeToStream(dataOutput);
+            cs.close();
+        }
+    }
+
+    private void writeSRGB() throws IOException {
+        if (param.isSRGBIntentSet()) {
+            ChunkStream cs = new ChunkStream("sRGB");
+
+            int intent = param.getSRGBIntent();
+            cs.write(intent);
+            cs.writeToStream(dataOutput);
+            cs.close();
+        }
+    }
+
+    private void writePLTE() throws IOException {
+        if (redPalette == null) {
+            return;
+        }
+
+        ChunkStream cs = new ChunkStream("PLTE");
+        for (int i = 0; i < redPalette.length; i++) {
+            cs.writeByte(redPalette[i]);
+            cs.writeByte(greenPalette[i]);
+            cs.writeByte(bluePalette[i]);
+        }
+
+        cs.writeToStream(dataOutput);
+        cs.close();
+    }
+
+    private void writeBKGD() throws IOException {
+        if (param.isBackgroundSet()) {
+            ChunkStream cs = new ChunkStream("bKGD");
+
+            switch (colorType) {
+            case PNG_COLOR_GRAY:
+            case PNG_COLOR_GRAY_ALPHA:
+                int gray = ((PNGEncodeParam.Gray)param).getBackgroundGray();
+                cs.writeShort(gray);
+                break;
+
+            case PNG_COLOR_PALETTE:
+                int index =
+                   ((PNGEncodeParam.Palette)param).getBackgroundPaletteIndex();
+                cs.writeByte(index);
+                break;
+
+            case PNG_COLOR_RGB:
+            case PNG_COLOR_RGB_ALPHA:
+                int[] rgb = ((PNGEncodeParam.RGB)param).getBackgroundRGB();
+                cs.writeShort(rgb[0]);
+                cs.writeShort(rgb[1]);
+                cs.writeShort(rgb[2]);
+                break;
+            }
+
+            cs.writeToStream(dataOutput);
+            cs.close();
+        }
+    }
+
+    private void writeHIST() throws IOException {
+        if (param.isPaletteHistogramSet()) {
+            ChunkStream cs = new ChunkStream("hIST");
+
+            int[] hist = param.getPaletteHistogram();
+            for (int i = 0; i < hist.length; i++) {
+                cs.writeShort(hist[i]);
+            }
+
+            cs.writeToStream(dataOutput);
+            cs.close();
+        }
+    }
+
+    private void writeTRNS() throws IOException {
+        if (param.isTransparencySet() &&
+            (colorType != PNG_COLOR_GRAY_ALPHA) &&
+            (colorType != PNG_COLOR_RGB_ALPHA)) {
+            ChunkStream cs = new ChunkStream("tRNS");
+
+            if (param instanceof PNGEncodeParam.Palette) {
+                byte[] t =
+                    ((PNGEncodeParam.Palette)param).getPaletteTransparency();
+                for (int i = 0; i < t.length; i++) {
+                    cs.writeByte(t[i]);
+                }
+            } else if (param instanceof PNGEncodeParam.Gray) {
+                int t = ((PNGEncodeParam.Gray)param).getTransparentGray();
+                cs.writeShort(t);
+            } else if (param instanceof PNGEncodeParam.RGB) {
+                int[] t = ((PNGEncodeParam.RGB)param).getTransparentRGB();
+                cs.writeShort(t[0]);
+                cs.writeShort(t[1]);
+                cs.writeShort(t[2]);
+            }
+
+            cs.writeToStream(dataOutput);
+            cs.close();
+        } else if (colorType == PNG_COLOR_PALETTE) {
+            int lastEntry = Math.min(255, alphaPalette.length - 1);
+            int nonOpaque;
+            for (nonOpaque = lastEntry; nonOpaque >= 0; nonOpaque--) {
+                if (alphaPalette[nonOpaque] != (byte)255) {
+                    break;
+                }
+            }
+
+            if (nonOpaque >= 0) {
+                ChunkStream cs = new ChunkStream("tRNS");
+                for (int i = 0; i <= nonOpaque; i++) {
+                    cs.writeByte(alphaPalette[i]);
+                }
+                cs.writeToStream(dataOutput);
+                cs.close();
+            }
+        }
+    }
+
+    private void writePHYS() throws IOException {
+        if (param.isPhysicalDimensionSet()) {
+            ChunkStream cs = new ChunkStream("pHYs");
+
+            int[] dims = param.getPhysicalDimension();
+            cs.writeInt(dims[0]);
+            cs.writeInt(dims[1]);
+            cs.writeByte((byte)dims[2]);
+
+            cs.writeToStream(dataOutput);
+            cs.close();
+        }
+    }
+
+    private void writeSPLT() throws IOException {
+        if (param.isSuggestedPaletteSet()) {
+            ChunkStream cs = new ChunkStream("sPLT");
+
+            System.out.println("sPLT not supported yet.");
+
+            cs.writeToStream(dataOutput);
+            cs.close();
+        }
+    }
+
+    private void writeTIME() throws IOException {
+        if (param.isModificationTimeSet()) {
+            ChunkStream cs = new ChunkStream("tIME");
+
+            Date date = param.getModificationTime();
+            TimeZone gmt = TimeZone.getTimeZone("GMT");
+
+            GregorianCalendar cal = new GregorianCalendar(gmt);
+            cal.setTime(date);
+
+            int year = cal.get(Calendar.YEAR);
+            int month = cal.get(Calendar.MONTH);
+            int day = cal.get(Calendar.DAY_OF_MONTH);
+            int hour = cal.get(Calendar.HOUR_OF_DAY);
+            int minute = cal.get(Calendar.MINUTE);
+            int second = cal.get(Calendar.SECOND);
+
+            cs.writeShort(year);
+            cs.writeByte(month + 1);
+            cs.writeByte(day);
+            cs.writeByte(hour);
+            cs.writeByte(minute);
+            cs.writeByte(second);
+
+            cs.writeToStream(dataOutput);
+            cs.close();
+        }
+    }
+
+    private void writeTEXT() throws IOException {
+        if (param.isTextSet()) {
+            String[] text = param.getText();
+
+            for (int i = 0; i < text.length/2; i++) {
+                byte[] keyword = text[2*i].getBytes();
+                byte[] value = text[2*i + 1].getBytes();
+
+                ChunkStream cs = new ChunkStream("tEXt");
+
+                cs.write(keyword, 0, Math.min(keyword.length, 79));
+                cs.write(0);
+                cs.write(value);
+
+                cs.writeToStream(dataOutput);
+                cs.close();
+            }
+        }
+    }
+
+    private void writeZTXT() throws IOException {
+        if (param.isCompressedTextSet()) {
+            String[] text = param.getCompressedText();
+
+            for (int i = 0; i < text.length/2; i++) {
+                byte[] keyword = text[2*i].getBytes();
+                byte[] value = text[2*i + 1].getBytes();
+
+                ChunkStream cs = new ChunkStream("zTXt");
+
+                cs.write(keyword, 0, Math.min(keyword.length, 79));
+                cs.write(0);
+                cs.write(0);
+
+                DeflaterOutputStream dos = new DeflaterOutputStream(cs);
+                dos.write(value);
+                dos.finish();
+
+                cs.writeToStream(dataOutput);
+                cs.close();
+            }
+        }
+    }
+
+    private void writePrivateChunks() throws IOException {
+        int numChunks = param.getNumPrivateChunks();
+        for (int i = 0; i < numChunks; i++) {
+            String type = param.getPrivateChunkType(i);
+            byte[] data = param.getPrivateChunkData(i);
+
+            ChunkStream cs = new ChunkStream(type);
+            cs.write(data);
+            cs.writeToStream(dataOutput);
+            cs.close();
+        }
+    }
+
+    /**
+     * Analyzes a set of palettes and determines if it can be expressed
+     * as a standard set of gray values, with zero or one values being
+     * fully transparent and the rest being fully opaque.  If it
+     * is possible to express the data thusly, the method returns
+     * a suitable instance of PNGEncodeParam.Gray; otherwise it
+     * returns null.
+     */
+    private PNGEncodeParam.Gray createGrayParam(byte[] redPalette,
+                                                byte[] greenPalette,
+                                                byte[] bluePalette,
+                                                byte[] alphaPalette) {
+        PNGEncodeParam.Gray param = new PNGEncodeParam.Gray();
+        int numTransparent = 0;
+
+        int grayFactor = 255/((1 << bitDepth) - 1);
+        int entries = 1 << bitDepth;
+        for (int i = 0; i < entries; i++) {
+            byte red = redPalette[i];
+            if ((red != i*grayFactor) ||
+                (red != greenPalette[i]) ||
+                (red != bluePalette[i])) {
+                return null;
+            }
+
+            // All alphas must be 255 except at most 1 can be 0
+            byte alpha = alphaPalette[i];
+            if (alpha == (byte)0) {
+                param.setTransparentGray(i);
+
+                ++numTransparent;
+                if (numTransparent > 1) {
+                    return null;
+                }
+            } else if (alpha != (byte)255) {
+                return null;
+            }
+        }
+
+        return param;
+    }
+
+    /**
+     * This method encodes a <code>RenderedImage</code> into PNG.
+     * The stream into which the PNG is dumped is not closed at
+     * the end of the operation, this should be done if needed
+     * by the caller of this method.
+     */
+    public void encode(RenderedImage im) throws IOException {
+        this.image = im;
+        this.width = image.getWidth();
+        this.height = image.getHeight();
+
+        SampleModel sampleModel = image.getSampleModel();
+
+        int[] sampleSize = sampleModel.getSampleSize();
+
+        // Set bitDepth to a sentinel value
+        this.bitDepth = -1;
+        this.bitShift = 0;
+
+        // Allow user to override the bit depth of gray images
+        if (param instanceof PNGEncodeParam.Gray) {
+            PNGEncodeParam.Gray paramg = (PNGEncodeParam.Gray)param;
+            if (paramg.isBitDepthSet()) {
+                this.bitDepth = paramg.getBitDepth();
+            }
+
+            if (paramg.isBitShiftSet()) {
+                this.bitShift = paramg.getBitShift();
+            }
+        }
+
+        // Get bit depth from image if not set in param
+        if (this.bitDepth == -1) {
+            // Get bit depth from channel 0 of the image
+
+            this.bitDepth = sampleSize[0];
+            // Ensure all channels have the same bit depth
+            for (int i = 1; i < sampleSize.length; i++) {
+                if (sampleSize[i] != bitDepth) {
+                    throw new RuntimeException();
+                }
+            }
+
+            // Round bit depth up to a power of 2
+            if (bitDepth > 2 && bitDepth < 4) {
+                bitDepth = 4;
+            } else if (bitDepth > 4 && bitDepth < 8) {
+                bitDepth = 8;
+            } else if (bitDepth > 8 && bitDepth < 16) {
+                bitDepth = 16;
+            } else if (bitDepth > 16) {
+                throw new RuntimeException();
+            }
+        }
+
+        this.numBands = sampleModel.getNumBands();
+        this.bpp = numBands*((bitDepth == 16) ? 2 : 1);
+
+        ColorModel colorModel = image.getColorModel();
+        if (colorModel instanceof IndexColorModel) {
+            if (bitDepth < 1 || bitDepth > 8) {
+                throw new RuntimeException();
+            }
+            if (sampleModel.getNumBands() != 1) {
+                throw new RuntimeException();
+            }
+
+            IndexColorModel icm = (IndexColorModel)colorModel;
+            int size = icm.getMapSize();
+
+            redPalette = new byte[size];
+            greenPalette = new byte[size];
+            bluePalette = new byte[size];
+            alphaPalette = new byte[size];
+
+            icm.getReds(redPalette);
+            icm.getGreens(greenPalette);
+            icm.getBlues(bluePalette);
+            icm.getAlphas(alphaPalette);
+
+            this.bpp = 1;
+
+            if (param == null) {
+                param = createGrayParam(redPalette,
+                                        greenPalette,
+                                        bluePalette,
+                                        alphaPalette);
+            }
+
+            // If param is still null, it can't be expressed as gray
+            if (param == null) {
+                param = new PNGEncodeParam.Palette();
+            }
+
+            if (param instanceof PNGEncodeParam.Palette) {
+                // If palette not set in param, create one from the ColorModel.
+                PNGEncodeParam.Palette parami = (PNGEncodeParam.Palette)param;
+                if (parami.isPaletteSet()) {
+                    int[] palette = parami.getPalette();
+                    size = palette.length/3;
+
+                    int index = 0;
+                    for (int i = 0; i < size; i++) {
+                        redPalette[i] = (byte)palette[index++];
+                        greenPalette[i] = (byte)palette[index++];
+                        bluePalette[i] = (byte)palette[index++];
+                        alphaPalette[i] = (byte)255;
+                    }
+                }
+                this.colorType = PNG_COLOR_PALETTE;
+            } else if (param instanceof PNGEncodeParam.Gray) {
+                redPalette = greenPalette = bluePalette = alphaPalette = null;
+                this.colorType = PNG_COLOR_GRAY;
+            } else {
+                throw new RuntimeException();
+            }
+        } else if (numBands == 1) {
+            if (param == null) {
+                param = new PNGEncodeParam.Gray();
+            }
+            this.colorType = PNG_COLOR_GRAY;
+        } else if (numBands == 2) {
+            if (param == null) {
+                param = new PNGEncodeParam.Gray();
+            }
+
+            if (param.isTransparencySet()) {
+                skipAlpha = true;
+                numBands = 1;
+                if ((sampleSize[0] == 8) && (bitDepth < 8)) {
+                    compressGray = true;
+                }
+                bpp = (bitDepth == 16) ? 2 : 1;
+                this.colorType = PNG_COLOR_GRAY;
+            } else {
+                if (this.bitDepth < 8) {
+                    this.bitDepth = 8;
+                }
+                this.colorType = PNG_COLOR_GRAY_ALPHA;
+            }
+        } else if (numBands == 3) {
+            if (param == null) {
+                param = new PNGEncodeParam.RGB();
+            }
+            this.colorType = PNG_COLOR_RGB;
+        } else if (numBands == 4) {
+            if (param == null) {
+                param = new PNGEncodeParam.RGB();
+            }
+            if (param.isTransparencySet()) {
+                skipAlpha = true;
+                numBands = 3;
+                bpp = (bitDepth == 16) ? 6 : 3;
+                this.colorType = PNG_COLOR_RGB;
+            } else {
+                this.colorType = PNG_COLOR_RGB_ALPHA;
+            }
+        }
+
+        interlace = param.getInterlacing();
+
+        writeMagic();
+
+        writeIHDR();
+
+        writeCHRM();
+        writeGAMA();
+        writeICCP();
+        writeSBIT();
+        writeSRGB();
+
+        writePLTE();
+
+        writeHIST();
+        writeTRNS();
+        writeBKGD();
+
+        writePHYS();
+        writeSPLT();
+        writeTIME();
+        writeTEXT();
+        writeZTXT();
+
+        writePrivateChunks();
+
+        writeIDAT();
+
+        writeIEND();
+
+        dataOutput.flush();
+    }
+}

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

Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/png/PNGImageWriter.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/png/PNGImageWriter.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/png/PNGImageWriter.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/png/PNGImageWriter.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,59 @@
+/*
+
+   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.codec.png;
+
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.flex.forks.batik.ext.awt.image.spi.ImageWriter;
+import org.apache.flex.forks.batik.ext.awt.image.spi.ImageWriterParams;
+
+/**
+ * ImageWriter implementation that uses Batik's PNG codec to
+ * write PNG files.
+ *
+ * @version $Id: PNGImageWriter.java 502538 2007-02-02 08:52:56Z dvholten $
+ */
+public class PNGImageWriter implements ImageWriter {
+
+    /**
+     * @see ImageWriter#writeImage(java.awt.image.RenderedImage, java.io.OutputStream)
+     */
+    public void writeImage(RenderedImage image, OutputStream out)
+            throws IOException {
+        writeImage(image, out, null);
+    }
+
+    /**
+     * @see ImageWriter#writeImage(java.awt.image.RenderedImage, java.io.OutputStream, org.apache.flex.forks.batik.ext.awt.image.spi.ImageWriterParams)
+     */
+    public void writeImage(RenderedImage image, OutputStream out,
+            ImageWriterParams params) throws IOException {
+        PNGImageEncoder encoder = new PNGImageEncoder(out, null);
+        encoder.encode(image);
+    }
+
+    /**
+     * @see ImageWriter#getMIMEType()
+     */
+    public String getMIMEType() {
+        return "image/png";
+    }
+}

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