/*******************************************************************************
* Copyright (c) 2009, Adobe Systems Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* · Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* · Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* · Neither the name of Adobe Systems Incorporated nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
package com.adobe.dp.office.conv;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.CRC32;
import java.util.zip.DeflaterOutputStream;
public class PNGWriter {
final static private byte[] sig = { (byte) 137, 80, 78, 71, 13, 10, 26, 10 };
final static private byte[] idat = { 'I', 'D', 'A', 'T' };
final static private byte[] end = { 0, 0, 0, 0, 'I', 'E', 'N', 'D', (byte) 0xAE, 0x42, 0x60, (byte) 0x82 };
int width;
int height;
int byteWidth;
boolean alpha;
byte[] prevLine;
byte[] filterBuf;
ByteArrayOutputStream compressedImage = new ByteArrayOutputStream();
DeflaterOutputStream deflater = new DeflaterOutputStream(compressedImage);
OutputStream out;
public PNGWriter(OutputStream out, int width, int height, boolean alpha) throws IOException {
this.out = out;
this.width = width;
this.height = height;
this.alpha = alpha;
out.write(sig);
byte[] len = { 0, 0, 0, 13 };
out.write(len);
byte[] ihdr = { 'I', 'H', 'D', 'R', (byte) (width >> 24), (byte) (width >> 16), (byte) (width >> 8),
(byte) width, (byte) (height >> 24), (byte) (height >> 16), (byte) (height >> 8), (byte) height,
8 /* bit depth */, (byte) (alpha ? 6 /* RGBA */: 2 /* RGB */), 0 /* flate */, 0 /* filter */, 0 };
out.write(ihdr);
CRC32 crc32 = new CRC32();
crc32.update(ihdr);
long crc = crc32.getValue();
byte[] checksum = { (byte) (crc >> 24), (byte) (crc >> 16), (byte) (crc >> 8), (byte) crc };
out.write(checksum);
byteWidth = width * (alpha ? 4 : 3);
filterBuf = new byte[byteWidth + 1];
}
public void writeScanline(byte[] pixels, int offset, int len) {
if (len != byteWidth)
throw new IllegalArgumentException("len");
try {
if (prevLine == null) {
filterBuf[0] = 0; // None
System.arraycopy(pixels, offset, filterBuf, 1, byteWidth);
prevLine = new byte[byteWidth];
} else {
filterBuf[0] = 2; // Up
for( int i = 0 ; i < byteWidth ; i++ )
filterBuf[i+1] = (byte)(pixels[offset+i] - prevLine[i]);
}
deflater.write(filterBuf);
System.arraycopy(pixels, offset, prevLine, 0, byteWidth);
} catch (IOException e) {
throw new Error("IOException while writing to memory-based stream");
}
}
public void close() throws IOException {
deflater.close();
byte[] bytes = compressedImage.toByteArray();
int csz = bytes.length;
byte[] len = { (byte) (csz >> 24), (byte) (csz >> 16), (byte) (csz >> 8), (byte) csz };
out.write(len);
out.write(idat);
out.write(bytes);
CRC32 crc32 = new CRC32();
crc32.update(idat);
crc32.update(bytes);
long crc = crc32.getValue();
byte[] checksum = { (byte) (crc >> 24), (byte) (crc >> 16), (byte) (crc >> 8), (byte) crc };
out.write(checksum);
out.write(end);
out.close();
}
}