1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17/** 18 * @author Viskov Nikolay 19 * @version $Revision$ 20 */ 21package org.apache.harmony.x.imageio.plugins.png; 22 23import com.android.internal.awt.ImageOutputStreamWrapper; 24 25import java.awt.image.BufferedImage; 26import java.awt.image.ColorModel; 27import java.awt.image.DataBufferByte; 28import java.awt.image.DataBufferInt; 29import java.awt.image.IndexColorModel; 30import java.awt.image.Raster; 31import java.awt.image.RenderedImage; 32import java.awt.image.SampleModel; 33import java.awt.image.SinglePixelPackedSampleModel; 34import java.awt.image.WritableRaster; 35import java.io.IOException; 36 37import javax.imageio.IIOImage; 38import javax.imageio.ImageTypeSpecifier; 39import javax.imageio.ImageWriteParam; 40import javax.imageio.ImageWriter; 41import javax.imageio.metadata.IIOMetadata; 42import javax.imageio.spi.ImageWriterSpi; 43import javax.imageio.stream.ImageOutputStream; 44 45import org.apache.harmony.x.imageio.internal.nls.Messages; 46 47import org.apache.harmony.luni.util.NotImplementedException; 48 49import android.graphics.Bitmap; 50import android.graphics.Bitmap.CompressFormat; 51 52public class PNGImageWriter extends ImageWriter { 53 54 // /* ???AWT: Debugging 55 private static final boolean DEBUG = false; 56 private static Bitmap bm; 57 public static Bitmap getBitmap() { 58 return bm; 59 } 60 // */ 61 62 private static int[][] BAND_OFFSETS = { 63 {}, { 64 0 }, { 65 0, 1 }, { 66 0, 1, 2 }, { 67 0, 1, 2, 3 } }; 68 69 // Each pixel is a grayscale sample. 70 private static final int PNG_COLOR_TYPE_GRAY = 0; 71 // Each pixel is an R,G,B triple. 72 private static final int PNG_COLOR_TYPE_RGB = 2; 73 // Each pixel is a palette index, a PLTE chunk must appear. 74 private static final int PNG_COLOR_TYPE_PLTE = 3; 75 // Each pixel is a grayscale sample, followed by an alpha sample. 76 private static final int PNG_COLOR_TYPE_GRAY_ALPHA = 4; 77 // Each pixel is an R,G,B triple, followed by an alpha sample. 78 private static final int PNG_COLOR_TYPE_RGBA = 6; 79 80 //???AWT: private static native void initIDs(Class<ImageOutputStream> iosClass); 81 82 static { 83 //???AWT 84 /* 85 System.loadLibrary("pngencoder"); //$NON-NLS-1$ 86 initIDs(ImageOutputStream.class); 87 */ 88 } 89 90 /* 91 private native int encode(byte[] input, int bytesInBuffer, int bytePixelSize, Object ios, int imageWidth, 92 int imageHeight, int bitDepth, int colorType, int[] palette, int i, boolean b); 93 */ 94 95 protected PNGImageWriter(ImageWriterSpi iwSpi) { 96 super(iwSpi); 97 } 98 99 @Override 100 public IIOMetadata convertStreamMetadata(IIOMetadata arg0, ImageWriteParam arg1) { 101 throw new NotImplementedException(); 102 } 103 104 @Override 105 public IIOMetadata convertImageMetadata(IIOMetadata arg0, ImageTypeSpecifier arg1, ImageWriteParam arg2) { 106 throw new NotImplementedException(); 107 } 108 109 @Override 110 public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier arg0, ImageWriteParam arg1) { 111 throw new NotImplementedException(); 112 } 113 114 @Override 115 public IIOMetadata getDefaultStreamMetadata(ImageWriteParam arg0) { 116 throw new NotImplementedException(); 117 } 118 119 @Override 120 public void write(IIOMetadata streamMetadata, IIOImage iioImage, ImageWriteParam param) throws IOException { 121 if (output == null) { 122 throw new IllegalStateException("Output not been set"); 123 } 124 if (iioImage == null) { 125 throw new IllegalArgumentException("Image equals null"); 126 } 127 // AWT???: I think this is not needed anymore 128 // if (iioImage.hasRaster() && !canWriteRasters()) { 129 // throw new UnsupportedOperationException("Can't write raster"); 130 //}// ImageOutputStreamImpl 131 132 Raster sourceRaster; 133 RenderedImage img = null; 134 if (!iioImage.hasRaster()) { 135 img = iioImage.getRenderedImage(); 136 if (img instanceof BufferedImage) { 137 sourceRaster = ((BufferedImage) img).getRaster(); 138 } else { 139 sourceRaster = img.getData(); 140 } 141 } else { 142 sourceRaster = iioImage.getRaster(); 143 } 144 145 SampleModel model = sourceRaster.getSampleModel(); 146 int srcWidth = sourceRaster.getWidth(); 147 int srcHeight = sourceRaster.getHeight(); 148 int numBands = model.getNumBands(); 149 150 ColorModel colorModel = img.getColorModel(); 151 int pixelSize = colorModel.getPixelSize(); 152 int bytePixelSize = pixelSize / 8; 153 int bitDepth = pixelSize / numBands; 154 155 // byte per band 156 int bpb = bitDepth > 8 ? 2 : 1; 157 158 boolean isInterlace = true; 159 if (param instanceof PNGImageWriterParam) { 160 isInterlace = ((PNGImageWriterParam) param).getInterlace(); 161 } 162 163 int colorType = PNG_COLOR_TYPE_GRAY; 164 int[] palette = null; 165 166 if (colorModel instanceof IndexColorModel) { 167 if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8) { 168// Wrong bitDepth-numBands composition 169 throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$ 170 } 171 if (numBands != 1) { 172// Wrong bitDepth-numBands composition 173 throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$ 174 } 175 176 IndexColorModel icm = (IndexColorModel) colorModel; 177 palette = new int[icm.getMapSize()]; 178 icm.getRGBs(palette); 179 colorType = PNG_COLOR_TYPE_PLTE; 180 } 181 else if (numBands == 1) { 182 if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8 && bitDepth != 16) { 183// Wrong bitDepth-numBands composition 184 throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$ 185 } 186 colorType = PNG_COLOR_TYPE_GRAY; 187 } 188 else if (numBands == 2) { 189 if (bitDepth != 8 && bitDepth != 16) { 190// Wrong bitDepth-numBands composition 191 throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$ 192 } 193 colorType = PNG_COLOR_TYPE_GRAY_ALPHA; 194 } 195 else if (numBands == 3) { 196 if (bitDepth != 8 && bitDepth != 16) { 197// Wrong bitDepth-numBands composition 198 throw new IllegalArgumentException(Messages.getString("imageio.1")); //$NON-NLS-1$ 199 } 200 colorType = PNG_COLOR_TYPE_RGB; 201 } 202 else if (numBands == 4) { 203 if (bitDepth != 8 && bitDepth != 16) { 204 //Wrong bitDepth-numBands composition 205 throw new IllegalArgumentException(Messages.getString("imageio.1")); //$NON-NLS-1$ 206 } 207 colorType = PNG_COLOR_TYPE_RGBA; 208 } 209 210 /* ???AWT: I think this is not needed anymore 211 int dbufferLenght = bytePixelSize * imageHeight * imageWidth; 212 DataBufferByte dbuffer = new DataBufferByte(dbufferLenght); 213 214 WritableRaster scanRaster = Raster.createInterleavedRaster(dbuffer, imageWidth, imageHeight, bpb * numBands 215 * imageWidth, bpb * numBands, BAND_OFFSETS[numBands], null); 216 217 scanRaster.setRect(((BufferedImage) image).getRaster()// image.getData() 218 .createChild(0, 0, imageWidth, imageHeight, 0, 0, null)); 219 */ 220 221 if (DEBUG) { 222 System.out.println("**** raster:" + sourceRaster); 223 System.out.println("**** model:" + model); 224 System.out.println("**** type:" + colorType); 225 } 226 227 if (model instanceof SinglePixelPackedSampleModel) { 228 DataBufferInt ibuf = (DataBufferInt)sourceRaster.getDataBuffer(); 229 int[] pixels = ibuf.getData(); 230 231 // Create a bitmap with the pixel 232 bm = Bitmap.createBitmap(pixels, srcWidth, srcHeight, Bitmap.Config.ARGB_8888); 233 234 // Use Bitmap.compress() to write the image 235 ImageOutputStream ios = (ImageOutputStream) getOutput(); 236 ImageOutputStreamWrapper iosw = new ImageOutputStreamWrapper(ios); 237 bm.compress(CompressFormat.PNG, 100, iosw); 238 } else { 239 // ???AWT: Add support for other color models 240 throw new RuntimeException("Color model not supported yet"); 241 } 242 } 243 244 public ImageWriteParam getDefaultWriteParam() { 245 return new PNGImageWriterParam(); 246 } 247} 248