You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xmlgraphics.apache.org by je...@apache.org on 2007/12/11 14:52:53 UTC
svn commit: r603245 - in
/xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps:
FormGenerator.java ImageEncodingHelper.java ImageFormGenerator.java
PSImageUtils.java
Author: jeremias
Date: Tue Dec 11 05:52:51 2007
New Revision: 603245
URL: http://svn.apache.org/viewvc?rev=603245&view=rev
Log:
Another round of refactoring in PSImageUtils to become more versatile and faster.
Added:
xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/FormGenerator.java (with props)
xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java (with props)
xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageFormGenerator.java (with props)
Modified:
xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/PSImageUtils.java
Added: xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/FormGenerator.java
URL: http://svn.apache.org/viewvc/xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/FormGenerator.java?rev=603245&view=auto
==============================================================================
--- xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/FormGenerator.java (added)
+++ xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/FormGenerator.java Tue Dec 11 05:52:51 2007
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.xmlgraphics.ps;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Dimension2D;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+
+/**
+ * Abstract helper class for generating PostScript forms.
+ */
+public abstract class FormGenerator {
+
+ private String formName;
+ private String title;
+ private Dimension2D dimensions;
+
+ /**
+ * Main constructor.
+ * @param formName the form's name
+ * @param title the form's title or null
+ * @param dimensions the form's dimensions
+ */
+ public FormGenerator(String formName, String title, Dimension2D dimensions) {
+ this.formName = formName;
+ this.title = title;
+ this.dimensions = dimensions;
+ }
+
+ /**
+ * Returns the form's name.
+ * @return the form's name
+ */
+ public String getFormName() {
+ return this.formName;
+ }
+
+ /**
+ * Returns the form's title.
+ * @return the form's title or null if there's no title
+ */
+ public String getTitle() {
+ return this.title;
+ }
+
+ /**
+ * returns the form's dimensions.
+ * @return the form's dimensions
+ */
+ public Dimension2D getDimensions() {
+ return this.dimensions;
+ }
+
+ /**
+ * Generates the PostScript code for the PaintProc of the form.
+ * @param gen the PostScript generator
+ * @throws IOException if an I/O error occurs
+ */
+ protected abstract void generatePaintProc(PSGenerator gen) throws IOException;
+
+ /**
+ * Generates some PostScript code right after the form definition (used primarily for
+ * bitmap data).
+ * @param gen the PostScript generator
+ * @throws IOException if an I/O error occurs
+ */
+ protected void generateAdditionalDataStream(PSGenerator gen) throws IOException {
+ //nop
+ }
+
+ /**
+ * Returns the matrix for use in the form.
+ * @return the matrix
+ */
+ protected AffineTransform getMatrix() {
+ return new AffineTransform();
+ }
+
+ /**
+ * Returns the form's bounding box.
+ * @return the form's bounding box
+ */
+ protected Rectangle2D getBBox() {
+ return new Rectangle2D.Double(0, 0, dimensions.getWidth(), dimensions.getHeight());
+ }
+
+ /**
+ * Generates the PostScript form.
+ * @param gen the PostScript generator
+ * @return a PSResource instance representing the form
+ * @throws IOException if an I/O error occurs
+ */
+ public PSResource generate(PSGenerator gen) throws IOException {
+ if (gen.getPSLevel() < 2) {
+ throw new UnsupportedOperationException(
+ "Forms require at least Level 2 PostScript");
+ }
+ gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE,
+ new Object[] {PSResource.TYPE_FORM, getFormName()});
+ if (title != null) {
+ gen.writeDSCComment(DSCConstants.TITLE, title);
+ }
+ gen.writeln("/" + formName);
+ gen.writeln("<< /FormType 1");
+ gen.writeln(" /BBox " + gen.formatRectangleToArray(getBBox()));
+ gen.writeln(" /Matrix " + gen.formatMatrix(getMatrix()));
+ gen.writeln(" /PaintProc {");
+ gen.writeln(" pop");
+ gen.writeln(" gsave");
+ generatePaintProc(gen);
+ gen.writeln(" grestore");
+ gen.writeln(" } bind");
+ gen.writeln(">> def");
+ generateAdditionalDataStream(gen);
+ gen.writeDSCComment(DSCConstants.END_RESOURCE);
+ PSResource res = new PSResource(PSResource.TYPE_FORM, formName);
+ gen.getResourceTracker().registerSuppliedResource(res);
+ return res;
+ }
+}
Propchange: xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/FormGenerator.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/FormGenerator.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java
URL: http://svn.apache.org/viewvc/xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java?rev=603245&view=auto
==============================================================================
--- xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java (added)
+++ xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java Tue Dec 11 05:52:51 2007
@@ -0,0 +1,278 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.xmlgraphics.ps;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.IndexColorModel;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.xmlgraphics.image.GraphicsUtil;
+
+/**
+ * Helper class for encoding bitmap images.
+ */
+public class ImageEncodingHelper {
+
+ private static final ColorModel DEFAULT_RGB_COLOR_MODEL = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB),
+ false, false, ColorModel.OPAQUE, DataBuffer.TYPE_BYTE);
+
+ private RenderedImage image;
+ private ColorModel encodedColorModel;
+ private boolean firstTileDump;
+
+ /**
+ * Main constructor
+ * @param image the image
+ */
+ public ImageEncodingHelper(RenderedImage image) {
+ this.image = image;
+ determineEncodedColorModel();
+ }
+
+ /**
+ * Returns the associated image.
+ * @return the image
+ */
+ public RenderedImage getImage() {
+ return this.image;
+ }
+
+ /**
+ * Returns the native {@link ColorModel} used by the image.
+ * @return the native color model
+ */
+ public ColorModel getNativeColorModel() {
+ return getImage().getColorModel();
+ }
+
+ /**
+ * Returns the effective {@link ColorModel} used to encode the image. If this is different
+ * from the value returned by {@link #getNativeColorModel()} this means that the image
+ * is converted in order to encode it because no native encoding is currently possible.
+ * @return the effective color model
+ */
+ public ColorModel getEncodedColorModel() {
+ return this.encodedColorModel;
+ }
+
+ /**
+ * Indicates whether the image has an alpha channel.
+ * @return true if the image has an alpha channel
+ */
+ public boolean hasAlpha() {
+ return image.getColorModel().hasAlpha();
+ }
+
+ /**
+ * Indicates whether the image is converted during encodation.
+ * @return true if the image cannot be encoded in its native format
+ */
+ public boolean isConverted() {
+ return getNativeColorModel() != getEncodedColorModel();
+ }
+
+ private void writeRGBTo(OutputStream out) throws IOException {
+ Raster raster = image.getData();
+ Object data;
+ int nbands = raster.getNumBands();
+ int dataType = raster.getDataBuffer().getDataType();
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ data = new byte[nbands];
+ break;
+ case DataBuffer.TYPE_USHORT:
+ data = new short[nbands];
+ break;
+ case DataBuffer.TYPE_INT:
+ data = new int[nbands];
+ break;
+ case DataBuffer.TYPE_FLOAT:
+ data = new float[nbands];
+ break;
+ case DataBuffer.TYPE_DOUBLE:
+ data = new double[nbands];
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown data buffer type: "+
+ dataType);
+ }
+
+ ColorModel colorModel = image.getColorModel();
+ int w = image.getWidth();
+ int h = image.getHeight();
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ int rgb = colorModel.getRGB(raster.getDataElements(x, y, data));
+ int r = (rgb >> 16) & 0xFF;
+ int g = (rgb >> 8) & 0xFF;
+ int b = (rgb) & 0xFF;
+ out.write(r);
+ out.write(g);
+ out.write(b);
+ }
+ }
+ }
+
+ private boolean optimizedWriteTo(OutputStream out)
+ throws IOException {
+ if (this.firstTileDump) {
+ Raster raster = image.getTile(0, 0);
+ DataBuffer buffer = raster.getDataBuffer();
+ if (buffer instanceof DataBufferByte) {
+ out.write(((DataBufferByte)buffer).getData());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Indicates whether the image consists of multiple tiles.
+ * @return true if there are multiple tiles
+ */
+ protected boolean isMultiTile() {
+ int tilesX = image.getNumXTiles();
+ int tilesY = image.getNumYTiles();
+ return (tilesX != 1 || tilesY != 1);
+ }
+
+ /**
+ * Determines the color model used for encoding the image.
+ */
+ protected void determineEncodedColorModel() {
+ this.firstTileDump = false;
+ this.encodedColorModel = DEFAULT_RGB_COLOR_MODEL;
+
+ ColorModel cm = image.getColorModel();
+ ColorSpace cs = cm.getColorSpace();
+
+ int numComponents = cm.getNumComponents();
+
+ if (!isMultiTile()) {
+ if (numComponents == 1 && cs.getType() == ColorSpace.TYPE_GRAY) {
+ if (cm.getTransferType() == DataBuffer.TYPE_BYTE) {
+ this.firstTileDump = true;
+ this.encodedColorModel = cm;
+ }
+ } else if (cm instanceof IndexColorModel) {
+ if (cm.getTransferType() == DataBuffer.TYPE_BYTE) {
+ this.firstTileDump = true;
+ this.encodedColorModel = cm;
+ }
+ } else if (cm instanceof ComponentColorModel
+ && numComponents == 3
+ && !cm.hasAlpha()) {
+ Raster raster = image.getTile(0, 0);
+ DataBuffer buffer = raster.getDataBuffer();
+ if (cm.getTransferType() == DataBuffer.TYPE_BYTE
+ && buffer.getOffset() == 0
+ && buffer.getNumBanks() == 1) {
+ this.firstTileDump = true;
+ this.encodedColorModel = cm;
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Encodes the image and writes everything to the given OutputStream.
+ * @param out the OutputStream
+ * @throws IOException if an I/O error occurs
+ */
+ public void encode(OutputStream out) throws IOException {
+ if (!isConverted()) {
+ optimizedWriteTo(out);
+ } else {
+ writeRGBTo(out);
+ }
+ }
+
+ /**
+ * Encodes the image's alpha channel. If it doesn't have an alpha channel, an
+ * {@link IllegalStateException} is thrown.
+ * @param out the OutputStream
+ * @throws IOException if an I/O error occurs
+ */
+ public void encodeAlpha(OutputStream out) throws IOException {
+ if (!hasAlpha()) {
+ throw new IllegalStateException("Image doesn't have an alpha channel");
+ }
+ Raster alpha = GraphicsUtil.getAlphaRaster(image);
+ DataBuffer buffer = alpha.getDataBuffer();
+ if (buffer instanceof DataBufferByte) {
+ out.write(((DataBufferByte)buffer).getData());
+ } else {
+ throw new UnsupportedOperationException(
+ "Alpha raster not supported: " + buffer.getClass().getName());
+ }
+ }
+
+ /**
+ * Writes all pixels (color components only) of a RenderedImage to an OutputStream.
+ * @param image the image to be encoded
+ * @param out the OutputStream to write to
+ * @throws IOException if an I/O error occurs
+ */
+ public static void encodePackedColorComponents(RenderedImage image, OutputStream out)
+ throws IOException {
+ ImageEncodingHelper helper = new ImageEncodingHelper(image);
+ helper.encode(out);
+ }
+
+ /**
+ * Create an ImageEncoder for the given RenderImage instance.
+ * @param img the image
+ * @return the requested ImageEncoder
+ */
+ public static ImageEncoder createRenderedImageEncoder(RenderedImage img) {
+ return new RenderedImageEncoder(img);
+ }
+
+ /**
+ * ImageEncoder implementation for RenderedImage instances.
+ */
+ private static class RenderedImageEncoder implements ImageEncoder {
+
+ private RenderedImage img;
+
+ public RenderedImageEncoder(RenderedImage img) {
+ this.img = img;
+ }
+
+ public void writeTo(OutputStream out) throws IOException {
+ ImageEncodingHelper.encodePackedColorComponents(img, out);
+ }
+
+ public String getImplicitFilter() {
+ return null; //No implicit filters with RenderedImage instances
+ }
+
+ }
+
+}
Propchange: xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageFormGenerator.java
URL: http://svn.apache.org/viewvc/xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageFormGenerator.java?rev=603245&view=auto
==============================================================================
--- xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageFormGenerator.java (added)
+++ xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageFormGenerator.java Tue Dec 11 05:52:51 2007
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.xmlgraphics.ps;
+
+import java.awt.Dimension;
+import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Dimension2D;
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+
+/**
+ * Abstract helper class for generating PostScript forms.
+ */
+public class ImageFormGenerator extends FormGenerator {
+
+ //Mode 1 (RenderedImage)
+ private RenderedImage image;
+
+ //Mode 2 (ImageEncoder)
+ private ImageEncoder encoder;
+ private ColorSpace colorSpace;
+
+ private boolean invertImage;
+ private Dimension pixelDimensions;
+
+ /**
+ * Main constructor.
+ * @param formName the form's name
+ * @param title the form's title or null
+ * @param dimensions the form's dimensions in units (usually points)
+ * @param image the image
+ * @param invertImage true if the image shall be inverted
+ */
+ public ImageFormGenerator(String formName, String title,
+ Dimension2D dimensions,
+ RenderedImage image, boolean invertImage) {
+ super(formName, title, dimensions);
+ this.image = image;
+ this.encoder = ImageEncodingHelper.createRenderedImageEncoder(image);
+ this.invertImage = invertImage;
+ this.pixelDimensions = new Dimension(image.getWidth(), image.getHeight());
+ }
+
+ /**
+ * Main constructor.
+ * @param formName the form's name
+ * @param title the form's title or null
+ * @param dimensions the form's dimensions in units (usually points)
+ * @param dimensionsPx the form's dimensions in pixels
+ * @param encoder the image encoder
+ * @param colorSpace the target color space
+ * @param invertImage true if the image shall be inverted
+ */
+ public ImageFormGenerator(String formName, String title,
+ Dimension2D dimensions, Dimension dimensionsPx,
+ ImageEncoder encoder, ColorSpace colorSpace, boolean invertImage) {
+ super(formName, title, dimensions);
+ this.encoder = encoder;
+ this.colorSpace = colorSpace;
+ this.invertImage = invertImage;
+ this.pixelDimensions = dimensionsPx;
+ }
+
+ /**
+ * Returns the name of the data segment associated with this image form.
+ * @return the data segment name
+ */
+ protected String getDataName() {
+ return getFormName() + ":Data";
+ }
+
+ private String getAdditionalFilters(PSGenerator gen) {
+ String implicitFilter = encoder.getImplicitFilter();
+ if (implicitFilter != null) {
+ return "/ASCII85Decode filter " + implicitFilter + " filter";
+ } else {
+ if (gen.getPSLevel() >= 3) {
+ return "/ASCII85Decode filter /FlateDecode filter";
+ } else {
+ return "/ASCII85Decode filter /RunLengthDecode filter";
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected void generatePaintProc(PSGenerator gen) throws IOException {
+ if (gen.getPSLevel() == 2) {
+ gen.writeln(" userdict /i 0 put"); //rewind image data
+ } else {
+ gen.writeln(" " + getDataName() + " 0 setfileposition"); //rewind image data
+ }
+ String dataSource;
+ if (gen.getPSLevel() == 2) {
+ dataSource = "{ " + getDataName() + " i get /i i 1 add store } bind";
+ } else {
+ dataSource = getDataName();
+ }
+ AffineTransform at = new AffineTransform();
+ at.scale(getDimensions().getWidth(), getDimensions().getHeight());
+ gen.concatMatrix(at);
+ PSDictionary imageDict = new PSDictionary();
+ imageDict.put("/DataSource", dataSource);
+ if (this.image != null) {
+ PSImageUtils.writeImageCommand(this.image, imageDict, gen);
+ } else {
+ imageDict.put("/BitsPerComponent", Integer.toString(8));
+ PSImageUtils.writeImageCommand(imageDict,
+ this.pixelDimensions, this.colorSpace, this.invertImage,
+ gen);
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected void generateAdditionalDataStream(PSGenerator gen) throws IOException {
+ gen.writeln("/" + getDataName() + " currentfile");
+ gen.writeln(getAdditionalFilters(gen));
+ if (gen.getPSLevel() == 2) {
+ //Creates a data array from the inline file
+ gen.writeln("{ /temp exch def ["
+ + " { temp 16384 string readstring not {exit } if } loop ] } exec");
+ } else {
+ gen.writeln("/ReusableStreamDecode filter");
+ }
+ PSImageUtils.compressAndWriteBitmap(encoder, gen);
+ gen.writeln("def");
+ }
+
+}
Propchange: xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageFormGenerator.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageFormGenerator.java
------------------------------------------------------------------------------
svn:keywords = Id
Modified: xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/PSImageUtils.java
URL: http://svn.apache.org/viewvc/xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/PSImageUtils.java?rev=603245&r1=603244&r2=603245&view=diff
==============================================================================
--- xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/PSImageUtils.java (original)
+++ xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/PSImageUtils.java Tue Dec 11 05:52:51 2007
@@ -21,11 +21,10 @@
import java.awt.Dimension;
import java.awt.color.ColorSpace;
+import java.awt.geom.Dimension2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.ColorModel;
-import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
-import java.awt.image.DataBufferByte;
import java.awt.image.IndexColorModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
@@ -34,7 +33,6 @@
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.output.CountingOutputStream;
import org.apache.xmlgraphics.util.io.ASCII85OutputStream;
import org.apache.xmlgraphics.util.io.Finalizable;
import org.apache.xmlgraphics.util.io.FlateEncodeOutputStream;
@@ -81,7 +79,7 @@
/**
* Writes a bitmap image to the PostScript stream.
- * @param img the bitmap image as a byte array
+ * @param encoder the image encoder
* @param imgDim the dimensions of the image
* @param imgDescription the name of the image
* @param targetRect the target rectangle to place the image in
@@ -96,7 +94,7 @@
ColorSpace colorSpace, boolean invertImage,
PSGenerator gen) throws IOException {
gen.saveGraphicsState();
- translateAndScale(gen, targetRect);
+ translateAndScale(gen, null, targetRect);
gen.commentln("%AXGBeginBitmap: " + imgDescription);
@@ -117,7 +115,10 @@
gen.writeln("/Data RawData /RunLengthDecode filter def");
}
}
- writeImageCommand(imgDim, colorSpace, invertImage, gen, "Data");
+ PSDictionary imageDict = new PSDictionary();
+ imageDict.put("/DataSource", "Data");
+ imageDict.put("/BitsPerComponent", Integer.toString(8));
+ writeImageCommand(imageDict, imgDim, colorSpace, invertImage, gen);
/* the following two lines could be enabled if something still goes wrong
* gen.write("Data closefile");
* gen.write("RawData flushfile");
@@ -128,7 +129,7 @@
compressAndWriteBitmap(encoder, gen);
- gen.writeln("");
+ gen.newLine();
gen.commentln("%AXGEndBitmap");
gen.restoreGraphicsState();
}
@@ -142,11 +143,11 @@
*/
private static void writeImage(RenderedImage img,
Rectangle2D targetRect, PSGenerator gen) throws IOException {
- ImageEncoder encoder = new RenderedImageEncoder(img);
+ ImageEncoder encoder = ImageEncodingHelper.createRenderedImageEncoder(img);
String imgDescription = img.getClass().getName();
gen.saveGraphicsState();
- translateAndScale(gen, targetRect);
+ translateAndScale(gen, null, targetRect);
gen.commentln("%AXGBeginBitmap: " + imgDescription);
@@ -186,79 +187,123 @@
gen.restoreGraphicsState();
}
- private static void writeImageCommand(RenderedImage img,
- PSDictionary imageDict, PSGenerator gen) throws IOException {
+ private static ColorModel populateImageDictionary(
+ ImageEncodingHelper helper, PSDictionary imageDict) {
+ RenderedImage img = helper.getImage();
String w = Integer.toString(img.getWidth());
String h = Integer.toString(img.getHeight());
imageDict.put("/ImageType", "1");
imageDict.put("/Width", w);
imageDict.put("/Height", h);
- ColorModel cm = img.getColorModel();
- ColorSpace cs = cm.getColorSpace();
- int tilesX = img.getNumXTiles();
- int tilesY = img.getNumYTiles();
- boolean multiTile = (tilesX != 1 || tilesY != 1);
+ ColorModel cm = helper.getEncodedColorModel();
boolean invertColors = false;
+ String decodeArray = getDecodeArray(cm.getNumComponents(), invertColors);
+ int bitsPerComp = cm.getComponentSize(0);
+
+ // Setup scanning for left-to-right and top-to-bottom
+ imageDict.put("/ImageMatrix", "[" + w + " 0 0 " + h + " 0 0]");
+
+ if ((cm instanceof IndexColorModel)) {
+ IndexColorModel im = (IndexColorModel)cm;
+ int c = im.getMapSize();
+ int hival = c - 1;
+ if (hival > 4095) {
+ throw new UnsupportedOperationException("hival must not go beyond 4095");
+ }
+ decodeArray = "[0 " + Integer.toString(hival) + "]";
+ bitsPerComp = im.getPixelSize();
+ }
+ imageDict.put("/BitsPerComponent", Integer.toString(bitsPerComp));
+ imageDict.put("/Decode", decodeArray);
+ return cm;
+ }
+
+ private static String getDecodeArray(int numComponents, boolean invertColors) {
String decodeArray;
- boolean monochrome1Bit = (cm.getPixelSize() == 1 && !multiTile);
- if (cs.getType() == ColorSpace.TYPE_CMYK) {
+ StringBuffer sb = new StringBuffer("[");
+ for (int i = 0; i < numComponents; i++) {
+ if (i > 0) {
+ sb.append(" ");
+ }
if (invertColors) {
- decodeArray = "[1 0 1 0 1 0 1 0]";
+ sb.append("1 0");
} else {
- decodeArray = "[0 1 0 1 0 1 0 1]";
+ sb.append("0 1");
}
- } else if (cs.getType() == ColorSpace.TYPE_GRAY || monochrome1Bit) {
- decodeArray = "[0 1]";
- } else {
- decodeArray = "[0 1 0 1 0 1]";
}
-
- int bitsPerComp = 8;
-
- // Setup scanning for left-to-right and top-to-bottom
- imageDict.put("/ImageMatrix", "[" + w + " 0 0 " + h + " 0 0]");
-
+ sb.append("]");
+ decodeArray = sb.toString();
+ return decodeArray;
+ }
+
+ private static void prepareColorspace(PSGenerator gen, ColorSpace colorSpace)
+ throws IOException {
+ gen.writeln(getColorSpaceName(colorSpace) + " setcolorspace");
+ }
+
+ private static void prepareColorSpace(PSGenerator gen, ColorModel cm) throws IOException {
//Prepare color space
- boolean indexedColorSpace = (cm instanceof IndexColorModel);
- if (indexedColorSpace) {
- if (!multiTile) {
- IndexColorModel im = (IndexColorModel)cm;
- gen.write("[/Indexed " + getColorSpaceName(cs));
- int c = im.getMapSize();
- int hival = c - 1;
- if (hival > 4095) {
- throw new UnsupportedOperationException("hival must not go beyond 4095");
- }
- gen.writeln(" " + Integer.toString(hival));
- gen.write(" <");
- int[] palette = new int[c];
- im.getRGBs(palette);
- for (int i = 0; i < c; i++) {
- if (i > 0) {
- if ((i % 8) == 0) {
- gen.newLine();
- gen.write(" ");
- } else {
- gen.write(" ");
- }
+ if ((cm instanceof IndexColorModel)) {
+ ColorSpace cs = cm.getColorSpace();
+ IndexColorModel im = (IndexColorModel)cm;
+ gen.write("[/Indexed " + getColorSpaceName(cs));
+ int c = im.getMapSize();
+ int hival = c - 1;
+ if (hival > 4095) {
+ throw new UnsupportedOperationException("hival must not go beyond 4095");
+ }
+ gen.writeln(" " + Integer.toString(hival));
+ gen.write(" <");
+ int[] palette = new int[c];
+ im.getRGBs(palette);
+ for (int i = 0; i < c; i++) {
+ if (i > 0) {
+ if ((i % 8) == 0) {
+ gen.newLine();
+ gen.write(" ");
+ } else {
+ gen.write(" ");
}
- gen.write(rgb2Hex(palette[i]));
}
- gen.writeln(">");
- gen.writeln("] setcolorspace");
- decodeArray = "[0 " + Integer.toString(hival) + "]";
- bitsPerComp = im.getPixelSize();
- } else {
- cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
- gen.writeln(getColorSpaceName(cs) + " setcolorspace");
+ gen.write(rgb2Hex(palette[i]));
}
+ gen.writeln(">");
+ gen.writeln("] setcolorspace");
} else {
- gen.writeln(getColorSpaceName(cs) + " setcolorspace");
+ gen.writeln(getColorSpaceName(cm.getColorSpace()) + " setcolorspace");
}
- imageDict.put("/BitsPerComponent", Integer.toString(bitsPerComp));
+ }
+
+ static void writeImageCommand(RenderedImage img,
+ PSDictionary imageDict, PSGenerator gen) throws IOException {
+ ImageEncodingHelper helper = new ImageEncodingHelper(img);
+ ColorModel cm = helper.getEncodedColorModel();
+ populateImageDictionary(helper, imageDict);
+
+ writeImageCommand(imageDict, cm, gen);
+ }
+
+ static void writeImageCommand(PSDictionary imageDict, ColorModel cm, PSGenerator gen)
+ throws IOException {
+ prepareColorSpace(gen, cm);
+ gen.write(imageDict.toString());
+ gen.writeln(" image");
+ }
+
+ static void writeImageCommand(PSDictionary imageDict,
+ Dimension imgDim, ColorSpace colorSpace, boolean invertImage,
+ PSGenerator gen) throws IOException {
+ imageDict.put("/ImageType", "1");
+ imageDict.put("/Width", Integer.toString(imgDim.width));
+ imageDict.put("/Height", Integer.toString(imgDim.height));
+ String decodeArray = getDecodeArray(colorSpace.getNumComponents(), invertImage);
imageDict.put("/Decode", decodeArray);
+ // Setup scanning for left-to-right and top-to-bottom
+ imageDict.put("/ImageMatrix", "[" + imgDim.width + " 0 0 " + imgDim.height + " 0 0]");
+
+ prepareColorspace(gen, colorSpace);
gen.write(imageDict.toString());
gen.writeln(" image");
}
@@ -295,28 +340,6 @@
writeImage(img, targetRect, gen);
}
- private static void writeImageCommand(Dimension imgDim, ColorSpace colorSpace,
- boolean invertImage, PSGenerator gen, String dataSource) throws IOException {
- prepareColorspace(colorSpace, gen);
- gen.writeln("<< /ImageType 1");
- gen.writeln(" /Width " + imgDim.width);
- gen.writeln(" /Height " + imgDim.height);
- gen.writeln(" /BitsPerComponent 8");
- StringBuffer sb = new StringBuffer();
- sb.append(" /Decode [");
- for (int i = 0; i < colorSpace.getNumComponents(); i++) {
- sb.append(invertImage ? "1 0 " : "0 1 ");
- }
- sb.append("]");
- gen.writeln(sb.toString());
- // Setup scanning for left-to-right and top-to-bottom
- gen.writeln(" /ImageMatrix [" + imgDim.width + " 0 0 "
- + imgDim.height + " 0 0]");
-
- gen.writeln(" /DataSource " + dataSource);
- gen.writeln(">> image");
- }
-
/**
* Writes a bitmap image as a PostScript form enclosed by DSC resource wrappers to the
* PostScript file.
@@ -330,7 +353,7 @@
* @param gen the PostScript generator
* @return a PSResource representing the form for resource tracking
* @throws IOException In case of an I/O exception
- * @deprecated Please use the variant with the more versatile ImageEncoder as parameter
+ * @deprecated Please use {@link FormGenerator}
*/
public static PSResource writeReusableImage(final byte[] img,
Dimension imgDim, String formName, String imageDescription,
@@ -364,9 +387,11 @@
* @param gen the PostScript generator
* @return a PSResource representing the form for resource tracking
* @throws IOException In case of an I/O exception
+ * @deprecated Please use {@link FormGenerator}
*/
- public static PSResource writeReusableImage(ImageEncoder encoder,
- Dimension imgDim, String formName, String imageDescription,
+ protected static PSResource writeReusableImage(ImageEncoder encoder,
+ Dimension imgDim,
+ String formName, String imageDescription,
ColorSpace colorSpace, boolean invertImage,
PSGenerator gen) throws IOException {
if (gen.getPSLevel() < 2) {
@@ -409,7 +434,10 @@
} else {
dataSource = dataName;
}
- writeImageCommand(imgDim, colorSpace, invertImage, gen, dataSource);
+ PSDictionary imageDict = new PSDictionary();
+ imageDict.put("/DataSource", dataSource);
+ imageDict.put("/BitsPerComponent", Integer.toString(8));
+ writeImageCommand(imageDict, imgDim, colorSpace, invertImage, gen);
gen.writeln(" grestore");
gen.writeln(" } bind");
gen.writeln(">> def");
@@ -436,39 +464,54 @@
* @param targetRect the target rectangle to place the image in
* @param gen the PostScript generator
* @throws IOException In case of an I/O exception
+ * @deprecated Please use {@link #paintForm(PSResource, Dimension2D, Rectangle2D, PSGenerator)}
+ * instead.
*/
public static void paintReusableImage(
String formName,
Rectangle2D targetRect,
PSGenerator gen) throws IOException {
PSResource form = new PSResource(PSResource.TYPE_FORM, formName);
- paintForm(form, targetRect, gen);
+ paintForm(form, null, targetRect, gen);
+ }
+
+ /**
+ * Paints a reusable image (previously added as a PostScript form).
+ * @param form the PostScript form resource implementing the image
+ * @param targetRect the target rectangle to place the image in
+ * @param gen the PostScript generator
+ * @throws IOException In case of an I/O exception
+ * @deprecated Please use {@link #paintForm(PSResource, Dimension2D, Rectangle2D, PSGenerator)}
+ * instead.
+ */
+ public static void paintForm(
+ PSResource form,
+ Rectangle2D targetRect,
+ PSGenerator gen) throws IOException {
+ paintForm(form, null, targetRect, gen);
}
/**
* Paints a reusable image (previously added as a PostScript form).
* @param form the PostScript form resource implementing the image
+ * @param formDimensions the original dimensions of the form
* @param targetRect the target rectangle to place the image in
* @param gen the PostScript generator
* @throws IOException In case of an I/O exception
*/
public static void paintForm(
PSResource form,
+ Dimension2D formDimensions,
Rectangle2D targetRect,
PSGenerator gen) throws IOException {
gen.saveGraphicsState();
- translateAndScale(gen, targetRect);
+ translateAndScale(gen, formDimensions, targetRect);
gen.writeln(form.getName() + " execform");
gen.getResourceTracker().notifyResourceUsageOnPage(form);
gen.restoreGraphicsState();
}
- private static void prepareColorspace(ColorSpace colorSpace, PSGenerator gen)
- throws IOException {
- gen.writeln(getColorSpaceName(colorSpace) + " setcolorspace");
- }
-
private static String getColorSpaceName(ColorSpace colorSpace) {
if (colorSpace.getType() == ColorSpace.TYPE_CMYK) {
return("/DeviceCMYK");
@@ -479,7 +522,7 @@
}
}
- private static void compressAndWriteBitmap(ImageEncoder encoder, PSGenerator gen)
+ static void compressAndWriteBitmap(ImageEncoder encoder, PSGenerator gen)
throws IOException {
OutputStream out = gen.getOutputStream();
out = new ASCII85OutputStream(out);
@@ -493,131 +536,31 @@
out = new RunLengthEncodeOutputStream(out);
}
}
- CountingOutputStream cout = new CountingOutputStream(out);
- encoder.writeTo(cout);
+ encoder.writeTo(out);
if (out instanceof Finalizable) {
((Finalizable)out).finalizeStream();
} else {
out.flush();
}
- gen.newLine();
+ gen.newLine(); //Just to be sure
}
- private static void translateAndScale(PSGenerator gen, Rectangle2D targetRect)
- throws IOException {
+ private static void translateAndScale(PSGenerator gen,
+ Dimension2D formDimensions, Rectangle2D targetRect)
+ throws IOException {
gen.writeln(gen.formatDouble(targetRect.getX()) + " "
+ gen.formatDouble(targetRect.getY()) + " translate");
- gen.writeln(gen.formatDouble(targetRect.getWidth()) + " "
- + gen.formatDouble(targetRect.getHeight()) + " scale");
- }
-
- private static class RenderedImageEncoder implements ImageEncoder {
-
- private RenderedImage img;
-
- public RenderedImageEncoder(RenderedImage img) {
- this.img = img;
- }
-
- private void writeRGBTo(OutputStream out) throws IOException {
- Raster raster = img.getData();
- Object data;
- int nbands = raster.getNumBands();
- int dataType = raster.getDataBuffer().getDataType();
- switch (dataType) {
- case DataBuffer.TYPE_BYTE:
- data = new byte[nbands];
- break;
- case DataBuffer.TYPE_USHORT:
- data = new short[nbands];
- break;
- case DataBuffer.TYPE_INT:
- data = new int[nbands];
- break;
- case DataBuffer.TYPE_FLOAT:
- data = new float[nbands];
- break;
- case DataBuffer.TYPE_DOUBLE:
- data = new double[nbands];
- break;
- default:
- throw new IllegalArgumentException("Unknown data buffer type: "+
- dataType);
- }
-
- ColorModel colorModel = img.getColorModel();
- int w = img.getWidth();
- int h = img.getHeight();
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- int rgb = colorModel.getRGB(raster.getDataElements(x, y, data));
- int r = (rgb >> 16) & 0xFF;
- int g = (rgb >> 8) & 0xFF;
- int b = (rgb) & 0xFF;
- out.write(r);
- out.write(g);
- out.write(b);
- }
- }
+ if (formDimensions == null) {
+ formDimensions = new Dimension(1, 1);
}
-
- private boolean optimizedWriteTo(OutputStream out) throws IOException {
- ColorModel cm = img.getColorModel();
- ColorSpace cs = cm.getColorSpace();
- int tilesX = img.getNumXTiles();
- int tilesY = img.getNumYTiles();
- int colorComponents = cm.getNumColorComponents();
- int components = cm.getNumComponents();
- boolean multiTile = (tilesX != 1 || tilesY != 1);
- if (components == 1 && cs.getType() == ColorSpace.TYPE_GRAY && !multiTile) {
- Raster raster = img.getTile(0, 0);
- DataBuffer buffer = raster.getDataBuffer();
- if (buffer instanceof DataBufferByte) {
- out.write(((DataBufferByte)buffer).getData());
- return true;
- }
- }
- if (!multiTile && cm instanceof IndexColorModel) {
- IndexColorModel im = (IndexColorModel)cm;
- //int pixelSize = im.getPixelSize();
- Raster raster = img.getTile(0, 0);
- DataBuffer buffer = raster.getDataBuffer();
- if (buffer instanceof DataBufferByte) {
- DataBufferByte byteBuffer = (DataBufferByte)buffer;
- out.write(byteBuffer.getData());
- return true;
- }
- }
- if (!multiTile && cm instanceof ComponentColorModel
- && components == 3 && colorComponents == 3) {
- ComponentColorModel ccm = (ComponentColorModel)cm;
- Raster raster = img.getTile(0, 0);
- DataBuffer buffer = raster.getDataBuffer();
- if (buffer instanceof DataBufferByte
- && buffer.getOffset() == 0
- && buffer.getNumBanks() == 1) {
- DataBufferByte byteBuffer = (DataBufferByte)buffer;
- out.write(byteBuffer.getData());
- return true;
- }
- }
- return false;
- }
-
- public void writeTo(OutputStream out) throws IOException {
- boolean optimized = optimizedWriteTo(out);
- if (!optimized) {
- //fallback
- writeRGBTo(out);
- }
- }
-
- public String getImplicitFilter() {
- return null; //No implicit filters with RenderedImage instances
+ double sx = targetRect.getWidth() / formDimensions.getWidth();
+ double sy = targetRect.getHeight() / formDimensions.getHeight();
+ if (sx != 1 || sy != 1) {
+ gen.writeln(gen.formatDouble(sx) + " "
+ + gen.formatDouble(sy) + " scale");
}
-
}
-
+
/**
* Extracts a packed RGB integer array of a RenderedImage.
* @param img the image
@@ -697,8 +640,8 @@
float bboxx, float bboxy, float bboxw, float bboxh,
PSGenerator gen) throws IOException {
renderEPS(new java.io.ByteArrayInputStream(rawEPS), name,
- x, y, w, h,
- bboxx, bboxy, bboxw, bboxh,
+ new Rectangle2D.Float(x, y, w, h),
+ new Rectangle2D.Float(bboxx, bboxy, bboxw, bboxh),
gen);
}
@@ -706,38 +649,35 @@
* Places an EPS file in the PostScript stream.
* @param in the InputStream that contains the EPS stream
* @param name name for the EPS document
- * @param x x-coordinate of viewport in points
- * @param y y-coordinate of viewport in points
- * @param w width of viewport in points
- * @param h height of viewport in points
- * @param bboxx x-coordinate of EPS bounding box in points
- * @param bboxy y-coordinate of EPS bounding box in points
- * @param bboxw width of EPS bounding box in points
- * @param bboxh height of EPS bounding box in points
+ * @param viewport the viewport in points in which to place the EPS
+ * @param bbox the EPS bounding box in points
* @param gen the PS generator
* @throws IOException in case an I/O error happens during output
*/
public static void renderEPS(InputStream in, String name,
- float x, float y, float w, float h,
- float bboxx, float bboxy, float bboxw, float bboxh,
+ Rectangle2D viewport, Rectangle2D bbox,
PSGenerator gen) throws IOException {
gen.getResourceTracker().notifyResourceUsageOnPage(PSProcSets.EPS_PROCSET);
gen.writeln("%AXGBeginEPS: " + name);
gen.writeln("BeginEPSF");
- gen.writeln(gen.formatDouble(x) + " " + gen.formatDouble(y) + " translate");
- gen.writeln("0 " + gen.formatDouble(h) + " translate");
+ gen.writeln(gen.formatDouble(viewport.getX())
+ + " " + gen.formatDouble(viewport.getY()) + " translate");
+ gen.writeln("0 " + gen.formatDouble(viewport.getHeight()) + " translate");
gen.writeln("1 -1 scale");
- float sx = w / bboxw;
- float sy = h / bboxh;
+ double sx = viewport.getWidth() / bbox.getWidth();
+ double sy = viewport.getHeight() / bbox.getHeight();
if (sx != 1 || sy != 1) {
gen.writeln(gen.formatDouble(sx) + " " + gen.formatDouble(sy) + " scale");
}
- if (bboxx != 0 || bboxy != 0) {
- gen.writeln(gen.formatDouble(-bboxx) + " " + gen.formatDouble(-bboxy) + " translate");
- }
- gen.writeln(gen.formatDouble(bboxx) + " " + gen.formatDouble(bboxy)
- + " " + gen.formatDouble(bboxw) + " " + gen.formatDouble(bboxh) + " re clip");
+ if (bbox.getX() != 0 || bbox.getY() != 0) {
+ gen.writeln(gen.formatDouble(-bbox.getX())
+ + " " + gen.formatDouble(-bbox.getY()) + " translate");
+ }
+ gen.writeln(gen.formatDouble(bbox.getX())
+ + " " + gen.formatDouble(bbox.getY())
+ + " " + gen.formatDouble(bbox.getWidth())
+ + " " + gen.formatDouble(bbox.getHeight()) + " re clip");
gen.writeln("newpath");
PSResource res = new PSResource(PSResource.TYPE_FILE, name);
---------------------------------------------------------------------
Apache XML Graphics Project URL: http://xmlgraphics.apache.org/
To unsubscribe, e-mail: commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: commits-help@xmlgraphics.apache.org