001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: TIFFRenderer.java 542237 2007-05-28 14:31:24Z jeremias $ */
019:
020: package org.apache.fop.render.bitmap;
021:
022: // Code originaly contributed by Oleg Tkachenko of Multiconn International Ltd
023: // (olegt@multiconn.com).
024:
025: import java.awt.image.BufferedImage;
026: import java.awt.image.DataBuffer;
027: import java.awt.image.PixelInterleavedSampleModel;
028: import java.awt.image.RenderedImage;
029: import java.awt.image.SampleModel;
030: import java.awt.image.SinglePixelPackedSampleModel;
031: import java.io.IOException;
032: import java.io.OutputStream;
033: import java.util.Iterator;
034:
035: import org.apache.commons.logging.Log;
036:
037: import org.apache.xmlgraphics.image.GraphicsUtil;
038: import org.apache.xmlgraphics.image.rendered.FormatRed;
039: import org.apache.xmlgraphics.image.writer.ImageWriter;
040: import org.apache.xmlgraphics.image.writer.ImageWriterParams;
041: import org.apache.xmlgraphics.image.writer.ImageWriterRegistry;
042: import org.apache.xmlgraphics.image.writer.MultiImageWriter;
043:
044: import org.apache.fop.apps.FOPException;
045: import org.apache.fop.apps.FOUserAgent;
046: import org.apache.fop.apps.MimeConstants;
047: import org.apache.fop.render.java2d.Java2DRenderer;
048:
049: /**
050: * <p>
051: * This class represents renderer to TIFF (Tagged Image File Format) format. It
052: * is one of the most popular and flexible of the current public domain raster
053: * file formats, which was is primarily designed for raster data interchange.
054: * Supported compression types are:
055: * <ul>
056: * <li>Raw noncompressed data</li>
057: * <li>Byte-oriented run-length encoding "PackBits" compression.</li>
058: * <li>Modified Huffman Compression (CCITT Group 3 1D facsimile compression)</li>
059: * <li>CCITT T.4 bilevel compression (CCITT Group 3 2D facsimile compression)</li>
060: * <li>CCITT T.6 bilevel compression (CCITT Group 4 facsimile compression)</li>
061: * <li>JPEG-in-TIFF compression</li>
062: * <li>DEFLATE lossless compression (also known as "Zip-in-TIFF")</li>
063: * <li>LZW compression</li>
064: * TODO
065: * <p>
066: * This class actually does not render itself, instead it extends
067: * <code>org.apache.fop.render.java2D.Java2DRenderer</code> and just encode
068: * rendering results into TIFF format using Batik's image codec
069: */
070: public class TIFFRenderer extends Java2DRenderer {
071:
072: /** The MIME type for tiff-Rendering */
073: public static final String MIME_TYPE = MimeConstants.MIME_TIFF;
074:
075: //private static final String COMPRESSION_NONE = "NONE";
076: //private static final String COMPRESSION_JPEG = "JPEG";
077: public static final String COMPRESSION_PACKBITS = "PackBits";
078: //private static final String COMPRESSION_DEFLATE = "Deflate";
079: //private static final String COMPRESSION_LZW = "LZW";
080: //private static final String COMPRESSION_ZLIB = "ZLib";
081: public static final String COMPRESSION_CCITT_T6 = "CCITT T.6"; //CCITT Group 4
082: public static final String COMPRESSION_CCITT_T4 = "CCITT T.4"; //CCITT Group 3
083:
084: /** ImageWriter parameters */
085: private ImageWriterParams writerParams;
086:
087: /** Image Type as parameter for the BufferedImage constructor (see BufferedImage.TYPE_*) */
088: private int bufferedImageType = BufferedImage.TYPE_INT_ARGB;
089:
090: private OutputStream outputStream;
091:
092: /** @see org.apache.fop.render.AbstractRenderer */
093: public String getMimeType() {
094: return MIME_TYPE;
095: }
096:
097: /** Creates TIFF renderer. */
098: public TIFFRenderer() {
099: writerParams = new ImageWriterParams();
100: writerParams.setCompressionMethod(COMPRESSION_PACKBITS);
101: }
102:
103: /**
104: * @see org.apache.fop.render.java2d.Java2DRenderer#setUserAgent(
105: * org.apache.fop.apps.FOUserAgent)
106: */
107: public void setUserAgent(FOUserAgent foUserAgent) {
108: super .setUserAgent(foUserAgent);
109:
110: //Set target resolution
111: int dpi = Math.round(userAgent.getTargetResolution());
112: writerParams.setResolution(dpi);
113: }
114:
115: /** @see org.apache.fop.render.Renderer#startRenderer(java.io.OutputStream) */
116: public void startRenderer(OutputStream outputStream)
117: throws IOException {
118: this .outputStream = outputStream;
119: super .startRenderer(outputStream);
120: }
121:
122: /** @see org.apache.fop.render.Renderer#stopRenderer() */
123: public void stopRenderer() throws IOException {
124: super .stopRenderer();
125: log.debug("Starting TIFF encoding ...");
126:
127: // Creates lazy iterator over generated page images
128: Iterator pageImagesItr = new LazyPageImagesIterator(
129: getNumberOfPages(), log);
130:
131: // Creates writer
132: ImageWriter writer = ImageWriterRegistry.getInstance()
133: .getWriterFor(getMimeType());
134: if (writer == null) {
135: throw new NullPointerException("No ImageWriter for "
136: + getMimeType() + " available!");
137: }
138: if (writer.supportsMultiImageWriter()) {
139: MultiImageWriter multiWriter = writer
140: .createMultiImageWriter(outputStream);
141: try {
142: // Write all pages/images
143: while (pageImagesItr.hasNext()) {
144: RenderedImage img = (RenderedImage) pageImagesItr
145: .next();
146: multiWriter.writeImage(img, writerParams);
147: }
148: } finally {
149: multiWriter.close();
150: }
151: } else {
152: writer.writeImage((RenderedImage) pageImagesItr.next(),
153: outputStream, writerParams);
154: if (pageImagesItr.hasNext()) {
155: log
156: .error("Image encoder does not support multiple images. Only the first page"
157: + " has been produced.");
158: }
159: }
160:
161: // Cleaning
162: outputStream.flush();
163: clearViewportList();
164: log.debug("TIFF encoding done.");
165: }
166:
167: /** @see org.apache.fop.render.java2d.Java2DRenderer#getBufferedImage(int, int) */
168: protected BufferedImage getBufferedImage(int bitmapWidth,
169: int bitmapHeight) {
170: return new BufferedImage(bitmapWidth, bitmapHeight,
171: bufferedImageType);
172: }
173:
174: /** Private inner class to lazy page rendering. */
175: private class LazyPageImagesIterator implements Iterator {
176: /** logging instance */
177: private Log log;
178:
179: private int count;
180:
181: private int current = 0;
182:
183: /**
184: * Main constructor
185: * @param c number of pages to iterate over
186: * @param log the logger to use (this is a hack so this compiles under JDK 1.3)
187: */
188: public LazyPageImagesIterator(int c, Log log) {
189: count = c;
190: this .log = log;
191: }
192:
193: public boolean hasNext() {
194: return current < count;
195: }
196:
197: public Object next() {
198: if (log.isDebugEnabled()) {
199: log.debug("[" + (current + 1) + "]");
200: }
201:
202: // Renders current page as image
203: BufferedImage pageImage = null;
204: try {
205: pageImage = getPageImage(current++);
206: } catch (FOPException e) {
207: log.error(e);
208: return null;
209: }
210:
211: if (COMPRESSION_CCITT_T4.equalsIgnoreCase(writerParams
212: .getCompressionMethod())
213: || COMPRESSION_CCITT_T6
214: .equalsIgnoreCase(writerParams
215: .getCompressionMethod())) {
216: return pageImage;
217: } else {
218: //Decorate the image with a packed sample model for encoding by the codec
219: SinglePixelPackedSampleModel sppsm;
220: sppsm = (SinglePixelPackedSampleModel) pageImage
221: .getSampleModel();
222:
223: int bands = sppsm.getNumBands();
224: int[] off = new int[bands];
225: int w = pageImage.getWidth();
226: int h = pageImage.getHeight();
227: for (int i = 0; i < bands; i++) {
228: off[i] = i;
229: }
230: SampleModel sm = new PixelInterleavedSampleModel(
231: DataBuffer.TYPE_BYTE, w, h, bands, w * bands,
232: off);
233:
234: RenderedImage rimg = new FormatRed(GraphicsUtil
235: .wrap(pageImage), sm);
236: return rimg;
237: }
238: }
239:
240: public void remove() {
241: throw new UnsupportedOperationException(
242: "Method 'remove' is not supported.");
243: }
244: }
245:
246: public void setBufferedImageType(int bufferedImageType) {
247: this .bufferedImageType = bufferedImageType;
248: }
249:
250: public ImageWriterParams getWriterParams() {
251: return writerParams;
252: }
253: }
|