Browse Source

Added support for CCITT compression in the TIFFRenderer by switching to the ImageWriter abstraction from XML Graphics Commons.

Submitted by: Oliver Hernàndez Valls <ohernandez@notariado.org>

In addition to the contributor's patch, I made the necessary changes to use the new multi-page feature of the ImageWriter abstraction. Plus I fixed a few minor issues concerning configuration.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@447325 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-0_93
Jeremias Maerki 17 years ago
parent
commit
70f8b609ca

+ 9
- 0
conf/fop.xconf View File

@@ -130,6 +130,15 @@ the location of this file.
<renderer mime="application/awt">
</renderer>

<renderer mime="image/png">
<!--transparent-page-background>true</transparent-page-background-->
</renderer>

<renderer mime="image/tiff">
<!--transparent-page-background>true</transparent-page-background-->
<!--compression>CCITT T.6</compression-->
</renderer>

<renderer mime="text/xml">
</renderer>


BIN
lib/xmlgraphics-commons-1.1-snapshot.jar View File


+ 8
- 2
src/foschema/fop-configuration.xsd View File

@@ -152,8 +152,7 @@
</xsd:sequence>
<xsd:sequence>
<xsd:annotation>
<xsd:documentation>The elements in this sequence apply only to the PNG renderer,
MIME type image/png.</xsd:documentation>
<xsd:documentation>The elements in this sequence apply only to the bitmap renderers (PNG and TIFF).</xsd:documentation>
</xsd:annotation>
<xsd:element name="transparent-page-background" type="xsd:boolean" default="false" minOccurs="0"/>
</xsd:sequence>
@@ -165,6 +164,13 @@
<xsd:element name="encoding" type="xsd:string" default="UTF-8" minOccurs="0"/>
</xsd:sequence>
</xsd:choice>
<xsd:sequence>
<xsd:annotation>
<xsd:documentation>The elements in this sequence apply only to the TIFF renderer,
MIME type image/tiff.</xsd:documentation>
</xsd:annotation>
<xsd:element name="compression" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:element name="fonts" minOccurs="0">
<xsd:complexType>
<xsd:sequence>

+ 83
- 77
src/java/org/apache/fop/render/bitmap/TIFFRenderer.java View File

@@ -38,13 +38,14 @@ import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.commons.logging.Log;

import org.apache.xmlgraphics.image.GraphicsUtil;
import org.apache.xmlgraphics.image.codec.tiff.TIFFEncodeParam;
import org.apache.xmlgraphics.image.codec.tiff.TIFFField;
import org.apache.xmlgraphics.image.codec.tiff.TIFFImageDecoder;
import org.apache.xmlgraphics.image.codec.tiff.TIFFImageEncoder;
import org.apache.xmlgraphics.image.rendered.FormatRed;
import org.apache.xmlgraphics.image.writer.ImageWriter;
import org.apache.xmlgraphics.image.writer.ImageWriterParams;
import org.apache.xmlgraphics.image.writer.ImageWriterRegistry;
import org.apache.xmlgraphics.image.writer.MultiImageWriter;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.render.java2d.Java2DRenderer;

