/*
 * 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: PSImageUtils.java 1792872 2017-04-27 12:30:09Z ssteiner $ */

package org.apache.xmlgraphics.ps;

import java.awt.Color;
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.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.InputStream;
import java.io.OutputStream;
import java.util.Arrays;

import org.apache.commons.io.IOUtils;

import org.apache.xmlgraphics.util.io.ASCII85OutputStream;
import org.apache.xmlgraphics.util.io.Finalizable;
import org.apache.xmlgraphics.util.io.FlateEncodeOutputStream;
import org.apache.xmlgraphics.util.io.RunLengthEncodeOutputStream;

// CSOFF: HideUtilityClassConstructor

Utility code for rendering images in PostScript.
/** * Utility code for rendering images in PostScript. */
public class PSImageUtils { public PSImageUtils() { }
Writes a bitmap image to the PostScript stream.
Params:
  • img – the bitmap image as a byte array
  • imgDim – the dimensions of the image
  • imgDescription – the name of the image
  • targetRect – the target rectangle to place the image in
  • isJPEG – true if "img" contains a DCT-encoded images, false if "img" contains the decoded bitmap
  • colorSpace – the color space of the image
  • gen – the PostScript generator
Throws:
Deprecated:Please use the variant with the more versatile ImageEncoder as parameter
/** * Writes a bitmap image to the PostScript stream. * @param img the bitmap image as a byte array * @param imgDim the dimensions of the image * @param imgDescription the name of the image * @param targetRect the target rectangle to place the image in * @param isJPEG true if "img" contains a DCT-encoded images, false if "img" contains the * decoded bitmap * @param colorSpace the color space of the image * @param gen the PostScript generator * @throws IOException In case of an I/O exception * @deprecated Please use the variant with the more versatile ImageEncoder as parameter */
public static void writeImage(final byte[] img, Dimension imgDim, String imgDescription, Rectangle2D targetRect, final boolean isJPEG, ColorSpace colorSpace, PSGenerator gen) throws IOException { ImageEncoder encoder = new ImageEncoder() { public void writeTo(OutputStream out) throws IOException { out.write(img); } public String getImplicitFilter() { if (isJPEG) { return "<< >> /DCTDecode"; } else { return null; } } }; writeImage(encoder, imgDim, imgDescription, targetRect, colorSpace, 8, false, gen); }
Writes a bitmap image to the PostScript stream.
Params:
  • encoder – the image encoder
  • imgDim – the dimensions of the image
  • imgDescription – the name of the image
  • targetRect – the target rectangle to place the image in
  • colorSpace – the color space of the image
  • bitsPerComponent – the number of bits per component
  • invertImage – true if the image shall be inverted
  • gen – the PostScript generator
Throws:
/** * Writes a bitmap image to the PostScript stream. * @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 * @param colorSpace the color space of the image * @param bitsPerComponent the number of bits per component * @param invertImage true if the image shall be inverted * @param gen the PostScript generator * @throws IOException In case of an I/O exception */
public static void writeImage(ImageEncoder encoder, Dimension imgDim, String imgDescription, Rectangle2D targetRect, ColorSpace colorSpace, int bitsPerComponent, boolean invertImage, PSGenerator gen) throws IOException { gen.saveGraphicsState(); translateAndScale(gen, null, targetRect); gen.commentln("%AXGBeginBitmap: " + imgDescription); gen.writeln("{{"); // Template: (RawData is used for the EOF signal only) // gen.write("/RawData currentfile <first filter> filter def"); // gen.write("/Data RawData <second filter> <third filter> [...] def"); String implicitFilter = encoder.getImplicitFilter(); if (implicitFilter != null) { gen.writeln("/RawData currentfile /ASCII85Decode filter def"); gen.writeln("/Data RawData " + implicitFilter + " filter def"); } else { if (gen.getPSLevel() >= 3) { gen.writeln("/RawData currentfile /ASCII85Decode filter def"); gen.writeln("/Data RawData /FlateDecode filter def"); } else { gen.writeln("/RawData currentfile /ASCII85Decode filter def"); gen.writeln("/Data RawData /RunLengthDecode filter def"); } } PSDictionary imageDict = new PSDictionary(); imageDict.put("/DataSource", "Data"); imageDict.put("/BitsPerComponent", Integer.toString(bitsPerComponent)); 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"); */ gen.writeln("} stopped {handleerror} if"); gen.writeln(" RawData flushfile"); gen.writeln("} exec"); compressAndWriteBitmap(encoder, gen); gen.newLine(); gen.commentln("%AXGEndBitmap"); gen.restoreGraphicsState(); } public static void writeImage(ImageEncoder encoder, Dimension imgDim, String imgDescription, Rectangle2D targetRect, ColorModel colorModel, PSGenerator gen) throws IOException { writeImage(encoder, imgDim, imgDescription, targetRect, colorModel, gen, null); }
Writes a bitmap image to the PostScript stream.
Params:
  • encoder – the image encoder
  • imgDim – the dimensions of the image
  • imgDescription – the name of the image
  • targetRect – the target rectangle to place the image in
  • colorModel – the color model of the image
  • gen – the PostScript generator
Throws:
/** * Writes a bitmap image to the PostScript stream. * @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 * @param colorModel the color model of the image * @param gen the PostScript generator * @throws IOException In case of an I/O exception */
public static void writeImage(ImageEncoder encoder, Dimension imgDim, String imgDescription, Rectangle2D targetRect, ColorModel colorModel, PSGenerator gen, RenderedImage ri) throws IOException { gen.saveGraphicsState(); translateAndScale(gen, null, targetRect); gen.commentln("%AXGBeginBitmap: " + imgDescription); gen.writeln("{{"); String implicitFilter = encoder.getImplicitFilter(); if (implicitFilter != null) { gen.writeln("/RawData currentfile /ASCII85Decode filter def"); gen.writeln("/Data RawData " + implicitFilter + " filter def"); } else { if (gen.getPSLevel() >= 3) { gen.writeln("/RawData currentfile /ASCII85Decode filter def"); gen.writeln("/Data RawData /FlateDecode filter def"); } else { gen.writeln("/RawData currentfile /ASCII85Decode filter def"); gen.writeln("/Data RawData /RunLengthDecode filter def"); } } PSDictionary imageDict = new PSDictionary(); imageDict.put("/DataSource", "Data"); populateImageDictionary(imgDim, colorModel, imageDict); if (ri != null) { DataBuffer buffer = ri.getData().getDataBuffer(); if (!(buffer instanceof DataBufferByte)) { imageDict.put("/BitsPerComponent", 8); } } writeImageCommand(imageDict, colorModel, gen); /* * the following two lines could be enabled if something still goes wrong * gen.write("Data closefile"); * gen.write("RawData flushfile"); */ gen.writeln("} stopped {handleerror} if"); gen.writeln(" RawData flushfile"); gen.writeln("} exec"); compressAndWriteBitmap(encoder, gen); gen.newLine(); gen.commentln("%AXGEndBitmap"); gen.restoreGraphicsState(); }
Writes a bitmap image to the PostScript stream.
Params:
  • encoder – the image encoder
  • imgDim – the dimensions of the image
  • imgDescription – the name of the image
  • targetRect – the target rectangle to place the image in
  • colorModel – the color model of the image
  • gen – the PostScript generator
Throws:
/** * Writes a bitmap image to the PostScript stream. * @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 * @param colorModel the color model of the image * @param gen the PostScript generator * @throws IOException In case of an I/O exception */
public static void writeImage(ImageEncoder encoder, Dimension imgDim, String imgDescription, Rectangle2D targetRect, ColorModel colorModel, PSGenerator gen, RenderedImage ri, Color maskColor) throws IOException { gen.saveGraphicsState(); translateAndScale(gen, null, targetRect); gen.commentln("%AXGBeginBitmap: " + imgDescription); gen.writeln("{{"); String implicitFilter = encoder.getImplicitFilter(); if (implicitFilter != null) { gen.writeln("/RawData currentfile /ASCII85Decode filter def"); gen.writeln("/Data RawData " + implicitFilter + " filter def"); } else { if (gen.getPSLevel() >= 3) { gen.writeln("/RawData currentfile /ASCII85Decode filter def"); gen.writeln("/Data RawData /FlateDecode filter def"); } else { gen.writeln("/RawData currentfile /ASCII85Decode filter def"); gen.writeln("/Data RawData /RunLengthDecode filter def"); } } PSDictionary imageDict = new PSDictionary(); imageDict.put("/DataSource", "Data"); populateImageDictionary(imgDim, colorModel, imageDict, maskColor); if (ri != null) { DataBuffer buffer = ri.getData().getDataBuffer(); if (!(buffer instanceof DataBufferByte)) { imageDict.put("/BitsPerComponent", 8); } } writeImageCommand(imageDict, colorModel, gen); /* * the following two lines could be enabled if something still goes wrong * gen.write("Data closefile"); * gen.write("RawData flushfile"); */ gen.writeln("} stopped {handleerror} if"); gen.writeln(" RawData flushfile"); gen.writeln("} exec"); compressAndWriteBitmap(encoder, gen); gen.newLine(); gen.commentln("%AXGEndBitmap"); gen.restoreGraphicsState(); } private static ColorModel populateImageDictionary(Dimension imgDim, ColorModel colorModel, PSDictionary imageDict) { imageDict.put("/ImageType", "1"); colorModel = writeImageDictionary(imgDim, imageDict, colorModel); return colorModel; } private static ColorModel populateImageDictionary(Dimension imgDim, ColorModel colorModel, PSDictionary imageDict, Color maskColor) { imageDict.put("/ImageType", "4"); colorModel = writeImageDictionary(imgDim, imageDict, colorModel); imageDict.put("/MaskColor", String.format("[ %d %d %d ]", maskColor.getRed(), maskColor.getGreen(), maskColor.getBlue())); return colorModel; } private static ColorModel writeImageDictionary(Dimension imgDim, PSDictionary imageDict, ColorModel colorModel) { String w = Integer.toString(imgDim.width); String h = Integer.toString(imgDim.height); imageDict.put("/Width", w); imageDict.put("/Height", h); boolean invertColors = false; String decodeArray = getDecodeArray(colorModel.getNumColorComponents(), invertColors); int bitsPerComp = colorModel.getComponentSize(0); // Setup scanning for left-to-right and top-to-bottom imageDict.put("/ImageMatrix", "[" + w + " 0 0 " + h + " 0 0]"); if ((colorModel instanceof IndexColorModel)) { IndexColorModel indexColorModel = (IndexColorModel) colorModel; int c = indexColorModel.getMapSize(); int hival = c - 1; if (hival > 4095) { throw new UnsupportedOperationException("hival must not go beyond 4095"); } bitsPerComp = indexColorModel.getPixelSize(); int ceiling = ((int) Math.pow(2, bitsPerComp)) - 1; decodeArray = "[0 " + ceiling + "]"; } imageDict.put("/BitsPerComponent", Integer.toString(bitsPerComp)); imageDict.put("/Decode", decodeArray); return colorModel; } private static String getDecodeArray(int numComponents, boolean invertColors) { String decodeArray; StringBuffer sb = new StringBuffer("["); for (int i = 0; i < numComponents; i++) { if (i > 0) { sb.append(" "); } if (invertColors) { sb.append("1 0"); } else { sb.append("0 1"); } } 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 if ((cm instanceof IndexColorModel)) { ColorSpace cs = cm.getColorSpace(); IndexColorModel im = (IndexColorModel)cm; boolean isDeviceGray; int c = im.getMapSize(); int[] palette = new int[c]; im.getRGBs(palette); byte[] reds = new byte[c]; byte[] greens = new byte[c]; byte[] blues = new byte[c]; im.getReds(reds); im.getGreens(greens); im.getBlues(blues); int hival = c - 1; if (hival > 4095) { throw new UnsupportedOperationException("hival must not go beyond 4095"); } isDeviceGray = Arrays.equals(reds, blues) && Arrays.equals(blues, greens); if (isDeviceGray) { gen.write("[/Indexed " + "/DeviceGray"); } else { gen.write("[/Indexed " + getColorSpaceName(cs)); } gen.writeln(" " + Integer.toString(hival)); gen.write(" <"); if (isDeviceGray) { gen.write(toHexString(blues)); } else { 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"); } else { gen.writeln(getColorSpaceName(cm.getColorSpace()) + " setcolorspace"); } } static String toHexString(byte[] color) { char[] hexChars = new char[color.length * 2]; int x; for (int i = 0; i < color.length; i++) { x = color[i] & 0xFF; hexChars[i * 2] = HEX[x >>> 4]; hexChars[i * 2 + 1] = HEX[x & 0x0F]; } return new String(hexChars); } static void writeImageCommand(RenderedImage img, PSDictionary imageDict, PSGenerator gen) throws IOException { ImageEncodingHelper helper = new ImageEncodingHelper(img, true); ColorModel cm = helper.getEncodedColorModel(); Dimension imgDim = new Dimension(img.getWidth(), img.getHeight()); populateImageDictionary(imgDim, cm, 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"); } private static final char[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; private static String rgb2Hex(int rgb) { StringBuffer sb = new StringBuffer(); for (int i = 5; i >= 0; i--) { int shift = i * 4; int n = (rgb & (15 << shift)) >> shift; sb.append(HEX[n % 16]); } return sb.toString(); }
Renders a bitmap image to PostScript.
Params:
  • img – image to render
  • x – x position
  • y – y position
  • w – width
  • h – height
  • gen – PS generator
Throws:
  • IOException – In case of an I/O problem while rendering the image
/** * Renders a bitmap image to PostScript. * @param img image to render * @param x x position * @param y y position * @param w width * @param h height * @param gen PS generator * @throws IOException In case of an I/O problem while rendering the image */
public static void renderBitmapImage(RenderedImage img, float x, float y, float w, float h, PSGenerator gen, Color mask) throws IOException { Rectangle2D targetRect = new Rectangle2D.Double(x, y, w, h); ImageEncoder encoder = ImageEncodingHelper.createRenderedImageEncoder(img); Dimension imgDim = new Dimension(img.getWidth(), img.getHeight()); String imgDescription = img.getClass().getName(); ImageEncodingHelper helper = new ImageEncodingHelper(img); ColorModel cm = helper.getEncodedColorModel(); if (mask == null) { writeImage(encoder, imgDim, imgDescription, targetRect, cm, gen, img); } else { writeImage(encoder, imgDim, imgDescription, targetRect, cm, gen, img, mask); } }
Writes a bitmap image as a PostScript form enclosed by DSC resource wrappers to the PostScript file.
Params:
  • img – the raw bitmap data
  • imgDim – the dimensions of the image
  • formName – the name of the PostScript form to use
  • imageDescription – a description of the image added as a DSC Title comment
  • isJPEG – true if "img" contains a DCT-encoded images, false if "img" contains the decoded bitmap
  • colorSpace – the color space of the image
  • gen – the PostScript generator
Throws:
Returns:a PSResource representing the form for resource tracking
Deprecated:Please use FormGenerator
/** * Writes a bitmap image as a PostScript form enclosed by DSC resource wrappers to the * PostScript file. * @param img the raw bitmap data * @param imgDim the dimensions of the image * @param formName the name of the PostScript form to use * @param imageDescription a description of the image added as a DSC Title comment * @param isJPEG true if "img" contains a DCT-encoded images, false if "img" contains the * decoded bitmap * @param colorSpace the color space of the image * @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(final byte[] img, Dimension imgDim, String formName, String imageDescription, final boolean isJPEG, ColorSpace colorSpace, PSGenerator gen) throws IOException { ImageEncoder encoder = new ImageEncoder() { public void writeTo(OutputStream out) throws IOException { out.write(img); } public String getImplicitFilter() { if (isJPEG) { return "<< >> /DCTDecode"; } else { return null; } } }; return writeReusableImage(encoder, imgDim, formName, imageDescription, colorSpace, false, gen); }
Writes a bitmap image as a PostScript form enclosed by DSC resource wrappers to the PostScript file.
Params:
  • encoder – the ImageEncoder that will provide the raw bitmap data
  • imgDim – the dimensions of the image
  • formName – the name of the PostScript form to use
  • imageDescription – a description of the image added as a DSC Title comment
  • colorSpace – the color space of the image
  • invertImage – true if the image shall be inverted
  • gen – the PostScript generator
Throws:
Returns:a PSResource representing the form for resource tracking
Deprecated:Please use FormGenerator
/** * Writes a bitmap image as a PostScript form enclosed by DSC resource wrappers to the * PostScript file. * @param encoder the ImageEncoder that will provide the raw bitmap data * @param imgDim the dimensions of the image * @param formName the name of the PostScript form to use * @param imageDescription a description of the image added as a DSC Title comment * @param colorSpace the color space of the image * @param invertImage true if the image shall be inverted * @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} */
protected static PSResource writeReusableImage(ImageEncoder encoder, Dimension imgDim, String formName, String imageDescription, ColorSpace colorSpace, boolean invertImage, PSGenerator gen) throws IOException { if (gen.getPSLevel() < 2) { throw new UnsupportedOperationException( "Reusable images requires at least Level 2 PostScript"); } String dataName = formName + ":Data"; gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE, formName); if (imageDescription != null) { gen.writeDSCComment(DSCConstants.TITLE, imageDescription); } String additionalFilters; String implicitFilter = encoder.getImplicitFilter(); if (implicitFilter != null) { additionalFilters = "/ASCII85Decode filter " + implicitFilter + " filter"; } else { if (gen.getPSLevel() >= 3) { additionalFilters = "/ASCII85Decode filter /FlateDecode filter"; } else { additionalFilters = "/ASCII85Decode filter /RunLengthDecode filter"; } } gen.writeln("/" + formName); gen.writeln("<< /FormType 1"); gen.writeln(" /BBox [0 0 " + imgDim.width + " " + imgDim.height + "]"); gen.writeln(" /Matrix [1 0 0 1 0 0]"); gen.writeln(" /PaintProc {"); gen.writeln(" pop"); gen.writeln(" gsave"); if (gen.getPSLevel() == 2) { gen.writeln(" userdict /i 0 put"); //rewind image data } else { gen.writeln(" " + dataName + " 0 setfileposition"); //rewind image data } String dataSource; if (gen.getPSLevel() == 2) { dataSource = "{ " + dataName + " i get /i i 1 add store } bind"; } else { dataSource = dataName; } 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"); gen.writeln("/" + dataName + " currentfile"); gen.writeln(additionalFilters); 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"); } compressAndWriteBitmap(encoder, gen); gen.writeln("def"); gen.writeDSCComment(DSCConstants.END_RESOURCE); PSResource res = new PSResource(PSResource.TYPE_FORM, formName); gen.getResourceTracker().registerSuppliedResource(res); return res; }
Paints a reusable image (previously added as a PostScript form).
Params:
  • formName – the name of the PostScript form implementing the image
  • targetRect – the target rectangle to place the image in
  • gen – the PostScript generator
Throws:
Deprecated:Please use paintForm(PSResource, Dimension2D, Rectangle2D, PSGenerator) instead.
/** * Paints a reusable image (previously added as a PostScript form). * @param formName the name of the PostScript form 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 paintReusableImage( String formName, Rectangle2D targetRect, PSGenerator gen) throws IOException { PSResource form = new PSResource(PSResource.TYPE_FORM, formName); paintForm(form, null, targetRect, gen); }
Paints a reusable image (previously added as a PostScript form).
Params:
  • form – the PostScript form resource implementing the image
  • targetRect – the target rectangle to place the image in
  • gen – the PostScript generator
Throws:
Deprecated:Please use paintForm(PSResource, Dimension2D, Rectangle2D, PSGenerator) instead.
/** * 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).
Params:
  • form – the PostScript form resource implementing the image
  • formDimensions – the original dimensions of the form
  • targetRect – the target rectangle to place the image in
  • gen – the PostScript generator
Throws:
/** * 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, formDimensions, targetRect); gen.writeln(form.getName() + " execform"); gen.getResourceTracker().notifyResourceUsageOnPage(form); gen.restoreGraphicsState(); } private static String getColorSpaceName(ColorSpace colorSpace) { if (colorSpace.getType() == ColorSpace.TYPE_CMYK) { return "/DeviceCMYK"; } else if (colorSpace.getType() == ColorSpace.TYPE_GRAY) { return "/DeviceGray"; } else { return "/DeviceRGB"; } } static void compressAndWriteBitmap(ImageEncoder encoder, PSGenerator gen) throws IOException { OutputStream out = gen.getOutputStream(); out = new ASCII85OutputStream(out); String implicitFilter = encoder.getImplicitFilter(); if (implicitFilter != null) { //nop } else { if (gen.getPSLevel() >= 3) { out = new FlateEncodeOutputStream(out); } else { out = new RunLengthEncodeOutputStream(out); } } encoder.writeTo(out); if (out instanceof Finalizable) { ((Finalizable)out).finalizeStream(); } else { out.flush(); } gen.newLine(); //Just to be sure }
Generates commands to modify the current transformation matrix so an image fits into a given rectangle.
Params:
  • gen – the PostScript generator
  • imageDimensions – the image's dimensions
  • targetRect – the target rectangle
Throws:
/** * Generates commands to modify the current transformation matrix so an image fits * into a given rectangle. * @param gen the PostScript generator * @param imageDimensions the image's dimensions * @param targetRect the target rectangle * @throws IOException if an I/O error occurs */
public static void translateAndScale(PSGenerator gen, Dimension2D imageDimensions, Rectangle2D targetRect) throws IOException { gen.writeln(gen.formatDouble(targetRect.getX()) + " " + gen.formatDouble(targetRect.getY()) + " translate"); if (imageDimensions == null) { imageDimensions = new Dimension(1, 1); } double sx = targetRect.getWidth() / imageDimensions.getWidth(); double sy = targetRect.getHeight() / imageDimensions.getHeight(); if (sx != 1 || sy != 1) { gen.writeln(gen.formatDouble(sx) + " " + gen.formatDouble(sy) + " scale"); } }
Extracts a packed RGB integer array of a RenderedImage.
Params:
  • img – the image
  • startX – the starting X coordinate
  • startY – the starting Y coordinate
  • w – the width of the cropped image
  • h – the height of the cropped image
  • rgbArray – the prepared integer array to write to
  • offset – offset in the target array
  • scansize – width of a row in the target array
Returns:the populated integer array previously passed in as rgbArray parameter
/** * Extracts a packed RGB integer array of a RenderedImage. * @param img the image * @param startX the starting X coordinate * @param startY the starting Y coordinate * @param w the width of the cropped image * @param h the height of the cropped image * @param rgbArray the prepared integer array to write to * @param offset offset in the target array * @param scansize width of a row in the target array * @return the populated integer array previously passed in as rgbArray parameter */
public static int[] getRGB(RenderedImage img, int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) { Raster raster = img.getData(); int yoff = offset; int off; 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); } if (rgbArray == null) { rgbArray = new int[offset + h * scansize]; } ColorModel colorModel = img.getColorModel(); for (int y = startY; y < startY + h; y++, yoff += scansize) { off = yoff; for (int x = startX; x < startX + w; x++) { rgbArray[off++] = colorModel.getRGB(raster.getDataElements(x, y, data)); } } return rgbArray; }
Places an EPS file in the PostScript stream.
Params:
  • rawEPS – byte array containing the raw EPS data
  • name – name for the EPS document
  • x – x-coordinate of viewport in points
  • y – y-coordinate of viewport in points
  • w – width of viewport in points
  • h – height of viewport in points
  • bboxx – x-coordinate of EPS bounding box in points
  • bboxy – y-coordinate of EPS bounding box in points
  • bboxw – width of EPS bounding box in points
  • bboxh – height of EPS bounding box in points
  • gen – the PS generator
Throws:
  • IOException – in case an I/O error happens during output
Deprecated:Please use the variant with the InputStream as parameter
/** * Places an EPS file in the PostScript stream. * @param rawEPS byte array containing the raw EPS data * @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 gen the PS generator * @throws IOException in case an I/O error happens during output * @deprecated Please use the variant with the InputStream as parameter */
public static void renderEPS(byte[] rawEPS, String name, float x, float y, float w, float h, float bboxx, float bboxy, float bboxw, float bboxh, PSGenerator gen) throws IOException { renderEPS(new java.io.ByteArrayInputStream(rawEPS), name, new Rectangle2D.Float(x, y, w, h), new Rectangle2D.Float(bboxx, bboxy, bboxw, bboxh), gen); }
Places an EPS file in the PostScript stream.
Params:
  • in – the InputStream that contains the EPS stream
  • name – name for the EPS document
  • viewport – the viewport in points in which to place the EPS
  • bbox – the EPS bounding box in points
  • gen – the PS generator
Throws:
  • IOException – in case an I/O error happens during output
/** * 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 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, 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(viewport.getX()) + " " + gen.formatDouble(viewport.getY()) + " translate"); gen.writeln("0 " + gen.formatDouble(viewport.getHeight()) + " translate"); gen.writeln("1 -1 scale"); 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 (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); gen.getResourceTracker().registerSuppliedResource(res); gen.getResourceTracker().notifyResourceUsageOnPage(res); gen.writeDSCComment(DSCConstants.BEGIN_DOCUMENT, res.getName()); IOUtils.copy(in, gen.getOutputStream()); gen.newLine(); gen.writeDSCComment(DSCConstants.END_DOCUMENT); gen.writeln("EndEPSF"); gen.writeln("%AXGEndEPS"); } }