001/* 002 * $Id: PngWriter.java 4784 2011-03-15 08:33:00Z blowagie $ 003 * 004 * This file is part of the iText (R) project. 005 * Copyright (c) 1998-2011 1T3XT BVBA 006 * Authors: Bruno Lowagie, Paulo Soares, et al. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Affero General Public License version 3 010 * as published by the Free Software Foundation with the addition of the 011 * following permission added to Section 15 as permitted in Section 7(a): 012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT, 013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 014 * 015 * This program is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 017 * or FITNESS FOR A PARTICULAR PURPOSE. 018 * See the GNU Affero General Public License for more details. 019 * You should have received a copy of the GNU Affero General Public License 020 * along with this program; if not, see http://www.gnu.org/licenses or write to 021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 022 * Boston, MA, 02110-1301 USA, or download the license from the following URL: 023 * http://itextpdf.com/terms-of-use/ 024 * 025 * The interactive user interfaces in modified source and object code versions 026 * of this program must display Appropriate Legal Notices, as required under 027 * Section 5 of the GNU Affero General Public License. 028 * 029 * In accordance with Section 7(b) of the GNU Affero General Public License, 030 * a covered work must retain the producer line in every PDF that is created 031 * or manipulated using iText. 032 * 033 * You can be released from the requirements of the license by purchasing 034 * a commercial license. Buying such a license is mandatory as soon as you 035 * develop commercial activities involving the iText software without 036 * disclosing the source code of your own applications. 037 * These activities include: offering paid services to customers as an ASP, 038 * serving PDFs on the fly in a web application, shipping iText with a closed 039 * source product. 040 * 041 * For more information, please contact iText Software Corp. at this 042 * address: sales@itextpdf.com 043 */ 044 045package com.itextpdf.text.pdf.codec; 046 047import com.itextpdf.text.DocWriter; 048import java.io.ByteArrayOutputStream; 049import java.io.IOException; 050import java.io.OutputStream; 051import java.util.zip.DeflaterOutputStream; 052 053/** 054 * Writes a PNG image. 055 * 056 * @author Paulo Soares 057 * @since 5.0.3 058 */ 059public class PngWriter { 060 private static final byte[] PNG_SIGNTURE = {(byte)137, 80, 78, 71, 13, 10, 26, 10}; 061 062 private static final byte[] IHDR = DocWriter.getISOBytes("IHDR"); 063 private static final byte[] PLTE = DocWriter.getISOBytes("PLTE"); 064 private static final byte[] IDAT = DocWriter.getISOBytes("IDAT"); 065 private static final byte[] IEND = DocWriter.getISOBytes("IEND"); 066 private static final byte[] iCCP = DocWriter.getISOBytes("iCCP"); 067 068 private static long[] crc_table; 069 070 private OutputStream outp; 071 072 public PngWriter(OutputStream outp) throws IOException { 073 this.outp = outp; 074 outp.write(PNG_SIGNTURE); 075 } 076 077 public void writeHeader(int width, int height, int bitDepth, int colorType) throws IOException { 078 ByteArrayOutputStream ms = new ByteArrayOutputStream(); 079 outputInt(width, ms); 080 outputInt(height, ms); 081 ms.write(bitDepth); 082 ms.write(colorType); 083 ms.write(0); 084 ms.write(0); 085 ms.write(0); 086 writeChunk(IHDR, ms.toByteArray()); 087 } 088 089 public void writeEnd() throws IOException { 090 writeChunk(IEND, new byte[0]); 091 } 092 093 public void writeData(byte[] data, int stride) throws IOException { 094 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 095 DeflaterOutputStream zip = new DeflaterOutputStream(stream); 096 for (int k = 0; k < data.length; k += stride) { 097 zip.write(0); 098 zip.write(data, k, stride); 099 } 100 zip.finish(); 101 writeChunk(IDAT, stream.toByteArray()); 102 } 103 104 public void writePalette(byte[] data) throws IOException { 105 writeChunk(PLTE, data); 106 } 107 108 public void writeIccProfile(byte[] data) throws IOException { 109 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 110 stream.write((byte)'I'); 111 stream.write((byte)'C'); 112 stream.write((byte)'C'); 113 stream.write(0); 114 stream.write(0); 115 DeflaterOutputStream zip = new DeflaterOutputStream(stream); 116 zip.write(data); 117 zip.finish(); 118 writeChunk(iCCP, stream.toByteArray()); 119 } 120 121 private static void make_crc_table() { 122 if (crc_table != null) 123 return; 124 long[] crc2 = new long[256]; 125 for (int n = 0; n < 256; n++) { 126 long c = n; 127 for (int k = 0; k < 8; k++) { 128 if ((c & 1) != 0) 129 c = 0xedb88320L ^ (c >> 1); 130 else 131 c = c >> 1; 132 } 133 crc2[n] = c; 134 } 135 crc_table = crc2; 136 } 137 138 private static long update_crc(long crc, byte[] buf, int offset, int len) { 139 long c = crc; 140 141 if (crc_table == null) 142 make_crc_table(); 143 for (int n = 0; n < len; n++) { 144 c = crc_table[(int)((c ^ buf[n + offset]) & 0xff)] ^ (c >> 8); 145 } 146 return c; 147 } 148 149 private static long crc(byte[] buf, int offset, int len) { 150 return update_crc(0xffffffffL, buf, offset, len) ^ 0xffffffffL; 151 } 152 153 private static long crc(byte[] buf) { 154 return update_crc(0xffffffffL, buf, 0, buf.length) ^ 0xffffffffL; 155 } 156 157 public void outputInt(int n) throws IOException { 158 outputInt(n, outp); 159 } 160 161 public static void outputInt(int n, OutputStream s) throws IOException { 162 s.write((byte)(n >> 24)); 163 s.write((byte)(n >> 16)); 164 s.write((byte)(n >> 8)); 165 s.write((byte)n); 166 } 167 168 public void writeChunk(byte[] chunkType, byte[] data) throws IOException { 169 outputInt(data.length); 170 outp.write(chunkType, 0, 4); 171 outp.write(data); 172 long c = update_crc(0xffffffffL, chunkType, 0, chunkType.length); 173 c = update_crc(c, data, 0, data.length) ^ 0xffffffffL; 174 outputInt((int)c); 175 } 176}