@@ -74,9 +75,21 @@ public class TIFFRenderer extends Java2DRenderer {
/** The MIME type for tiff-Rendering */
public static final String MIME_TYPE = MimeConstants.MIME_TIFF;

/** */
private TIFFEncodeParam renderParams;

//private static final String COMPRESSION_NONE = "NONE";
//private static final String COMPRESSION_JPEG = "JPEG";
private static final String COMPRESSION_PACKBITS = "PackBits";
//private static final String COMPRESSION_DEFLATE = "Deflate";
//private static final String COMPRESSION_LZW = "LZW";
//private static final String COMPRESSION_ZLIB = "ZLib";
private static final String COMPRESSION_CCITT_T6 = "CCITT T.6"; //CCITT Group 4
private static final String COMPRESSION_CCITT_T4 = "CCITT T.4"; //CCITT Group 3
/** ImageWriter parameters */
private ImageWriterParams writerParams;
/** Image Type as parameter for the BufferedImage constructor (see BufferedImage.TYPE_*) */
private int bufferedImageType = BufferedImage.TYPE_INT_ARGB;
private OutputStream outputStream;

/** @see org.apache.fop.render.AbstractRenderer */
@@ -86,9 +99,20 @@ public class TIFFRenderer extends Java2DRenderer {

/** Creates TIFF renderer. */
public TIFFRenderer() {
renderParams = new TIFFEncodeParam();
//Default to packbits compression which is widely supported
renderParams.setCompression(TIFFEncodeParam.COMPRESSION_PACKBITS);
writerParams = new ImageWriterParams();
writerParams.setCompressionMethod(COMPRESSION_PACKBITS);
}

/**
* @see org.apache.fop.render.java2d.Java2DRenderer#setUserAgent(
* org.apache.fop.apps.FOUserAgent)
*/
public void setUserAgent(FOUserAgent foUserAgent) {
super.setUserAgent(foUserAgent);

//Set target resolution
int dpi = Math.round(userAgent.getTargetResolution());
writerParams.setResolution(dpi);
}

/**
@@ -99,28 +123,20 @@ public class TIFFRenderer extends Java2DRenderer {
public void configure(Configuration cfg) throws ConfigurationException {
super.configure(cfg);

//TODO Support output of monochrome bitmaps (fax-style)
int comp = cfg.getChild("compression").getAttributeAsInteger("value", 1);
String name = null;
switch (comp) {
case TIFFEncodeParam.COMPRESSION_NONE:
name = "COMPRESSION_NONE";
break;
case TIFFEncodeParam.COMPRESSION_JPEG_TTN2:
name = "COMPRESSION_JPEG_TTN2";
break;
case TIFFEncodeParam.COMPRESSION_PACKBITS:
name = "COMPRESSION_PACKBITS";
break;
case TIFFEncodeParam.COMPRESSION_DEFLATE:
name = "COMPRESSION_DEFLATE";
break;
default:
log.info("TIFF compression not supported: " + comp);
return;
//set compression
String name = cfg.getChild("compression").getValue(COMPRESSION_PACKBITS);
//Some compression formats need a special image format:
if (name.equalsIgnoreCase(COMPRESSION_CCITT_T6)) {
bufferedImageType = BufferedImage.TYPE_BYTE_BINARY;
} else if (name.equalsIgnoreCase(COMPRESSION_CCITT_T4)) {
bufferedImageType = BufferedImage.TYPE_BYTE_BINARY;
} else {
bufferedImageType = BufferedImage.TYPE_INT_ARGB;
}
if (!"NONE".equalsIgnoreCase(name)) {
writerParams.setCompressionMethod(name);
}
log.info("TIFF compression set to " + name);

}

/** @see org.apache.fop.render.Renderer#startRenderer(java.io.OutputStream) */
@@ -131,49 +147,45 @@ public class TIFFRenderer extends Java2DRenderer {

/** @see org.apache.fop.render.Renderer#stopRenderer() */
public void stopRenderer() throws IOException {

super.stopRenderer();
log.debug("Starting Tiff encoding ...");

//Set target resolution
float pixSzMM = userAgent.getTargetPixelUnitToMillimeter();
// num Pixs in 100 Meters
int numPix = (int)(((1000 * 100) / pixSzMM) + 0.5);
int denom = 100 * 100; // Centimeters per 100 Meters;
long [] rational = {numPix, denom};
TIFFField [] fields = {
new TIFFField(TIFFImageDecoder.TIFF_RESOLUTION_UNIT,
TIFFField.TIFF_SHORT, 1,
new char[] {(char)3}),
new TIFFField(TIFFImageDecoder.TIFF_X_RESOLUTION,
TIFFField.TIFF_RATIONAL, 1,
new long[][] {rational}),
new TIFFField(TIFFImageDecoder.TIFF_Y_RESOLUTION,
TIFFField.TIFF_RATIONAL, 1,
new long[][] {rational})
};
renderParams.setExtraFields(fields);

// Creates encoder
TIFFImageEncoder enc = new TIFFImageEncoder(outputStream, renderParams);
log.debug("Starting TIFF encoding ...");

// Creates lazy iterator over generated page images
Iterator pageImagesItr = new LazyPageImagesIterator(getNumberOfPages(), log);

// The first image to be passed to enc
RenderedImage first = (RenderedImage) pageImagesItr.next();

// The other images are set to the renderParams
renderParams.setExtraImages(pageImagesItr);

// Start encoding
enc.encode(first);
// Creates writer
ImageWriter writer = ImageWriterRegistry.getInstance().getWriterFor(getMimeType());
if (writer == null) {
throw new NullPointerException("No ImageWriter for " + getMimeType() + " available!");
}
if (writer.supportsMultiImageWriter()) {
MultiImageWriter multiWriter = writer.createMultiImageWriter(outputStream);
try {
// Write all pages/images
while (pageImagesItr.hasNext()) {
RenderedImage img = (RenderedImage) pageImagesItr.next();
multiWriter.writeImage(img, writerParams);
}
} finally {
multiWriter.close();
}
} else {
writer.writeImage((RenderedImage) pageImagesItr.next(), outputStream, writerParams);
if (pageImagesItr.hasNext()) {
log.error("Image encoder does not support multiple images. Only the first page"
+ " has been produced.");
}
}

// Cleaning
outputStream.flush();
clearViewportList();
log.debug("Tiff encoding done.");

log.debug("TIFF encoding done.");
}
/** @see org.apache.fop.render.java2d.Java2DRenderer#getBufferedImage(int, int) */
protected BufferedImage getBufferedImage(int bitmapWidth, int bitmapHeight) {
return new BufferedImage(bitmapWidth, bitmapHeight, bufferedImageType);
}

/** Private inner class to lazy page rendering. */
@@ -200,7 +212,9 @@ public class TIFFRenderer extends Java2DRenderer {
}

public Object next() {
log.debug("[" + (current + 1) + "]");
if (log.isDebugEnabled()) {
log.debug("[" + (current + 1) + "]");
}

// Renders current page as image
BufferedImage pageImage = null;
@@ -211,18 +225,10 @@ public class TIFFRenderer extends Java2DRenderer {
return null;
}

switch (renderParams.getCompression()) {
// These types of compression require a monochrome image
/* these compression types are not supported by the Batik codec
case TIFFEncodeParam.COMPRESSION_GROUP3_1D:
case TIFFEncodeParam.COMPRESSION_GROUP3_2D:
case TIFFEncodeParam.COMPRESSION_GROUP4:
BufferedImage faxImage = new BufferedImage(
pageImage.getWidth(), pageImage.getHeight(),
BufferedImage.TYPE_BYTE_BINARY);
faxImage.getGraphics().drawImage(pageImage, 0, 0, null);
return faxImage;*/
default:
if (COMPRESSION_CCITT_T4.equalsIgnoreCase(writerParams.getCompressionMethod())
|| COMPRESSION_CCITT_T6.equalsIgnoreCase(writerParams.getCompressionMethod())) {
return pageImage;
} else {
//Decorate the image with a packed sample model for encoding by the codec
SinglePixelPackedSampleModel sppsm;
sppsm = (SinglePixelPackedSampleModel)pageImage.getSampleModel();

+ 14
- 5
src/java/org/apache/fop/render/java2d/Java2DRenderer.java View File

@@ -314,10 +314,8 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem
int bitmapHeight = (int) ((pageHeight * scaleY) + 0.5);
BufferedImage currentPageImage = new BufferedImage(
bitmapWidth, bitmapHeight, BufferedImage.TYPE_INT_ARGB);
// FIXME TYPE_BYTE_BINARY ?

BufferedImage currentPageImage = getBufferedImage(bitmapWidth, bitmapHeight);
Graphics2D graphics = currentPageImage.createGraphics();
graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
@@ -367,7 +365,18 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem
}
}

/**
* Returns a specific <code>BufferedImage</code> to paint a page image on. This method can
* be overridden in subclasses to produce different image formats (ex. grayscale or b/w).
* @param bitmapWidth width of the image in pixels
* @param bitmapHeight heigth of the image in pixels
* @return the newly created BufferedImage
*/
protected BufferedImage getBufferedImage(int bitmapWidth, int bitmapHeight) {
return new BufferedImage(
bitmapWidth, bitmapHeight, BufferedImage.TYPE_INT_ARGB);
}
/**
* Returns a page viewport.
* @param pageNum the page number

+ 4
- 0
status.xml View File

@@ -28,6 +28,10 @@

<changes>
<release version="FOP Trunk">
<action context="Code" dev="JM" type="add" fixes-bug="40519" due-to="Oliver Hernàndez Valls">
Added support for CCITT compression in the TIFFRenderer by switching to the ImageWriter
abstraction from XML Graphics Commons.
</action>
<action context="Code" dev="JM" type="add">
Extension properties fox:orphan-content-limit and fox:widow-content-limit which
help with list-block and table layout. See the documentation for details.

Loading…
Cancel
Save