--- /dev/null
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.fop.render.pcl;
+
+import java.awt.RenderingHints;
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorConvertOp;
+import java.awt.image.RenderedImage;
+
+/**
+ * Default implementation of the MonochromeBitmapConverter which uses the Java Class Library
+ * to convert grayscale bitmaps to monochrome bitmaps.
+ */
+public class DefaultMonochromeBitmapConverter implements
+ MonochromeBitmapConverter {
+
+ /** @see MonochromeBitmapConverter#setHint(java.lang.String, java.lang.String) */
+ public void setHint(String name, String value) {
+ //ignore, not supported
+ }
+
+ /** @see MonochromeBitmapConverter#convertToMonochrome(java.awt.image.BufferedImage) */
+ public RenderedImage convertToMonochrome(BufferedImage img) {
+ BufferedImage buf = new BufferedImage(img.getWidth(), img.getHeight(),
+ BufferedImage.TYPE_BYTE_BINARY);
+ RenderingHints hints = new RenderingHints(null);
+ //This hint doesn't seem to make a difference :-(
+ hints.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
+ ColorConvertOp op = new ColorConvertOp(
+ ColorSpace.getInstance(ColorSpace.CS_GRAY), hints);
+ op.filter(img, buf);
+ return buf;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.fop.render.pcl;
+
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.IndexColorModel;
+import java.awt.image.RenderedImage;
+import java.awt.image.renderable.ParameterBlock;
+
+import javax.media.jai.ColorCube;
+import javax.media.jai.ImageLayout;
+import javax.media.jai.JAI;
+import javax.media.jai.KernelJAI;
+import javax.media.jai.LookupTableJAI;
+import javax.media.jai.PlanarImage;
+
+/**
+ * Implementation of the MonochromeBitmapConverter which uses Java Advanced Imaging (JAI)
+ * to convert grayscale bitmaps to monochrome bitmaps. JAI provides better dithering options
+ * including error diffusion dithering.
+ * <p>
+ * If you call setHint("quality", "true") on the instance you can enabled error diffusion
+ * dithering which produces a nicer result but is also a lot slower.
+ */
+public class JAIMonochromeBitmapConverter implements
+ MonochromeBitmapConverter {
+
+ private boolean isErrorDiffusion = false;
+
+ /** @see MonochromeBitmapConverter#setHint(java.lang.String, java.lang.String) */
+ public void setHint(String name, String value) {
+ if ("quality".equalsIgnoreCase(name)) {
+ isErrorDiffusion = "true".equalsIgnoreCase(value);
+ }
+ }
+
+ /** @see MonochromeBitmapConverter#convertToMonochrome(java.awt.image.BufferedImage) */
+ public RenderedImage convertToMonochrome(BufferedImage img) {
+ if (img.getColorModel().getColorSpace().getNumComponents() != 1) {
+ throw new IllegalArgumentException("Source image must be a grayscale image!");
+ }
+
+ // Load the ParameterBlock for the dithering operation
+ // and set the operation name.
+ ParameterBlock pb = new ParameterBlock();
+ pb.addSource(img);
+ String opName = null;
+ if (isErrorDiffusion) {
+ opName = "errordiffusion";
+ LookupTableJAI lut = new LookupTableJAI(new byte[] {(byte)0x00, (byte)0xff});
+ pb.add(lut);
+ pb.add(KernelJAI.ERROR_FILTER_FLOYD_STEINBERG);
+ } else {
+ opName = "ordereddither";
+ //Create the color cube.
+ ColorCube colorMap = ColorCube.createColorCube(DataBuffer.TYPE_BYTE,
+ 0, new int[] {2});
+ pb.add(colorMap);
+ pb.add(KernelJAI.DITHER_MASK_441);
+ }
+
+ //Create an image layout for a monochrome b/w image
+ ImageLayout layout = new ImageLayout();
+ byte[] map = new byte[] {(byte)0x00, (byte)0xff};
+ ColorModel cm = new IndexColorModel(1, 2, map, map, map);
+ layout.setColorModel(cm);
+
+ // Create a hint containing the layout.
+ RenderingHints hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout);
+
+ // Dither the image.
+ PlanarImage dst = JAI.create(opName, pb, hints);
+
+ //Convert it to a BufferedImage
+ return dst.getAsBufferedImage();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.fop.render.pcl;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
+
+/**
+ * Interface for converters that convert grayscale images to monochrome (1-bit) bitmap images.
+ */
+public interface MonochromeBitmapConverter {
+
+ /**
+ * Sets a hint to the implementation
+ * @param name the name of the hint
+ * @param value the value
+ */
+ void setHint(String name, String value);
+
+ /**
+ * Converts a grayscale bitmap image to a monochrome (1-bit) b/w bitmap image.
+ * @param img the grayscale image
+ * @return the converted monochrome image
+ */
+ RenderedImage convertToMonochrome(BufferedImage img);
+
+}
--- /dev/null
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.fop.render.pcl;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ByteLookupTable;
+import java.awt.image.ColorConvertOp;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.IndexColorModel;
+import java.awt.image.LookupOp;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+
+import org.apache.fop.util.UnitConv;
+import org.apache.xmlgraphics.image.GraphicsUtil;
+
+/**
+ * This class provides methods for generating PCL print files.
+ */
+public class PCLGenerator {
+
+ /** The ESC (escape) character */
+ public static final char ESC = '\033';
+
+ /** A list of all supported resolutions in PCL (values in dpi) */
+ public static final int[] PCL_RESOLUTIONS = new int[] {75, 100, 150, 200, 300, 600};
+
+ private final DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US);
+ private final DecimalFormat df2 = new DecimalFormat("0.##", symbols);
+ private final DecimalFormat df4 = new DecimalFormat("0.####", symbols);
+
+ private OutputStream out;
+
+ private boolean currentSourceTransparency = true;
+ private boolean currentPatternTransparency = true;
+
+ private int maxBitmapResolution = PCL_RESOLUTIONS[PCL_RESOLUTIONS.length - 1];
+
+ /**
+ * Main constructor.
+ * @param out the OutputStream to write the PCL stream to
+ */
+ public PCLGenerator(OutputStream out) {
+ this.out = out;
+ }
+
+ /**
+ * Main constructor.
+ * @param out the OutputStream to write the PCL stream to
+ * @param maxResolution the maximum resolution to encode bitmap images at
+ */
+ public PCLGenerator(OutputStream out, int maxResolution) {
+ this(out);
+ boolean found = false;
+ for (int i = 0; i < PCL_RESOLUTIONS.length; i++) {
+ if (PCL_RESOLUTIONS[i] == maxResolution) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ throw new IllegalArgumentException("Illegal value for maximum resolution!");
+ }
+ this.maxBitmapResolution = maxResolution;
+ }
+
+ /** @return the OutputStream that this generator writes to */
+ public OutputStream getOutputStream() {
+ return this.out;
+ }
+
+ /** @return the maximum resolution to encode bitmap images at */
+ public int getMaximumBitmapResolution() {
+ return this.maxBitmapResolution;
+ }
+
+ /**
+ * Writes a PCL escape command to the output stream.
+ * @param cmd the command (without the ESCAPE character)
+ * @throws IOException In case of an I/O error
+ */
+ public void writeCommand(String cmd) throws IOException {
+ out.write(27); //ESC
+ out.write(cmd.getBytes("US-ASCII"));
+ }
+
+ /**
+ * Writes raw text (in ISO-8859-1 encoding) to the output stream.
+ * @param s the text
+ * @throws IOException In case of an I/O error
+ */
+ public void writeText(String s) throws IOException {
+ out.write(s.getBytes("ISO-8859-1"));
+ }
+
+ /**
+ * Formats a double value with two decimal positions for PCL output.
+ *
+ * @param value value to format
+ * @return the formatted value
+ */
+ public final String formatDouble2(double value) {
+ return df2.format(value);
+ }
+
+ /**
+ * Formats a double value with four decimal positions for PCL output.
+ *
+ * @param value value to format
+ * @return the formatted value
+ */
+ public final String formatDouble4(double value) {
+ return df4.format(value);
+ }
+
+ /**
+ * Sends the universal end of language command (UEL).
+ * @throws IOException In case of an I/O error
+ */
+ public void universalEndOfLanguage() throws IOException {
+ writeCommand("%-12345X");
+ }
+
+ /**
+ * Resets the printer and restores the user default environment.
+ * @throws IOException In case of an I/O error
+ */
+ public void resetPrinter() throws IOException {
+ writeCommand("E");
+ }
+
+ /**
+ * Sends the job separation command.
+ * @throws IOException In case of an I/O error
+ */
+ public void separateJobs() throws IOException {
+ writeCommand("&l1T");
+ }
+
+ /**
+ * Sends the form feed character.
+ * @throws IOException In case of an I/O error
+ */
+ public void formFeed() throws IOException {
+ out.write(12); //=OC ("FF", Form feed)
+ }
+
+ /**
+ * Sets the unit of measure.
+ * @param value the resolution value (units per inch)
+ * @throws IOException In case of an I/O error
+ */
+ public void setUnitOfMeasure(int value) throws IOException {
+ writeCommand("&u" + value + "D");
+ }
+
+ /**
+ * Sets the raster graphics resolution
+ * @param value the resolution value (units per inch)
+ * @throws IOException In case of an I/O error
+ */
+ public void setRasterGraphicsResolution(int value) throws IOException {
+ writeCommand("*t" + value + "R");
+ }
+
+ /**
+ * Selects the page size.
+ * @param selector the integer representing the page size
+ * @throws IOException In case of an I/O error
+ */
+ public void selectPageSize(int selector) throws IOException {
+ writeCommand("&l" + selector + "A");
+ }
+
+ /**
+ * Selects the paper source. The parameter is usually printer-specific. Usually, "1" is the
+ * default tray, "2" is the manual paper feed, "3" is the manual envelope feed, "4" is the
+ * "lower" tray and "7" is "auto-select". Consult the technical reference for your printer
+ * for all available values.
+ * @param selector the integer representing the paper source/tray
+ * @throws IOException In case of an I/O error
+ */
+ public void selectPaperSource(int selector) throws IOException {
+ writeCommand("&l" + selector + "H");
+ }
+
+ /**
+ * Clears the horizontal margins.
+ * @throws IOException In case of an I/O error
+ */
+ public void clearHorizontalMargins() throws IOException {
+ writeCommand("9");
+ }
+
+ /**
+ * The Top Margin command designates the number of lines between
+ * the top of the logical page and the top of the text area.
+ * @param numberOfLines the number of lines (See PCL specification for details)
+ * @throws IOException In case of an I/O error
+ */
+ public void setTopMargin(int numberOfLines) throws IOException {
+ writeCommand("&l" + numberOfLines + "E");
+ }
+
+ /**
+ * The Text Length command can be used to define the bottom border. See the PCL specification
+ * for details.
+ * @param numberOfLines the number of lines
+ * @throws IOException In case of an I/O error
+ */
+ public void setTextLength(int numberOfLines) throws IOException {
+ writeCommand("&l" + numberOfLines + "F");
+ }
+
+ /**
+ * Sets the Vertical Motion Index (VMI).
+ * @param value the VMI value
+ * @throws IOException In case of an I/O error
+ */
+ public void setVMI(double value) throws IOException {
+ writeCommand("&l" + formatDouble4(value) + "C");
+ }
+
+ /**
+ * Sets the cursor to a new absolute coordinate.
+ * @param x the X coordinate (in millipoints)
+ * @param y the Y coordinate (in millipoints)
+ * @throws IOException In case of an I/O error
+ */
+ public void setCursorPos(double x, double y) throws IOException {
+ if (x < 0) {
+ //A negative x value will result in a relative movement so go to "0" first.
+ //But this will most probably have no effect anyway since you can't paint to the left
+ //of the logical page
+ writeCommand("&a0h" + formatDouble2(x / 100) + "h" + formatDouble2(y / 100) + "V");
+ } else {
+ writeCommand("&a" + formatDouble2(x / 100) + "h" + formatDouble2(y / 100) + "V");
+ }
+ }
+
+ /**
+ * Pushes the current cursor position on a stack (stack size: max 20 entries)
+ * @throws IOException In case of an I/O error
+ */
+ public void pushCursorPos() throws IOException {
+ writeCommand("&f0S");
+ }
+
+ /**
+ * Pops the current cursor position from the stack.
+ * @throws IOException In case of an I/O error
+ */
+ public void popCursorPos() throws IOException {
+ writeCommand("&f1S");
+ }
+
+ /**
+ * Changes the current print direction while maintaining the current cursor position.
+ * @param rotate the rotation angle (counterclockwise), one of 0, 90, 180 and 270.
+ * @throws IOException In case of an I/O error
+ */
+ public void changePrintDirection(int rotate) throws IOException {
+ writeCommand("&a" + rotate + "P");
+ }
+
+ /**
+ * Enters the HP GL/2 mode.
+ * @param restorePreviousHPGL2Cursor true if the previous HP GL/2 pen position should be
+ * restored, false if the current position is maintained
+ * @throws IOException In case of an I/O error
+ */
+ public void enterHPGL2Mode(boolean restorePreviousHPGL2Cursor) throws IOException {
+ if (restorePreviousHPGL2Cursor) {
+ writeCommand("%0B");
+ } else {
+ writeCommand("%1B");
+ }
+ }
+
+ /**
+ * Enters the PCL mode.
+ * @param restorePreviousPCLCursor true if the previous PCL cursor position should be restored,
+ * false if the current position is maintained
+ * @throws IOException In case of an I/O error
+ */
+ public void enterPCLMode(boolean restorePreviousPCLCursor) throws IOException {
+ if (restorePreviousPCLCursor) {
+ writeCommand("%0A");
+ } else {
+ writeCommand("%1A");
+ }
+ }
+
+ /**
+ * Generate a filled rectangle at the current cursor position.
+ *
+ * @param w the width in millipoints
+ * @param h the height in millipoints
+ * @param col the fill color
+ * @throws IOException In case of an I/O error
+ */
+ protected void fillRect(int w, int h, Color col) throws IOException {
+ if ((w == 0) || (h == 0)) {
+ return;
+ }
+ if (h < 0) {
+ h *= -1;
+ } else {
+ //y += h;
+ }
+
+ setPatternTransparencyMode(false);
+ writeCommand("*c" + formatDouble4(w / 100) + "h"
+ + formatDouble4(h / 100) + "V");
+ int lineshade = convertToPCLShade(col);
+ writeCommand("*c" + lineshade + "G");
+ writeCommand("*c2P");
+ // Reset pattern transparency mode.
+ setPatternTransparencyMode(true);
+ }
+
+ /**
+ * Sets the source transparency mode.
+ * @param transparent true if transparent, false for opaque
+ * @throws IOException In case of an I/O error
+ */
+ public void setSourceTransparencyMode(boolean transparent) throws IOException {
+ setTransparencyMode(transparent, currentPatternTransparency);
+ }
+
+ /**
+ * Sets the pattern transparency mode.
+ * @param transparent true if transparent, false for opaque
+ * @throws IOException In case of an I/O error
+ */
+ public void setPatternTransparencyMode(boolean transparent) throws IOException {
+ setTransparencyMode(currentSourceTransparency, transparent);
+ }
+
+ /**
+ * Sets the transparency modes.
+ * @param source source transparency: true if transparent, false for opaque
+ * @param pattern pattern transparency: true if transparent, false for opaque
+ * @throws IOException In case of an I/O error
+ */
+ public void setTransparencyMode(boolean source, boolean pattern) throws IOException {
+ if (source != currentSourceTransparency && pattern != currentPatternTransparency) {
+ writeCommand("*v" + (source ? '0' : '1') + "n" + (pattern ? '0' : '1') + "O");
+ } else if (source != currentSourceTransparency) {
+ writeCommand("*v" + (source ? '0' : '1') + "N");
+ } else if (pattern != currentPatternTransparency) {
+ writeCommand("*v" + (pattern ? '0' : '1') + "O");
+ }
+ this.currentSourceTransparency = source;
+ this.currentPatternTransparency = pattern;
+ }
+
+ /**
+ * Convert an RGB color value to a grayscale from 0 to 100.
+ * @param r the red component
+ * @param g the green component
+ * @param b the blue component
+ * @return the gray value
+ */
+ public final int convertToGray(int r, int g, int b) {
+ return (r * 30 + g * 59 + b * 11) / 100;
+ }
+
+ /**
+ * Convert a Color value to a PCL shade value (0-100).
+ * @param col the color
+ * @return the PCL shade value (100=black)
+ */
+ public final int convertToPCLShade(Color col) {
+ float gray = convertToGray(col.getRed(), col.getGreen(), col.getBlue()) / 255f;
+ return (int)(100 - (gray * 100f));
+ }
+
+ /**
+ * Select the current pattern
+ * @param patternID the pattern ID (<ESC>*c#G command)
+ * @param pattern the pattern type (<ESC>*v#T command)
+ * @throws IOException In case of an I/O error
+ */
+ public void selectCurrentPattern(int patternID, int pattern) throws IOException {
+ if (pattern > 1) {
+ writeCommand("*c" + patternID + "G");
+ }
+ writeCommand("*v" + pattern + "T");
+ }
+
+ /**
+ * Indicates whether an image is a monochrome (b/w) image.
+ * @param img the image
+ * @return true if it's a monochrome image
+ */
+ public static boolean isMonochromeImage(RenderedImage img) {
+ ColorModel cm = img.getColorModel();
+ if (cm instanceof IndexColorModel) {
+ IndexColorModel icm = (IndexColorModel)cm;
+ return icm.getMapSize() == 2;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Indicates whether an image is a grayscale image.
+ * @param img the image
+ * @return true if it's a grayscale image
+ */
+ public static boolean isGrayscaleImage(RenderedImage img) {
+ return (img.getColorModel().getColorSpace().getNumComponents() == 1);
+ }
+
+ private MonochromeBitmapConverter createMonochromeBitmapConverter() {
+ MonochromeBitmapConverter converter = null;
+ try {
+ String clName = "org.apache.fop.render.pcl.JAIMonochromeBitmapConverter";
+ Class clazz = Class.forName(clName);
+ converter = (MonochromeBitmapConverter)clazz.newInstance();
+ } catch (ClassNotFoundException cnfe) {
+ // Class was not compiled so is not available. Simply ignore.
+ } catch (LinkageError le) {
+ // This can happen if fop was build with support for a
+ // particular provider (e.g. a binary fop distribution)
+ // but the required support files (i.e. JAI) are not
+ // available in the current runtime environment.
+ // Simply continue with the backup implementation.
+ } catch (InstantiationException e) {
+ // Problem instantiating the class, simply continue with the backup implementation
+ } catch (IllegalAccessException e) {
+ // Problem instantiating the class, simply continue with the backup implementation
+ }
+ if (converter == null) {
+ converter = new DefaultMonochromeBitmapConverter();
+ }
+ return converter;
+ }
+
+ private int calculatePCLResolution(int resolution) {
+ return calculatePCLResolution(resolution, false);
+ }
+
+ /**
+ * Calculates the ideal PCL resolution for a given resolution.
+ * @param resolution the input resolution
+ * @param increased true if you want to go to a higher resolution, for example if you
+ * convert grayscale or color images to monochrome images so dithering has
+ * a chance to generate better quality.
+ * @return the resulting PCL resolution (one of 75, 100, 150, 200, 300, 600)
+ */
+ private int calculatePCLResolution(int resolution, boolean increased) {
+ int choice = -1;
+ for (int i = PCL_RESOLUTIONS.length - 2; i >= 0; i--) {
+ if (resolution > PCL_RESOLUTIONS[i]) {
+ int idx = i + 1;
+ if (idx < PCL_RESOLUTIONS.length - 2) {
+ idx += increased ? 2 : 0;
+ } else if (idx < PCL_RESOLUTIONS.length - 1) {
+ idx += increased ? 1 : 0;
+ }
+ choice = idx;
+ break;
+ //return PCL_RESOLUTIONS[idx];
+ }
+ }
+ if (choice < 0) {
+ choice = (increased ? 2 : 0);
+ }
+ while (choice > 0 && PCL_RESOLUTIONS[choice] > getMaximumBitmapResolution()) {
+ choice--;
+ }
+ return PCL_RESOLUTIONS[choice];
+ }
+
+ private boolean isValidPCLResolution(int resolution) {
+ return resolution == calculatePCLResolution(resolution);
+ }
+
+ private Dimension getAdjustedDimension(Dimension orgDim, double orgResolution,
+ int pclResolution) {
+ if (orgResolution == pclResolution) {
+ return orgDim;
+ } else {
+ Dimension result = new Dimension();
+ result.width = (int)Math.round((double)orgDim.width * pclResolution / orgResolution);
+ result.height = (int)Math.round((double)orgDim.height * pclResolution / orgResolution);
+ return result;
+ }
+ }
+
+ //Threshold table to convert an alpha channel (8-bit) into a clip mask (1-bit)
+ private static final byte[] THRESHOLD_TABLE = new byte[256];
+ static { // Initialize the arrays
+ for (int i = 0; i < 256; i++) {
+ THRESHOLD_TABLE[i] = (byte) ((i < 240) ? 255 : 0);
+ }
+ }
+
+ private RenderedImage getMask(RenderedImage img, Dimension targetDim) {
+ ColorModel cm = img.getColorModel();
+ if (cm.hasAlpha()) {
+ BufferedImage alpha = new BufferedImage(img.getWidth(), img.getHeight(),
+ BufferedImage.TYPE_BYTE_GRAY);
+ Raster raster = img.getData();
+ GraphicsUtil.copyBand(raster, cm.getNumColorComponents(), alpha.getRaster(), 0);
+
+ BufferedImageOp op1 = new LookupOp(new ByteLookupTable(0, THRESHOLD_TABLE), null);
+ BufferedImage alphat = op1.filter(alpha, null);
+
+ BufferedImage mask;
+ if (true) {
+ mask = new BufferedImage(targetDim.width, targetDim.height,
+ BufferedImage.TYPE_BYTE_BINARY);
+ } else {
+ byte[] arr = {(byte)0, (byte)0xff};
+ ColorModel colorModel = new IndexColorModel(1, 2, arr, arr, arr);
+ WritableRaster wraster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
+ targetDim.width, targetDim.height, 1, 1, null);
+ mask = new BufferedImage(colorModel, wraster, false, null);
+ }
+
+ Graphics2D g2d = mask.createGraphics();
+ try {
+ AffineTransform at = new AffineTransform();
+ double sx = targetDim.getWidth() / img.getWidth();
+ double sy = targetDim.getHeight() / img.getHeight();
+ at.scale(sx, sy);
+ g2d.drawRenderedImage(alphat, at);
+ } finally {
+ g2d.dispose();
+ }
+ /*
+ try {
+ BatchDiffer.saveAsPNG(alpha, new java.io.File("D:/out-alpha.png"));
+ BatchDiffer.saveAsPNG(mask, new java.io.File("D:/out-mask.png"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }*/
+ return mask;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Paint a bitmap at the current cursor position. The bitmap is converted to a monochrome
+ * (1-bit) bitmap image.
+ * @param img the bitmap image
+ * @param targetDim the target Dimention (in mpt)
+ * @param sourceTransparency true if the background should not be erased
+ * @throws IOException In case of an I/O error
+ */
+ public void paintBitmap(RenderedImage img, Dimension targetDim, boolean sourceTransparency)
+ throws IOException {
+ double targetResolution = img.getWidth() / UnitConv.mpt2in(targetDim.width);
+ int resolution = (int)Math.round(targetResolution);
+ int effResolution = calculatePCLResolution(resolution, true);
+ Dimension orgDim = new Dimension(img.getWidth(), img.getHeight());
+ Dimension effDim = getAdjustedDimension(orgDim, targetResolution, effResolution);
+ boolean scaled = !orgDim.equals(effDim);
+
+ boolean monochrome = isMonochromeImage(img);
+ if (!monochrome) {
+ //Transparency mask disabled. Doesn't work reliably
+ final boolean transparencyDisabled = true;
+ RenderedImage mask = (transparencyDisabled ? null : getMask(img, effDim));
+ if (mask != null) {
+ pushCursorPos();
+ selectCurrentPattern(0, 1); //Solid white
+ setTransparencyMode(true, true);
+ paintMonochromeBitmap(mask, effResolution);
+ popCursorPos();
+ }
+
+ BufferedImage src = null;
+ if (img instanceof BufferedImage && !scaled) {
+ if (!isGrayscaleImage(img) || img.getColorModel().hasAlpha()) {
+ src = new BufferedImage(effDim.width, effDim.height,
+ BufferedImage.TYPE_BYTE_GRAY);
+ ColorConvertOp op = new ColorConvertOp(
+ ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
+ op.filter((BufferedImage)img, src);
+ } else {
+ src = (BufferedImage)img;
+ }
+ }
+ if (src == null) {
+ src = new BufferedImage(effDim.width, effDim.height,
+ BufferedImage.TYPE_BYTE_GRAY);
+ Graphics2D g2d = src.createGraphics();
+ try {
+ AffineTransform at = new AffineTransform();
+ double sx = effDim.getWidth() / orgDim.getWidth();
+ double sy = effDim.getHeight() / orgDim.getHeight();
+ at.scale(sx, sy);
+ g2d.drawRenderedImage(img, at);
+ } finally {
+ g2d.dispose();
+ }
+ }
+ MonochromeBitmapConverter converter = createMonochromeBitmapConverter();
+ converter.setHint("quality", "false");
+
+ BufferedImage buf = (BufferedImage)converter.convertToMonochrome(src);
+
+ RenderedImage red = buf;
+ selectCurrentPattern(0, 0); //Solid black
+ setTransparencyMode(sourceTransparency || mask != null, true);
+ paintMonochromeBitmap(red, effResolution);
+ } else {
+ //TODO untested!
+ RenderedImage effImg = img;
+ if (scaled) {
+ BufferedImage buf = new BufferedImage(effDim.width, effDim.height,
+ BufferedImage.TYPE_BYTE_BINARY);
+ Graphics2D g2d = buf.createGraphics();
+ try {
+ AffineTransform at = new AffineTransform();
+ double sx = effDim.getWidth() / orgDim.getWidth();
+ double sy = effDim.getHeight() / orgDim.getHeight();
+ at.scale(sx, sy);
+ g2d.drawRenderedImage(img, at);
+ } finally {
+ g2d.dispose();
+ }
+ effImg = buf;
+ }
+ setSourceTransparencyMode(sourceTransparency);
+ selectCurrentPattern(0, 0); //Solid black
+ paintMonochromeBitmap(effImg, effResolution);
+ }
+ }
+
+ /**
+ * Paint a bitmap at the current cursor position. The bitmap must be a monochrome
+ * (1-bit) bitmap image.
+ * @param img the bitmap image (must be 1-bit b/w)
+ * @param resolution the resolution of the image (must be a PCL resolution)
+ * @throws IOException In case of an I/O error
+ */
+ public void paintMonochromeBitmap(RenderedImage img, int resolution) throws IOException {
+ if (!isValidPCLResolution(resolution)) {
+ throw new IllegalArgumentException("Invalid PCL resolution: " + resolution);
+ }
+ setRasterGraphicsResolution(resolution);
+ writeCommand("*r0f" + img.getHeight() + "t" + img.getWidth() + "s1A");
+ Raster raster = img.getData();
+ boolean monochrome = isMonochromeImage(img);
+ if (!monochrome) {
+ throw new IllegalArgumentException("img must be a monochrome image");
+ }
+
+ int x = 0;
+ int y = 0;
+ int imgw = img.getWidth();
+ int imgh = img.getHeight();
+ int bytewidth = (imgw / 8);
+ if ((imgw % 8) != 0) {
+ bytewidth++;
+ }
+ byte ib;
+ byte[] rle = new byte[bytewidth * 2]; //compressed (RLE)
+ byte[] uncompressed = new byte[bytewidth]; //uncompressed
+ int lastcount = -1;
+ byte lastbyte = 0;
+ int rlewidth = 0;
+
+ // Transfer graphics data
+ for (y = 0; y < imgh; y++) {
+ ib = 0;
+ for (x = 0; x < imgw; x++) {
+ int sample = raster.getSample(x, y, 0);
+ //Set image bit for black
+ if ((sample == 0)) {
+ ib |= (1 << (7 - (x % 8)));
+ }
+
+ //RLE encoding
+ if ((x % 8) == 7 || ((x + 1) == imgw)) {
+ if (rlewidth < bytewidth) {
+ if (lastcount >= 0) {
+ if (ib == lastbyte) {
+ lastcount++;
+ } else {
+ rle[rlewidth++] = (byte)(lastcount & 0xFF);
+ rle[rlewidth++] = lastbyte;
+ lastbyte = ib;
+ lastcount = 0;
+ }
+ } else {
+ lastbyte = ib;
+ lastcount = 0;
+ }
+ if (lastcount == 255 || ((x + 1) == imgw)) {
+ rle[rlewidth++] = (byte)(lastcount & 0xFF);
+ rle[rlewidth++] = lastbyte;
+ lastbyte = 0;
+ lastcount = -1;
+ }
+ }
+ uncompressed[x / 8] = ib;
+ ib = 0;
+ }
+ }
+ if (rlewidth < bytewidth) {
+ writeCommand("*b1m" + rlewidth + "W");
+ this.out.write(rle, 0, rlewidth);
+ } else {
+ writeCommand("*b0m" + bytewidth + "W");
+ this.out.write(uncompressed);
+ }
+ lastcount = -1;
+ rlewidth = 0;
+ }
+
+ // End raster graphics
+ writeCommand("*rB");
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.fop.render.pcl;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ImageObserver;
+import java.awt.image.RenderedImage;
+import java.awt.image.renderable.RenderableImage;
+import java.io.IOException;
+import java.text.AttributedCharacterIterator;
+
+import org.apache.fop.util.UnitConv;
+import org.apache.xmlgraphics.java2d.AbstractGraphics2D;
+import org.apache.xmlgraphics.java2d.GraphicContext;
+
+/**
+ * Graphics2D implementation implementing PCL and HP GL/2.
+ * Note: This class cannot be used stand-alone to create full PCL documents.
+ */
+public class PCLGraphics2D extends AbstractGraphics2D {
+
+ /** The PCL generator */
+ protected PCLGenerator gen;
+
+ private boolean failOnUnsupportedFeature = true;
+ private boolean clippingDisabled = false;
+
+ /**
+ * Create a new PCLGraphics2D.
+ * @param gen the PCL Generator to paint with
+ */
+ public PCLGraphics2D(PCLGenerator gen) {
+ super(true);
+ this.gen = gen;
+ }
+
+ /**
+ * Copy constructor
+ * @param g parent PCLGraphics2D
+ */
+ public PCLGraphics2D(PCLGraphics2D g) {
+ super(true);
+ this.gen = g.gen;
+ }
+
+ /** @see java.awt.Graphics#create() */
+ public Graphics create() {
+ PCLGraphics2D copy = new PCLGraphics2D(this);
+ copy.setGraphicContext((GraphicContext)getGraphicContext().clone());
+ return copy;
+ }
+
+ /** @see java.awt.Graphics#dispose() */
+ public void dispose() {
+ this.gen = null;
+ }
+
+ /**
+ * Sets the GraphicContext
+ * @param c GraphicContext to use
+ */
+ public void setGraphicContext(GraphicContext c) {
+ this.gc = c;
+ }
+
+ /**
+ * Allows to disable all clipping operations.
+ * @param value true if clipping should be disabled.
+ */
+ public void setClippingDisabled(boolean value) {
+ this.clippingDisabled = value;
+ }
+
+ /**
+ * Central handler for IOExceptions for this class.
+ * @param ioe IOException to handle
+ */
+ public void handleIOException(IOException ioe) {
+ //TODO Surely, there's a better way to do this.
+ ioe.printStackTrace();
+ }
+
+ /**
+ * Raises an UnsupportedOperationException if this instance is configured to do so and an
+ * unsupported feature has been requested. Clients can make use of this to fall back to
+ * a more compatible way of painting a PCL graphic.
+ * @param msg the error message to be displayed
+ */
+ protected void handleUnsupportedFeature(String msg) {
+ if (this.failOnUnsupportedFeature) {
+ throw new UnsupportedOperationException(msg);
+ }
+ }
+
+ /** @see java.awt.Graphics2D#getDeviceConfiguration() */
+ public GraphicsConfiguration getDeviceConfiguration() {
+ return GraphicsEnvironment.getLocalGraphicsEnvironment().
+ getDefaultScreenDevice().getDefaultConfiguration();
+ }
+
+ /**
+ * Applies a new Stroke object.
+ * @param stroke Stroke object to use
+ * @throws IOException In case of an I/O problem
+ */
+ protected void applyStroke(Stroke stroke) throws IOException {
+ if (stroke instanceof BasicStroke) {
+ BasicStroke bs = (BasicStroke)stroke;
+
+ float[] da = bs.getDashArray();
+ if (da != null) {
+
+ gen.writeText("UL1,");
+ int len = Math.min(20, da.length);
+ float patternLen = 0.0f;
+ for (int idx = 0; idx < len; idx++) {
+ patternLen += da[idx];
+ }
+ if (len == 1) {
+ patternLen *= 2;
+ }
+ for (int idx = 0; idx < len; idx++) {
+ float perc = da[idx] * 100 / patternLen;
+ gen.writeText(gen.formatDouble2(perc));
+ if (idx < da.length - 1) {
+ gen.writeText(",");
+ }
+ }
+ if (len == 1) {
+ gen.writeText("," + gen.formatDouble2(da[0] * 100 / patternLen ));
+
+ }
+ gen.writeText(";");
+ /* TODO Dash phase NYI
+ float offset = bs.getDashPhase();
+ gen.writeln(gen.formatDouble4(offset) + " setdash");
+ */
+ Point2D ptLen = new Point2D.Double(patternLen, 0);
+ //interpret as absolute length
+ getTransform().deltaTransform(ptLen, ptLen);
+ double transLen = UnitConv.pt2mm(ptLen.distance(0, 0));
+ gen.writeText("LT1," + gen.formatDouble4(transLen) + ",1;");
+ } else {
+ gen.writeText("LT;");
+ }
+
+ gen.writeText("LA1"); //line cap
+ int ec = bs.getEndCap();
+ switch (ec) {
+ case BasicStroke.CAP_BUTT:
+ gen.writeText(",1");
+ break;
+ case BasicStroke.CAP_ROUND:
+ gen.writeText(",4");
+ break;
+ case BasicStroke.CAP_SQUARE:
+ gen.writeText(",2");
+ break;
+ default: System.err.println("Unsupported line cap: " + ec);
+ }
+
+ gen.writeText(",2"); //line join
+ int lj = bs.getLineJoin();
+ switch (lj) {
+ case BasicStroke.JOIN_MITER:
+ gen.writeText(",1");
+ break;
+ case BasicStroke.JOIN_ROUND:
+ gen.writeText(",4");
+ break;
+ case BasicStroke.JOIN_BEVEL:
+ gen.writeText(",5");
+ break;
+ default: System.err.println("Unsupported line join: " + lj);
+ }
+
+ float ml = bs.getMiterLimit();
+ gen.writeText(",3" + gen.formatDouble4(ml));
+
+ float lw = bs.getLineWidth();
+ Point2D ptSrc = new Point2D.Double(lw, 0);
+ //Pen widths are set as absolute metric values (WU0;)
+ Point2D ptDest = getTransform().deltaTransform(ptSrc, null);
+ double transDist = UnitConv.pt2mm(ptDest.distance(0, 0));
+ //System.out.println("--" + ptDest.distance(0, 0) + " " + transDist);
+ gen.writeText(";PW" + gen.formatDouble4(transDist) + ";");
+
+ } else {
+ handleUnsupportedFeature("Unsupported Stroke: " + stroke.getClass().getName());
+ }
+ }
+
+ /**
+ * Applies a new Paint object.
+ * @param paint Paint object to use
+ * @throws IOException In case of an I/O problem
+ */
+ protected void applyPaint(Paint paint) throws IOException {
+ if (paint instanceof Color) {
+ Color col = (Color)paint;
+ int shade = gen.convertToPCLShade(col);
+ gen.writeText("TR0;FT10," + shade + ";");
+ } else {
+ handleUnsupportedFeature("Unsupported Paint: " + paint.getClass().getName());
+ }
+ }
+
+ private void writeClip(Shape imclip) throws IOException {
+ if (clippingDisabled) {
+ return;
+ }
+ if (imclip == null) {
+ //gen.writeText("IW;");
+ } else {
+ handleUnsupportedFeature("Clipping is not supported. Shape: " + imclip);
+ /* This is an attempt to clip using the "InputWindow" (IW) but this only allows to
+ * clip a rectangular area. Force falling back to bitmap mode for now.
+ Rectangle2D bounds = imclip.getBounds2D();
+ Point2D p1 = new Point2D.Double(bounds.getX(), bounds.getY());
+ Point2D p2 = new Point2D.Double(
+ bounds.getX() + bounds.getWidth(), bounds.getY() + bounds.getHeight());
+ getTransform().transform(p1, p1);
+ getTransform().transform(p2, p2);
+ gen.writeText("IW" + gen.formatDouble4(p1.getX())
+ + "," + gen.formatDouble4(p2.getY())
+ + "," + gen.formatDouble4(p2.getX())
+ + "," + gen.formatDouble4(p1.getY()) + ";");
+ */
+ }
+ }
+
+ /** @see java.awt.Graphics2D#draw(java.awt.Shape) */
+ public void draw(Shape s) {
+ try {
+ AffineTransform trans = getTransform();
+
+ Shape imclip = getClip();
+ writeClip(imclip);
+
+ if (!Color.black.equals(getColor())) {
+ //TODO PCL 5 doesn't support colored pens, PCL5c has a pen color (PC) command
+ handleUnsupportedFeature("Only black is supported as stroke color: " + getColor());
+ }
+ applyStroke(getStroke());
+
+ PathIterator iter = s.getPathIterator(trans);
+ processPathIteratorStroke(iter);
+ writeClip(null);
+ } catch (IOException ioe) {
+ handleIOException(ioe);
+ }
+ }
+
+ /** @see java.awt.Graphics2D#fill(java.awt.Shape) */
+ public void fill(Shape s) {
+ try {
+ AffineTransform trans = getTransform();
+ Shape imclip = getClip();
+ writeClip(imclip);
+
+ applyPaint(getPaint());
+
+ PathIterator iter = s.getPathIterator(trans);
+ processPathIteratorFill(iter);
+ writeClip(null);
+ } catch (IOException ioe) {
+ handleIOException(ioe);
+ }
+ }
+
+ /**
+ * Processes a path iterator generating the nexessary painting operations.
+ * @param iter PathIterator to process
+ * @throws IOException In case of an I/O problem.
+ */
+ public void processPathIteratorStroke(PathIterator iter) throws IOException {
+ gen.writeText("\n");
+ double[] vals = new double[6];
+ boolean penDown = false;
+ double x = 0;
+ double y = 0;
+ StringBuffer sb = new StringBuffer(256);
+ penUp(sb);
+ while (!iter.isDone()) {
+ int type = iter.currentSegment(vals);
+ if (type == PathIterator.SEG_CLOSE) {
+ gen.writeText("PM;");
+ gen.writeText(sb.toString());
+ gen.writeText("PM2;EP;");
+ sb.setLength(0);
+ iter.next();
+ continue;
+ } else if (type == PathIterator.SEG_MOVETO) {
+ gen.writeText(sb.toString());
+ sb.setLength(0);
+ if (penDown) {
+ penUp(sb);
+ penDown = false;
+ }
+ } else {
+ if (!penDown) {
+ penDown(sb);
+ penDown = true;
+ }
+ }
+ switch (type) {
+ case PathIterator.SEG_CLOSE:
+ break;
+ case PathIterator.SEG_MOVETO:
+ x = vals[0];
+ y = vals[1];
+ plotAbsolute(x, y, sb);
+ gen.writeText(sb.toString());
+ sb.setLength(0);
+ break;
+ case PathIterator.SEG_LINETO:
+ x = vals[0];
+ y = vals[1];
+ plotAbsolute(x, y, sb);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ x = vals[4];
+ y = vals[5];
+ bezierAbsolute(vals[0], vals[1], vals[2], vals[3], x, y, sb);
+ break;
+ case PathIterator.SEG_QUADTO:
+ double originX = x;
+ double originY = y;
+ x = vals[2];
+ y = vals[3];
+ quadraticBezierAbsolute(originX, originY, vals[0], vals[1], x, y, sb);
+ break;
+ default:
+ break;
+ }
+ iter.next();
+ }
+ sb.append("\n");
+ gen.writeText(sb.toString());
+ }
+
+ /**
+ * Processes a path iterator generating the nexessary painting operations.
+ * @param iter PathIterator to process
+ * @throws IOException In case of an I/O problem.
+ */
+ public void processPathIteratorFill(PathIterator iter) throws IOException {
+ gen.writeText("\n");
+ double[] vals = new double[6];
+ boolean penDown = false;
+ double x = 0;
+ double y = 0;
+ boolean pendingPM0 = true;
+ StringBuffer sb = new StringBuffer(256);
+ penUp(sb);
+ while (!iter.isDone()) {
+ int type = iter.currentSegment(vals);
+ if (type == PathIterator.SEG_CLOSE) {
+ sb.append("PM1;");
+ iter.next();
+ continue;
+ } else if (type == PathIterator.SEG_MOVETO) {
+ if (penDown) {
+ penUp(sb);
+ penDown = false;
+ }
+ } else {
+ if (!penDown) {
+ penDown(sb);
+ penDown = true;
+ }
+ }
+ switch (type) {
+ case PathIterator.SEG_MOVETO:
+ x = vals[0];
+ y = vals[1];
+ plotAbsolute(x, y, sb);
+ break;
+ case PathIterator.SEG_LINETO:
+ x = vals[0];
+ y = vals[1];
+ plotAbsolute(x, y, sb);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ x = vals[4];
+ y = vals[5];
+ bezierAbsolute(vals[0], vals[1], vals[2], vals[3], x, y, sb);
+ break;
+ case PathIterator.SEG_QUADTO:
+ double originX = x;
+ double originY = y;
+ x = vals[2];
+ y = vals[3];
+ quadraticBezierAbsolute(originX, originY, vals[0], vals[1], x, y, sb);
+ break;
+ default:
+ throw new IllegalStateException("Must not get here");
+ }
+ if (pendingPM0) {
+ pendingPM0 = false;
+ sb.append("PM;");
+ }
+ iter.next();
+ }
+ sb.append("PM2;");
+ fillPolygon(iter.getWindingRule(), sb);
+ sb.append("\n");
+ gen.writeText(sb.toString());
+ }
+
+ private void fillPolygon(int windingRule, StringBuffer sb) {
+ int fillMethod = (windingRule == PathIterator.WIND_EVEN_ODD ? 0 : 1);
+ sb.append("FP").append(fillMethod).append(";");
+ }
+
+ private void plotAbsolute(double x, double y, StringBuffer sb) {
+ sb.append("PA").append(gen.formatDouble4(x));
+ sb.append(",").append(gen.formatDouble4(y)).append(";");
+ }
+
+ private void bezierAbsolute(double x1, double y1, double x2, double y2, double x3, double y3,
+ StringBuffer sb) {
+ sb.append("BZ").append(gen.formatDouble4(x1));
+ sb.append(",").append(gen.formatDouble4(y1));
+ sb.append(",").append(gen.formatDouble4(x2));
+ sb.append(",").append(gen.formatDouble4(y2));
+ sb.append(",").append(gen.formatDouble4(x3));
+ sb.append(",").append(gen.formatDouble4(y3)).append(";");
+ }
+
+ private void quadraticBezierAbsolute(double originX, double originY,
+ double x1, double y1, double x2, double y2, StringBuffer sb) {
+ //Quadratic Bezier curve can be mapped to a normal bezier curve
+ //See http://pfaedit.sourceforge.net/bezier.html
+ double nx1 = originX + (2.0 / 3.0) * (x1 - originX);
+ double ny1 = originY + (2.0 / 3.0) * (y1 - originY);
+
+ double nx2 = nx1 + (1.0 / 3.0) * (x2 - originX);
+ double ny2 = ny1 + (1.0 / 3.0) * (y2 - originY);
+
+ bezierAbsolute(nx1, ny1, nx2, ny2, x2, y2, sb);
+ }
+
+ private void penDown(StringBuffer sb) {
+ sb.append("PD;");
+ }
+
+ private void penUp(StringBuffer sb) {
+ sb.append("PU;");
+ }
+
+ /** @see java.awt.Graphics2D#drawString(java.lang.String, float, float) */
+ public void drawString(String s, float x, float y) {
+ java.awt.Font awtFont = getFont();
+ FontRenderContext frc = getFontRenderContext();
+ GlyphVector gv = awtFont.createGlyphVector(frc, s);
+ Shape glyphOutline = gv.getOutline(x, y);
+ fill(glyphOutline);
+ }
+
+ /** @see java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float) */
+ public void drawString(AttributedCharacterIterator iterator, float x,
+ float y) {
+ // TODO Auto-generated method stub
+ handleUnsupportedFeature("drawString NYI");
+ }
+
+ /**
+ * @see java.awt.Graphics2D#drawRenderedImage(java.awt.image.RenderedImage,
+ * java.awt.geom.AffineTransform)
+ */
+ public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
+ handleUnsupportedFeature("Bitmap images are not supported");
+ }
+
+ /**
+ * @see java.awt.Graphics2D#drawRenderableImage(java.awt.image.renderable.RenderableImage,
+ * java.awt.geom.AffineTransform)
+ */
+ public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
+ handleUnsupportedFeature("Bitmap images are not supported");
+ }
+
+ /**
+ * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, int, int,
+ * java.awt.image.ImageObserver)
+ */
+ public boolean drawImage(Image img, int x, int y, int width, int height,
+ ImageObserver observer) {
+ handleUnsupportedFeature("Bitmap images are not supported");
+ return false;
+ }
+
+ /**
+ * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, java.awt.image.ImageObserver)
+ */
+ public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
+ handleUnsupportedFeature("Bitmap images are not supported");
+ return false;
+ /*
+ * First attempt disabled.
+ * Reasons: Lack of transparency control, positioning and rotation issues
+ final int width = img.getWidth(observer);
+ final int height = img.getHeight(observer);
+ if (width == -1 || height == -1) {
+ return false;
+ }
+
+ Dimension size = new Dimension(width, height);
+ BufferedImage buf = buildBufferedImage(size);
+
+ java.awt.Graphics2D g = buf.createGraphics();
+ try {
+ g.setComposite(AlphaComposite.SrcOver);
+ g.setBackground(new Color(255, 255, 255));
+ g.setPaint(new Color(255, 255, 255));
+ g.fillRect(0, 0, width, height);
+ g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight()));
+
+ if (!g.drawImage(img, 0, 0, observer)) {
+ return false;
+ }
+ } finally {
+ g.dispose();
+ }
+
+ try {
+ AffineTransform at = getTransform();
+ gen.enterPCLMode(false);
+ //Shape imclip = getClip(); Clipping is not available in PCL
+ Point2D p1 = new Point2D.Double(x, y);
+ at.transform(p1, p1);
+ pclContext.getTransform().transform(p1, p1);
+ gen.setCursorPos(p1.getX(), p1.getY());
+ gen.paintBitmap(buf, 72);
+ gen.enterHPGL2Mode(false);
+ } catch (IOException ioe) {
+ handleIOException(ioe);
+ }
+
+ return true;*/
+ }
+
+ /** @see java.awt.Graphics#copyArea(int, int, int, int, int, int) */
+ public void copyArea(int x, int y, int width, int height, int dx, int dy) {
+ // TODO Auto-generated method stub
+ handleUnsupportedFeature("copyArea NYI");
+ }
+
+ /** @see java.awt.Graphics#setXORMode(java.awt.Color) */
+ public void setXORMode(Color c1) {
+ // TODO Auto-generated method stub
+ handleUnsupportedFeature("setXORMode NYI");
+ }
+
+ /**
+ * Used to create proper font metrics
+ */
+ private Graphics2D fmg;
+
+ {
+ BufferedImage bi = new BufferedImage(1, 1,
+ BufferedImage.TYPE_INT_ARGB);
+
+ fmg = bi.createGraphics();
+ }
+
+ /**
+ * Creates a buffered image.
+ * @param size dimensions of the image to be created
+ * @return the buffered image
+ */
+ protected BufferedImage buildBufferedImage(Dimension size) {
+ return new BufferedImage(size.width, size.height,
+ BufferedImage.TYPE_BYTE_GRAY);
+ }
+
+ /** @see java.awt.Graphics#getFontMetrics(java.awt.Font) */
+ public java.awt.FontMetrics getFontMetrics(java.awt.Font f) {
+ return fmg.getFontMetrics(f);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.fop.render.pcl;
+
+import java.awt.Dimension;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fop.render.AbstractGraphics2DAdapter;
+import org.apache.fop.render.Graphics2DImagePainter;
+import org.apache.fop.render.RendererContext;
+import org.apache.fop.util.UnitConv;
+import org.apache.xmlgraphics.java2d.GraphicContext;
+
+/**
+ * Graphics2DAdapter implementation for PCL and HP GL/2.
+ */
+public class PCLGraphics2DAdapter extends AbstractGraphics2DAdapter {
+
+ /** logging instance */
+ private static Log log = LogFactory.getLog(PCLGraphics2DAdapter.class);
+
+ /**
+ * Main constructor
+ */
+ public PCLGraphics2DAdapter() {
+ }
+
+ /** @see org.apache.fop.render.Graphics2DAdapter */
+ public void paintImage(Graphics2DImagePainter painter,
+ RendererContext context,
+ int x, int y, int width, int height) throws IOException {
+ PCLRendererContext pclContext = PCLRendererContext.wrapRendererContext(context);
+ PCLRenderer pcl = (PCLRenderer)context.getRenderer();
+ PCLGenerator gen = pcl.gen;
+
+ // get the 'width' and 'height' attributes of the image/document
+ Dimension dim = painter.getImageSize();
+ float imw = (float)dim.getWidth();
+ float imh = (float)dim.getHeight();
+
+ boolean painted = false;
+ boolean paintAsBitmap = pclContext.paintAsBitmap();
+ if (!paintAsBitmap) {
+ ByteArrayOutputStream baout = new ByteArrayOutputStream();
+ PCLGenerator tempGen = new PCLGenerator(baout, gen.getMaximumBitmapResolution());
+ try {
+ GraphicContext ctx = (GraphicContext)pcl.getGraphicContext().clone();
+
+ AffineTransform prepareHPGL2 = new AffineTransform();
+ prepareHPGL2.scale(0.001, 0.001);
+ ctx.setTransform(prepareHPGL2);
+
+ PCLGraphics2D graphics = new PCLGraphics2D(tempGen);
+ graphics.setGraphicContext(ctx);
+ graphics.setClippingDisabled(pclContext.isClippingDisabled());
+ Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
+ painter.paint(graphics, area);
+
+ //If we arrive here, the graphic is natively paintable, so write the graphic
+ pcl.saveGraphicsState();
+ pcl.setCursorPos(x, y);
+ gen.writeCommand("*c" + gen.formatDouble4(width / 100f) + "x"
+ + gen.formatDouble4(height / 100f) + "Y");
+ gen.writeCommand("*c0T");
+ gen.enterHPGL2Mode(false);
+ gen.writeText("\nIN;");
+ gen.writeText("SP1;");
+ //One Plotter unit is 0.025mm!
+ double scale = imw / UnitConv.mm2pt(imw * 0.025);
+ gen.writeText("SC0," + gen.formatDouble4(scale)
+ + ",0,-" + gen.formatDouble4(scale) + ",2;");
+ gen.writeText("IR0,100,0,100;");
+ gen.writeText("PU;PA0,0;\n");
+ baout.writeTo(gen.getOutputStream()); //Buffer is written to output stream
+ gen.writeText("\n");
+
+ gen.enterPCLMode(false);
+ pcl.restoreGraphicsState();
+ painted = true;
+ } catch (UnsupportedOperationException uoe) {
+ log.debug(
+ "Cannot paint graphic natively. Falling back to bitmap painting. Reason: "
+ + uoe.getMessage());
+ }
+ }
+
+ if (!painted) {
+ //Fallback solution: Paint to a BufferedImage
+ int resolution = (int)Math.round(context.getUserAgent().getTargetResolution());
+ BufferedImage bi = paintToBufferedImage(painter, pclContext, resolution, true, false);
+
+ pcl.setCursorPos(x, y);
+ gen.paintBitmap(bi, new Dimension(width, height), pclContext.isSourceTransparency());
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.fop.render.pcl;
+
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.fop.util.UnitConv;
+
+/**
+ * This class represents a page format with PCL-specific properties.
+ */
+public class PCLPageDefinition {
+
+ private static List pageDefinitions;
+ private static PCLPageDefinition defaultPageDefinition;
+
+ private String name;
+ private int selector;
+ private Dimension physicalPageSize;
+ private Rectangle logicalPageRect;
+ private boolean landscape;
+
+ static {
+ createPageDefinitions();
+ }
+
+ /**
+ * Main constructor
+ * @param name the name of the page definition
+ * @param selector the selector used by the <ESC>&l#A command (page size)
+ * @param physicalPageSize the physical page size
+ * @param logicalPageRect the rectangle defining the logical page
+ * @param landscape true if it is a landscape format
+ */
+ public PCLPageDefinition(String name, int selector, Dimension physicalPageSize,
+ Rectangle logicalPageRect, boolean landscape) {
+ this.name = name;
+ this.selector = selector;
+ this.physicalPageSize = physicalPageSize;
+ this.logicalPageRect = logicalPageRect;
+ this.landscape = landscape;
+ }
+
+ /** @return the name of the page definition */
+ public String getName() {
+ return this.name;
+ }
+
+ /** @return the selector used by the <ESC>&l#A command (page size) */
+ public int getSelector() {
+ return this.selector;
+ }
+
+ /** @return true if it is a landscape format */
+ public boolean isLandscapeFormat() {
+ return this.landscape;
+ }
+
+ /** @return the physical page size */
+ public Dimension getPhysicalPageSize() {
+ return this.physicalPageSize;
+ }
+
+ /** @return the rectangle defining the logical page */
+ public Rectangle getLogicalPageRect() {
+ return this.logicalPageRect;
+ }
+
+ private boolean matches(long width, long height, int errorMargin) {
+ return (Math.abs(this.physicalPageSize.width - width) < errorMargin)
+ && (Math.abs(this.physicalPageSize.height - height) < errorMargin);
+ }
+
+ /** @see java.lang.Object#toString() */
+ public String toString() {
+ return getName();
+ }
+
+ /**
+ * Tries to determine a matching page definition.
+ * @param width the physical page width (in mpt)
+ * @param height the physical page height (in mpt)
+ * @param errorMargin the error margin for detecting the right page definition
+ * @return the page definition or null if no match was found
+ */
+ public static PCLPageDefinition getPageDefinition(long width, long height, int errorMargin) {
+ Iterator iter = pageDefinitions.iterator();
+ while (iter.hasNext()) {
+ PCLPageDefinition def = (PCLPageDefinition)iter.next();
+ if (def.matches(width, height, errorMargin)) {
+ return def;
+ }
+ }
+ return null;
+ }
+
+ /** @return the default page definition (letter) */
+ public static PCLPageDefinition getDefaultPageDefinition() {
+ return defaultPageDefinition;
+ }
+
+ /**
+ * Converts an offset values for logical pages to millipoints. The values are given as pixels
+ * in a 300dpi environment.
+ * @param offset the offset as given in the PCL 5 specification (under "Printable Area")
+ * @return the converted value in millipoints
+ */
+ private static int convert300dpiDotsToMpt(int offset) {
+ return (int)Math.round(((double)offset) * 72000 / 300);
+ }
+
+ private static Dimension createPhysicalPageSizeInch(float width, float height) {
+ return new Dimension(
+ (int)Math.round(UnitConv.in2mpt(width)),
+ (int)Math.round(UnitConv.in2mpt(height)));
+ }
+
+ private static Dimension createPhysicalPageSizeMm(float width, float height) {
+ return new Dimension(
+ (int)Math.round(UnitConv.mm2mpt(width)),
+ (int)Math.round(UnitConv.mm2mpt(height)));
+ }
+
+ private static Rectangle createLogicalPageRect(int x, int y, int width, int height) {
+ return new Rectangle(convert300dpiDotsToMpt(x), convert300dpiDotsToMpt(y),
+ convert300dpiDotsToMpt(width), convert300dpiDotsToMpt(height));
+ }
+
+ private static void createPageDefinitions() {
+ pageDefinitions = new java.util.ArrayList();
+ pageDefinitions.add(new PCLPageDefinition("Letter", 2,
+ createPhysicalPageSizeInch(8.5f, 11),
+ createLogicalPageRect(75, 0, 2400, 3300), false));
+ defaultPageDefinition = new PCLPageDefinition("Legal", 3,
+ createPhysicalPageSizeInch(8.5f, 14),
+ createLogicalPageRect(75, 0, 2400, 4200), false);
+ pageDefinitions.add(defaultPageDefinition);
+ pageDefinitions.add(new PCLPageDefinition("Executive", 1,
+ createPhysicalPageSizeInch(7.25f, 10.5f),
+ createLogicalPageRect(75, 0, 2025, 3150), false));
+ pageDefinitions.add(new PCLPageDefinition("Ledger", 6,
+ createPhysicalPageSizeInch(11, 17),
+ createLogicalPageRect(75, 0, 3150, 5100), false));
+ pageDefinitions.add(new PCLPageDefinition("A4", 26,
+ createPhysicalPageSizeMm(210, 297),
+ createLogicalPageRect(71, 0, 2338, 3507), false));
+ pageDefinitions.add(new PCLPageDefinition("A3", 27,
+ createPhysicalPageSizeMm(297, 420),
+ createLogicalPageRect(71, 0, 3365, 4960), false));
+
+ //TODO Add envelope definitions
+
+ pageDefinitions.add(new PCLPageDefinition("LetterL", 2,
+ createPhysicalPageSizeInch(11, 8.5f),
+ createLogicalPageRect(60, 0, 3180, 2550), true));
+ pageDefinitions.add(new PCLPageDefinition("LegalL", 3,
+ createPhysicalPageSizeInch(14, 8.5f),
+ createLogicalPageRect(60, 0, 4080, 2550), true));
+ pageDefinitions.add(new PCLPageDefinition("ExecutiveL", 1,
+ createPhysicalPageSizeInch(10.5f, 7.25f),
+ createLogicalPageRect(60, 0, 3030, 2175), true));
+ pageDefinitions.add(new PCLPageDefinition("LedgerL", 6,
+ createPhysicalPageSizeInch(17, 11),
+ createLogicalPageRect(60, 0, 4980, 3300), true));
+ pageDefinitions.add(new PCLPageDefinition("A4L", 26,
+ createPhysicalPageSizeMm(297, 210),
+ createLogicalPageRect(59, 0, 3389, 2480), true));
+ pageDefinitions.add(new PCLPageDefinition("A3L", 27,
+ createPhysicalPageSizeMm(420, 297),
+ createLogicalPageRect(59, 0, 4842, 3507), true));
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 1999-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.fop.render.pcl;
+
+//Java
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.PixelInterleavedSampleModel;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import org.w3c.dom.Document;
+
+import org.apache.xmlgraphics.java2d.GraphicContext;
+
+// FOP
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.apps.MimeConstants;
+import org.apache.fop.area.Area;
+import org.apache.fop.area.Block;
+import org.apache.fop.area.BlockViewport;
+import org.apache.fop.area.CTM;
+import org.apache.fop.area.PageViewport;
+import org.apache.fop.area.Trait;
+import org.apache.fop.area.inline.AbstractTextArea;
+import org.apache.fop.area.inline.ForeignObject;
+import org.apache.fop.area.inline.Image;
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.SpaceArea;
+import org.apache.fop.area.inline.TextArea;
+import org.apache.fop.area.inline.Viewport;
+import org.apache.fop.area.inline.WordArea;
+import org.apache.fop.fo.extensions.ExtensionElementMapping;
+import org.apache.fop.fonts.Font;
+import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.image.EPSImage;
+import org.apache.fop.image.FopImage;
+import org.apache.fop.image.ImageFactory;
+import org.apache.fop.image.XMLImage;
+import org.apache.fop.render.Graphics2DAdapter;
+import org.apache.fop.render.Graphics2DImagePainter;
+import org.apache.fop.render.PrintRenderer;
+import org.apache.fop.render.RendererContext;
+import org.apache.fop.render.RendererContextConstants;
+import org.apache.fop.render.java2d.FontMetricsMapper;
+import org.apache.fop.render.java2d.FontSetup;
+import org.apache.fop.render.java2d.Java2DRenderer;
+import org.apache.fop.render.pcl.extensions.PCLElementMapping;
+import org.apache.fop.traits.BorderProps;
+import org.apache.fop.util.QName;
+import org.apache.fop.util.UnitConv;
+
+/**
+ * Renderer for the PCL 5 printer language. It also uses HP GL/2 for certain graphic elements.
+ */
+public class PCLRenderer extends PrintRenderer {
+
+ /** logging instance */
+ private static Log log = LogFactory.getLog(PCLRenderer.class);
+
+ /** The MIME type for PCL */
+ public static final String MIME_TYPE = MimeConstants.MIME_PCL_ALT;
+
+ private static final QName CONV_MODE
+ = new QName(ExtensionElementMapping.URI, null, "conversion-mode");
+ private static final QName SRC_TRANSPARENCY
+ = new QName(ExtensionElementMapping.URI, null, "source-transparency");
+
+ /** The OutputStream to write the PCL stream to */
+ protected OutputStream out;
+
+ /** The PCL generator */
+ protected PCLGenerator gen;
+ private boolean ioTrouble = false;
+
+ private Stack graphicContextStack = new Stack();
+ private GraphicContext graphicContext = new GraphicContext();
+
+ private PCLPageDefinition currentPageDefinition;
+ private int currentPrintDirection = 0;
+ private GeneralPath currentPath = null;
+ private java.awt.Color currentFillColor = null;
+
+ /**
+ * Controls whether appearance is more important than speed. False can cause some FO feature
+ * to be ignored (like the advanced borders).
+ */
+ private boolean qualityBeforeSpeed = false;
+
+ /**
+ * Controls whether all text should be painted as text. This is a fallback setting in case
+ * the mixture of native and bitmapped text does not provide the necessary quality.
+ */
+ private boolean allTextAsBitmaps = false;
+
+ /**
+ * Create the PCL renderer
+ */
+ public PCLRenderer() {
+ }
+
+ /**
+ * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
+ */
+ public void configure(Configuration cfg) throws ConfigurationException {
+ super.configure(cfg);
+ String rendering = cfg.getChild("rendering").getValue(null);
+ if ("quality".equalsIgnoreCase(rendering)) {
+ this.qualityBeforeSpeed = true;
+ } else if ("speed".equalsIgnoreCase(rendering)) {
+ this.qualityBeforeSpeed = false;
+ } else if (rendering != null) {
+ throw new ConfigurationException(
+ "Valid values for 'rendering' are 'quality' and 'speed'. Value found: "
+ + rendering);
+ }
+ String textRendering = cfg.getChild("text-rendering").getValue(null);
+ if ("bitmap".equalsIgnoreCase(textRendering)) {
+ this.allTextAsBitmaps = true;
+ } else if ("auto".equalsIgnoreCase(textRendering)) {
+ this.allTextAsBitmaps = false;
+ } else if (textRendering != null) {
+ throw new ConfigurationException(
+ "Valid values for 'text-rendering' are 'auto' and 'bitmap'. Value found: "
+ + textRendering);
+ }
+ }
+
+ /**
+ * @see org.apache.fop.render.Renderer#setupFontInfo(org.apache.fop.fonts.FontInfo)
+ */
+ public void setupFontInfo(FontInfo inFontInfo) {
+ //Don't call super.setupFontInfo() here!
+ //The PCLRenderer uses the Java2D FontSetup which needs a special font setup
+ //create a temp Image to test font metrics on
+ fontInfo = inFontInfo;
+ BufferedImage fontImage = new BufferedImage(100, 100,
+ BufferedImage.TYPE_INT_RGB);
+ Graphics2D g = fontImage.createGraphics();
+ //The next line is important to get accurate font metrics!
+ g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
+ RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+ FontSetup.setup(fontInfo, g);
+ }
+
+ /**
+ * Central exception handler for I/O exceptions.
+ * @param ioe IOException to handle
+ */
+ protected void handleIOTrouble(IOException ioe) {
+ if (!ioTrouble) {
+ log.error("Error while writing to target file", ioe);
+ ioTrouble = true;
+ }
+ }
+
+ /** @see org.apache.fop.render.Renderer#getGraphics2DAdapter() */
+ public Graphics2DAdapter getGraphics2DAdapter() {
+ return new PCLGraphics2DAdapter();
+ }
+
+ /** @return the GraphicContext used to track coordinate system transformations */
+ public GraphicContext getGraphicContext() {
+ return this.graphicContext;
+ }
+
+ /** @return the target resolution */
+ protected int getResolution() {
+ int resolution = (int)Math.round(userAgent.getTargetResolution());
+ if (resolution <= 300) {
+ return 300;
+ } else {
+ return 600;
+ }
+ }
+
+ /**
+ * Sets the current font (NOTE: Hard-coded font mappings ATM!)
+ * @param name the font name (internal F* names for now)
+ * @param size the font size
+ * @param text the text to be rendered (used to determine if there are non-printable chars)
+ * @return true if the font can be mapped to PCL
+ * @throws IOException if an I/O problem occurs
+ */
+ public boolean setFont(String name, float size, String text) throws IOException {
+ byte[] encoded = text.getBytes("ISO-8859-1");
+ for (int i = 0, c = encoded.length; i < c; i++) {
+ if (encoded[i] == 0x3F && text.charAt(i) != '?') {
+ return false;
+ }
+ }
+ int fontcode = 0;
+ if (name.length() > 1 && name.charAt(0) == 'F') {
+ try {
+ fontcode = Integer.parseInt(name.substring(1));
+ } catch (Exception e) {
+ log.error(e);
+ }
+ }
+ //Note "(ON" selects ISO 8859-1 symbol set as used by PCLGenerator
+ String formattedSize = gen.formatDouble2(size / 1000);
+ switch (fontcode) {
+ case 1: // F1 = Helvetica
+ // gen.writeCommand("(8U");
+ // gen.writeCommand("(s1p" + formattedSize + "v0s0b24580T");
+ // Arial is more common among PCL5 printers than Helvetica - so use Arial
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v0s0b16602T");
+ break;
+ case 2: // F2 = Helvetica Oblique
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v1s0b16602T");
+ break;
+ case 3: // F3 = Helvetica Bold
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v0s3b16602T");
+ break;
+ case 4: // F4 = Helvetica Bold Oblique
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v1s3b16602T");
+ break;
+ case 5: // F5 = Times Roman
+ // gen.writeCommand("(8U");
+ // gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
+ // Times New is more common among PCL5 printers than Times - so use Times New
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v0s0b16901T");
+ break;
+ case 6: // F6 = Times Italic
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v1s0b16901T");
+ break;
+ case 7: // F7 = Times Bold
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v0s3b16901T");
+ break;
+ case 8: // F8 = Times Bold Italic
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v1s3b16901T");
+ break;
+ case 9: // F9 = Courier
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
+ + "h0s0b4099T");
+ break;
+ case 10: // F10 = Courier Oblique
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
+ + "h1s0b4099T");
+ break;
+ case 11: // F11 = Courier Bold
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
+ + "h0s3b4099T");
+ break;
+ case 12: // F12 = Courier Bold Oblique
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
+ + "h1s3b4099T");
+ break;
+ case 13: // F13 = Symbol
+
+ return false;
+ //gen.writeCommand("(19M");
+ //gen.writeCommand("(s1p" + formattedSize + "v0s0b16686T");
+ // ECMA Latin 1 Symbol Set in Times Roman???
+ // gen.writeCommand("(9U");
+ // gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
+ //break;
+ case 14: // F14 = Zapf Dingbats
+
+ return false;
+ //gen.writeCommand("(14L");
+ //gen.writeCommand("(s1p" + formattedSize + "v0s0b45101T");
+ //break;
+ default:
+ //gen.writeCommand("(0N");
+ //gen.writeCommand("(s" + formattedSize + "V");
+ return false;
+ }
+ return true;
+ }
+
+ /** @see org.apache.fop.render.Renderer#startRenderer(java.io.OutputStream) */
+ public void startRenderer(OutputStream outputStream) throws IOException {
+ log.debug("Rendering areas to PCL...");
+ this.out = outputStream;
+ this.gen = new PCLGenerator(out, getResolution());
+
+ gen.universalEndOfLanguage();
+ gen.writeText("@PJL COMMENT Produced by " + userAgent.getProducer() + "\n");
+ if (userAgent.getTitle() != null) {
+ gen.writeText("@PJL JOB NAME = \"" + userAgent.getTitle() + "\"\n");
+ }
+ gen.writeText("@PJL SET RESOLUTION = " + getResolution() + "\n");
+ gen.writeText("@PJL ENTER LANGUAGE = PCL\n");
+ gen.resetPrinter();
+ gen.setUnitOfMeasure(getResolution());
+ gen.setRasterGraphicsResolution(getResolution());
+ }
+
+ /** @see org.apache.fop.render.Renderer#stopRenderer() */
+ public void stopRenderer() throws IOException {
+ gen.separateJobs();
+ gen.resetPrinter();
+ gen.universalEndOfLanguage();
+ }
+
+ /** @see org.apache.fop.render.AbstractRenderer */
+ public String getMimeType() {
+ return MIME_TYPE;
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderPage(org.apache.fop.area.PageViewport)
+ */
+ public void renderPage(PageViewport page) throws IOException, FOPException {
+ saveGraphicsState();
+
+ //Paper source
+ String paperSource = page.getForeignAttributeValue(
+ new QName(PCLElementMapping.NAMESPACE, null, "paper-source"));
+ if (paperSource != null) {
+ gen.selectPaperSource(Integer.parseInt(paperSource));
+ }
+
+ //Page size
+ final long pagewidth = Math.round(page.getViewArea().getWidth());
+ final long pageheight = Math.round(page.getViewArea().getHeight());
+ selectPageFormat(pagewidth, pageheight);
+
+ super.renderPage(page);
+
+ //Eject page
+ gen.formFeed();
+ restoreGraphicsState();
+ }
+
+ private void selectPageFormat(long pagewidth, long pageheight) throws IOException {
+ this.currentPageDefinition = PCLPageDefinition.getPageDefinition(
+ pagewidth, pageheight, 1000);
+
+ if (this.currentPageDefinition == null) {
+ this.currentPageDefinition = PCLPageDefinition.getDefaultPageDefinition();
+ log.warn("Paper type could not be determined. Falling back to: "
+ + this.currentPageDefinition.getName());
+ }
+ log.debug("page size: " + currentPageDefinition.getPhysicalPageSize());
+ log.debug("logical page: " + currentPageDefinition.getLogicalPageRect());
+ if (this.currentPageDefinition.isLandscapeFormat()) {
+ gen.writeCommand("&l1O"); //Orientation
+ } else {
+ gen.writeCommand("&l0O"); //Orientation
+ }
+ gen.selectPageSize(this.currentPageDefinition.getSelector());
+
+ gen.clearHorizontalMargins();
+ gen.setTopMargin(0);
+ }
+
+ /** Saves the current graphics state on the stack. */
+ protected void saveGraphicsState() {
+ graphicContextStack.push(graphicContext);
+ graphicContext = (GraphicContext)graphicContext.clone();
+ }
+
+ /** Restores the last graphics state from the stack. */
+ protected void restoreGraphicsState() {
+ graphicContext = (GraphicContext)graphicContextStack.pop();
+ }
+
+ /**
+ * Clip an area. write a clipping operation given coordinates in the current
+ * transform. Coordinates are in points.
+ *
+ * @param x the x coordinate
+ * @param y the y coordinate
+ * @param width the width of the area
+ * @param height the height of the area
+ */
+ protected void clipRect(float x, float y, float width, float height) {
+ //PCL cannot clip (only HP GL/2 can)
+ }
+
+ private Point2D transformedPoint(float x, float y) {
+ return transformedPoint(Math.round(x), Math.round(y));
+ }
+
+ private Point2D transformedPoint(int x, int y) {
+ AffineTransform at = graphicContext.getTransform();
+ if (log.isTraceEnabled()) {
+ log.trace("Current transform: " + at);
+ }
+ Point2D.Float orgPoint = new Point2D.Float(x, y);
+ Point2D.Float transPoint = new Point2D.Float();
+ at.transform(orgPoint, transPoint);
+ //At this point we have the absolute position in FOP's coordinate system
+
+ //Now get PCL coordinates taking the current print direction and the logical page
+ //into account.
+ Dimension pageSize = currentPageDefinition.getPhysicalPageSize();
+ Rectangle logRect = currentPageDefinition.getLogicalPageRect();
+ switch (currentPrintDirection) {
+ case 0:
+ transPoint.x -= logRect.x;
+ transPoint.y -= logRect.y;
+ break;
+ case 90:
+ float ty = transPoint.x;
+ transPoint.x = pageSize.height - transPoint.y;
+ transPoint.y = ty;
+ transPoint.x -= logRect.y;
+ transPoint.y -= logRect.x;
+ break;
+ case 180:
+ transPoint.x = pageSize.width - transPoint.x;
+ transPoint.y = pageSize.height - transPoint.y;
+ transPoint.x -= pageSize.width - logRect.x - logRect.width;
+ transPoint.y -= pageSize.height - logRect.y - logRect.height;
+ //The next line is odd and is probably necessary due to the default value of the
+ //Text Length command: "1/2 inch less than maximum text length"
+ //I wonder why this isn't necessary for the 90 degree rotation. *shrug*
+ transPoint.y -= UnitConv.in2mpt(0.5);
+ break;
+ case 270:
+ float tx = transPoint.y;
+ transPoint.y = pageSize.width - transPoint.x;
+ transPoint.x = tx;
+ transPoint.x -= pageSize.height - logRect.y - logRect.height;
+ transPoint.y -= pageSize.width - logRect.x - logRect.width;
+ break;
+ default:
+ throw new IllegalStateException("Illegal print direction: " + currentPrintDirection);
+ }
+ return transPoint;
+ }
+
+ private void changePrintDirection() {
+ AffineTransform at = graphicContext.getTransform();
+ int newDir;
+ try {
+ if (at.getScaleX() == 0 && at.getScaleY() == 0
+ && at.getShearX() == 1 && at.getShearY() == -1) {
+ newDir = 90;
+ } else if (at.getScaleX() == -1 && at.getScaleY() == -1
+ && at.getShearX() == 0 && at.getShearY() == 0) {
+ newDir = 180;
+ } else if (at.getScaleX() == 0 && at.getScaleY() == 0
+ && at.getShearX() == -1 && at.getShearY() == 1) {
+ newDir = 270;
+ } else {
+ newDir = 0;
+ }
+ if (newDir != this.currentPrintDirection) {
+ this.currentPrintDirection = newDir;
+ gen.changePrintDirection(this.currentPrintDirection);
+ }
+ } catch (IOException ioe) {
+ handleIOTrouble(ioe);
+ }
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#startVParea(CTM, Rectangle2D)
+ */
+ protected void startVParea(CTM ctm, Rectangle2D clippingRect) {
+ saveGraphicsState();
+ AffineTransform at = new AffineTransform(ctm.toArray());
+ graphicContext.transform(at);
+ changePrintDirection();
+ if (log.isDebugEnabled()) {
+ log.debug("startVPArea: " + at + " --> " + graphicContext.getTransform());
+ }
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#endVParea()
+ */
+ protected void endVParea() {
+ restoreGraphicsState();
+ changePrintDirection();
+ if (log.isDebugEnabled()) {
+ log.debug("endVPArea() --> " + graphicContext.getTransform());
+ }
+ }
+
+ /**
+ * Handle block traits.
+ * The block could be any sort of block with any positioning
+ * so this should render the traits such as border and background
+ * in its position.
+ *
+ * @param block the block to render the traits
+ */
+ protected void handleBlockTraits(Block block) {
+ int borderPaddingStart = block.getBorderAndPaddingWidthStart();
+ int borderPaddingBefore = block.getBorderAndPaddingWidthBefore();
+
+ float startx = currentIPPosition / 1000f;
+ float starty = currentBPPosition / 1000f;
+ float width = block.getIPD() / 1000f;
+ float height = block.getBPD() / 1000f;
+
+ startx += block.getStartIndent() / 1000f;
+ startx -= block.getBorderAndPaddingWidthStart() / 1000f;
+
+ width += borderPaddingStart / 1000f;
+ width += block.getBorderAndPaddingWidthEnd() / 1000f;
+ height += borderPaddingBefore / 1000f;
+ height += block.getBorderAndPaddingWidthAfter() / 1000f;
+
+ drawBackAndBorders(block, startx, starty, width, height);
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderText(TextArea)
+ */
+ protected void renderText(final TextArea text) {
+ renderInlineAreaBackAndBorders(text);
+
+ String fontname = getInternalFontNameForArea(text);
+ int fontsize = text.getTraitAsInteger(Trait.FONT_SIZE);
+
+ //Determine position
+ int saveIP = currentIPPosition;
+ int rx = currentIPPosition + text.getBorderAndPaddingWidthStart();
+ int bl = currentBPPosition + text.getOffset() + text.getBaselineOffset();
+
+ try {
+ final Color col = (Color)text.getTrait(Trait.COLOR);
+ boolean pclFont = allTextAsBitmaps
+ ? false
+ : setFont(fontname, fontsize, text.getText());
+ if (pclFont) {
+ //this.currentFill = col;
+ if (col != null) {
+ //useColor(ct);
+ gen.setTransparencyMode(true, false);
+ gen.selectCurrentPattern(gen.convertToPCLShade(col), 2);
+ }
+
+ saveGraphicsState();
+ graphicContext.translate(rx, bl);
+ setCursorPos(0, 0);
+ gen.setTransparencyMode(true, true);
+
+ super.renderText(text); //Updates IPD and renders words and spaces
+ restoreGraphicsState();
+ } else {
+ //Use Java2D to paint different fonts via bitmap
+ final Font font = getFontFromArea(text);
+ final int baseline = text.getBaselineOffset();
+
+ //for cursive fonts, so the text isn't clipped
+ int extraWidth = font.getFontSize() / 3;
+ final FontMetricsMapper mapper = (FontMetricsMapper)fontInfo.getMetricsFor(
+ font.getFontName());
+ int maxAscent = mapper.getMaxAscent(font.getFontSize()) / 1000;
+ final int additionalBPD = maxAscent - baseline;
+
+ Graphics2DAdapter g2a = getGraphics2DAdapter();
+ final Rectangle paintRect = new Rectangle(
+ rx, currentBPPosition + text.getOffset() - additionalBPD,
+ text.getIPD() + extraWidth, text.getBPD() + additionalBPD);
+ RendererContext rc = createRendererContext(paintRect.x, paintRect.y,
+ paintRect.width, paintRect.height, null);
+ Map atts = new java.util.HashMap();
+ atts.put(CONV_MODE, "bitmap");
+ atts.put(SRC_TRANSPARENCY, "true");
+ rc.setProperty(RendererContextConstants.FOREIGN_ATTRIBUTES, atts);
+
+ Graphics2DImagePainter painter = new Graphics2DImagePainter() {
+
+ public void paint(Graphics2D g2d, Rectangle2D area) {
+ g2d.setFont(mapper.getFont(font.getFontSize()));
+ g2d.translate(0, baseline + additionalBPD);
+ g2d.scale(1000, 1000);
+ g2d.setColor(col);
+ Java2DRenderer.renderText(text, g2d, font);
+ }
+
+ public Dimension getImageSize() {
+ return paintRect.getSize();
+ }
+
+ };
+ g2a.paintImage(painter, rc,
+ paintRect.x, paintRect.y, paintRect.width, paintRect.height);
+ currentIPPosition = saveIP + text.getAllocIPD();
+ }
+
+ //renderTextDecoration(tf, fontsize, area, bl, rx);
+ } catch (IOException ioe) {
+ handleIOTrouble(ioe);
+ }
+ }
+
+ /**
+ * Sets the current cursor position. The coordinates are transformed to the absolute position
+ * on the logical PCL page and then passed on to the PCLGenerator.
+ * @param x the x coordinate (in millipoints)
+ * @param y the y coordinate (in millipoints)
+ */
+ void setCursorPos(float x, float y) {
+ try {
+ Point2D transPoint = transformedPoint(x, y);
+ gen.setCursorPos(transPoint.getX(), transPoint.getY());
+ } catch (IOException ioe) {
+ handleIOTrouble(ioe);
+ }
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractPathOrientedRenderer#clip()
+ */
+ protected void clip() {
+ if (currentPath == null) {
+ throw new IllegalStateException("No current path available!");
+ }
+ //TODO Find a good way to do clipping. PCL itself cannot clip.
+ currentPath = null;
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractPathOrientedRenderer#closePath()
+ */
+ protected void closePath() {
+ currentPath.closePath();
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractPathOrientedRenderer#lineTo(float, float)
+ */
+ protected void lineTo(float x, float y) {
+ if (currentPath == null) {
+ currentPath = new GeneralPath();
+ }
+ currentPath.lineTo(x, y);
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractPathOrientedRenderer#moveTo(float, float)
+ */
+ protected void moveTo(float x, float y) {
+ if (currentPath == null) {
+ currentPath = new GeneralPath();
+ }
+ currentPath.moveTo(x, y);
+ }
+
+ /**
+ * Fill a rectangular area.
+ * @param x the x coordinate (in pt)
+ * @param y the y coordinate (in pt)
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ */
+ protected void fillRect(float x, float y, float width, float height) {
+ try {
+ setCursorPos(x * 1000, y * 1000);
+ gen.fillRect((int)(width * 1000), (int)(height * 1000),
+ this.currentFillColor);
+ } catch (IOException ioe) {
+ handleIOTrouble(ioe);
+ }
+ }
+
+ /**
+ * Sets the new current fill color.
+ * @param color the color
+ */
+ protected void updateFillColor(java.awt.Color color) {
+ this.currentFillColor = color;
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderWord(org.apache.fop.area.inline.WordArea)
+ */
+ protected void renderWord(WordArea word) {
+ //Font font = getFontFromArea(word.getParentArea());
+
+ String s = word.getWord();
+
+ try {
+ gen.writeText(s);
+ } catch (IOException ioe) {
+ handleIOTrouble(ioe);
+ }
+
+ super.renderWord(word);
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderSpace(org.apache.fop.area.inline.SpaceArea)
+ */
+ protected void renderSpace(SpaceArea space) {
+ AbstractTextArea textArea = (AbstractTextArea)space.getParentArea();
+ String s = space.getSpace();
+ char sp = s.charAt(0);
+ Font font = getFontFromArea(textArea);
+
+ int tws = (space.isAdjustable()
+ ? textArea.getTextWordSpaceAdjust()
+ + 2 * textArea.getTextLetterSpaceAdjust()
+ : 0);
+
+ double dx = (font.getCharWidth(sp) + tws) / 100f;
+ try {
+ gen.writeCommand("&a+" + gen.formatDouble2(dx) + "H");
+ } catch (IOException ioe) {
+ handleIOTrouble(ioe);
+ }
+ super.renderSpace(space);
+ }
+
+ /**
+ * Render an inline viewport.
+ * This renders an inline viewport by clipping if necessary.
+ * @param viewport the viewport to handle
+ * @todo Copied from AbstractPathOrientedRenderer
+ */
+ public void renderViewport(Viewport viewport) {
+
+ float x = currentIPPosition / 1000f;
+ float y = (currentBPPosition + viewport.getOffset()) / 1000f;
+ float width = viewport.getIPD() / 1000f;
+ float height = viewport.getBPD() / 1000f;
+ // TODO: Calculate the border rect correctly.
+ float borderPaddingStart = viewport.getBorderAndPaddingWidthStart() / 1000f;
+ float borderPaddingBefore = viewport.getBorderAndPaddingWidthBefore() / 1000f;
+ float bpwidth = borderPaddingStart
+ + (viewport.getBorderAndPaddingWidthEnd() / 1000f);
+ float bpheight = borderPaddingBefore
+ + (viewport.getBorderAndPaddingWidthAfter() / 1000f);
+
+ drawBackAndBorders(viewport, x, y, width + bpwidth, height + bpheight);
+
+ if (viewport.getClip()) {
+ saveGraphicsState();
+
+ clipRect(x + borderPaddingStart, y + borderPaddingBefore, width, height);
+ }
+ super.renderViewport(viewport);
+
+ if (viewport.getClip()) {
+ restoreGraphicsState();
+ }
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List)
+ */
+ protected void renderBlockViewport(BlockViewport bv, List children) {
+ // clip and position viewport if necessary
+
+ // save positions
+ int saveIP = currentIPPosition;
+ int saveBP = currentBPPosition;
+ //String saveFontName = currentFontName;
+
+ CTM ctm = bv.getCTM();
+ int borderPaddingStart = bv.getBorderAndPaddingWidthStart();
+ int borderPaddingBefore = bv.getBorderAndPaddingWidthBefore();
+ float x, y;
+ x = (float)(bv.getXOffset() + containingIPPosition) / 1000f;
+ y = (float)(bv.getYOffset() + containingBPPosition) / 1000f;
+ //This is the content-rect
+ float width = (float)bv.getIPD() / 1000f;
+ float height = (float)bv.getBPD() / 1000f;
+
+
+ if (bv.getPositioning() == Block.ABSOLUTE
+ || bv.getPositioning() == Block.FIXED) {
+
+ currentIPPosition = bv.getXOffset();
+ currentBPPosition = bv.getYOffset();
+
+ //For FIXED, we need to break out of the current viewports to the
+ //one established by the page. We save the state stack for restoration
+ //after the block-container has been painted. See below.
+ List breakOutList = null;
+ if (bv.getPositioning() == Block.FIXED) {
+ breakOutList = breakOutOfStateStack();
+ }
+
+ CTM tempctm = new CTM(containingIPPosition, containingBPPosition);
+ ctm = tempctm.multiply(ctm);
+
+ //Adjust for spaces (from margin or indirectly by start-indent etc.
+ x += bv.getSpaceStart() / 1000f;
+ currentIPPosition += bv.getSpaceStart();
+
+ y += bv.getSpaceBefore() / 1000f;
+ currentBPPosition += bv.getSpaceBefore();
+
+ float bpwidth = (borderPaddingStart + bv.getBorderAndPaddingWidthEnd()) / 1000f;
+ float bpheight = (borderPaddingBefore + bv.getBorderAndPaddingWidthAfter()) / 1000f;
+
+ drawBackAndBorders(bv, x, y, width + bpwidth, height + bpheight);
+
+ //Now adjust for border/padding
+ currentIPPosition += borderPaddingStart;
+ currentBPPosition += borderPaddingBefore;
+
+ Rectangle2D clippingRect = null;
+ if (bv.getClip()) {
+ clippingRect = new Rectangle(currentIPPosition, currentBPPosition,
+ bv.getIPD(), bv.getBPD());
+ }
+
+ startVParea(ctm, clippingRect);
+ currentIPPosition = 0;
+ currentBPPosition = 0;
+ renderBlocks(bv, children);
+ endVParea();
+
+ if (breakOutList != null) {
+ restoreStateStackAfterBreakOut(breakOutList);
+ }
+
+ currentIPPosition = saveIP;
+ currentBPPosition = saveBP;
+ } else {
+
+ currentBPPosition += bv.getSpaceBefore();
+
+ //borders and background in the old coordinate system
+ handleBlockTraits(bv);
+
+ //Advance to start of content area
+ currentIPPosition += bv.getStartIndent();
+
+ CTM tempctm = new CTM(containingIPPosition, currentBPPosition);
+ ctm = tempctm.multiply(ctm);
+
+ //Now adjust for border/padding
+ currentBPPosition += borderPaddingBefore;
+
+ Rectangle2D clippingRect = null;
+ if (bv.getClip()) {
+ clippingRect = new Rectangle(currentIPPosition, currentBPPosition,
+ bv.getIPD(), bv.getBPD());
+ }
+
+ startVParea(ctm, clippingRect);
+ currentIPPosition = 0;
+ currentBPPosition = 0;
+ renderBlocks(bv, children);
+ endVParea();
+
+ currentIPPosition = saveIP;
+ currentBPPosition = saveBP;
+
+ currentBPPosition += (int)(bv.getAllocBPD());
+ }
+ //currentFontName = saveFontName;
+ }
+
+ private List breakOutOfStateStack() {
+ log.debug("Block.FIXED --> break out");
+ List breakOutList = new java.util.ArrayList();
+ while (!this.graphicContextStack.empty()) {
+ breakOutList.add(0, this.graphicContext);
+ restoreGraphicsState();
+ }
+ return breakOutList;
+ }
+
+ private void restoreStateStackAfterBreakOut(List breakOutList) {
+ log.debug("Block.FIXED --> restoring context after break-out");
+ for (int i = 0, c = breakOutList.size(); i < c; i++) {
+ saveGraphicsState();
+ this.graphicContext = (GraphicContext)breakOutList.get(i);
+ }
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderImage(Image, Rectangle2D)
+ */
+ public void renderImage(Image image, Rectangle2D pos) {
+ drawImage(image.getURL(), pos, image.getForeignAttributes());
+ }
+
+ /**
+ * Draw an image at the indicated location.
+ * @param url the URI/URL of the image
+ * @param pos the position of the image
+ * @param foreignAttributes an optional Map with foreign attributes, may be null
+ */
+ protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) {
+ url = ImageFactory.getURL(url);
+ ImageFactory fact = userAgent.getFactory().getImageFactory();
+ FopImage fopimage = fact.getImage(url, userAgent);
+ if (fopimage == null) {
+ return;
+ }
+ if (!fopimage.load(FopImage.DIMENSIONS)) {
+ return;
+ }
+ String mime = fopimage.getMimeType();
+ if ("text/xml".equals(mime)) {
+ if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
+ return;
+ }
+ Document doc = ((XMLImage) fopimage).getDocument();
+ String ns = ((XMLImage) fopimage).getNameSpace();
+
+ renderDocument(doc, ns, pos, foreignAttributes);
+ } else if ("image/svg+xml".equals(mime)) {
+ if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
+ return;
+ }
+ Document doc = ((XMLImage) fopimage).getDocument();
+ String ns = ((XMLImage) fopimage).getNameSpace();
+
+ renderDocument(doc, ns, pos, foreignAttributes);
+ } else if (fopimage instanceof EPSImage) {
+ log.warn("EPS images are not supported by this renderer");
+ } else {
+ if (!fopimage.load(FopImage.BITMAP)) {
+ log.error("Bitmap image could not be processed: " + fopimage);
+ return;
+ }
+ byte[] imgmap = fopimage.getBitmaps();
+
+ ColorModel cm = new ComponentColorModel(
+ ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB),
+ new int[] {8, 8, 8},
+ false, false,
+ ColorModel.OPAQUE, DataBuffer.TYPE_BYTE);
+ int imgw = fopimage.getWidth();
+ int imgh = fopimage.getHeight();
+ SampleModel sampleModel = new PixelInterleavedSampleModel(
+ DataBuffer.TYPE_BYTE, imgw, imgh, 3, imgw * 3, new int[] {0, 1, 2});
+ DataBuffer dbuf = new DataBufferByte(imgmap, imgw * imgh * 3);
+
+ WritableRaster raster = Raster.createWritableRaster(sampleModel,
+ dbuf, null);
+
+ // Combine the color model and raster into a buffered image
+ RenderedImage img = new BufferedImage(cm, raster, false, null);
+
+ try {
+ setCursorPos(this.currentIPPosition + (int)pos.getX(),
+ this.currentBPPosition + (int)pos.getY());
+ gen.paintBitmap(img,
+ new Dimension((int)pos.getWidth(), (int)pos.getHeight()),
+ false);
+ } catch (IOException ioe) {
+ handleIOTrouble(ioe);
+ }
+ }
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D)
+ */
+ public void renderForeignObject(ForeignObject fo, Rectangle2D pos) {
+ Document doc = fo.getDocument();
+ String ns = fo.getNameSpace();
+ renderDocument(doc, ns, pos, fo.getForeignAttributes());
+ }
+
+ /**
+ * Common method to render the background and borders for any inline area.
+ * The all borders and padding are drawn outside the specified area.
+ * @param area the inline area for which the background, border and padding is to be
+ * rendered
+ * @todo Copied from AbstractPathOrientedRenderer
+ */
+ protected void renderInlineAreaBackAndBorders(InlineArea area) {
+ float x = currentIPPosition / 1000f;
+ float y = (currentBPPosition + area.getOffset()) / 1000f;
+ float width = area.getIPD() / 1000f;
+ float height = area.getBPD() / 1000f;
+ float borderPaddingStart = area.getBorderAndPaddingWidthStart() / 1000f;
+ float borderPaddingBefore = area.getBorderAndPaddingWidthBefore() / 1000f;
+ float bpwidth = borderPaddingStart
+ + (area.getBorderAndPaddingWidthEnd() / 1000f);
+ float bpheight = borderPaddingBefore
+ + (area.getBorderAndPaddingWidthAfter() / 1000f);
+
+ if (height != 0.0f || bpheight != 0.0f && bpwidth != 0.0f) {
+ drawBackAndBorders(area, x, y - borderPaddingBefore
+ , width + bpwidth
+ , height + bpheight);
+ }
+ }
+
+ /**
+ * Draw the background and borders. This draws the background and border
+ * traits for an area given the position.
+ *
+ * @param area the area whose traits are used
+ * @param startx the start x position
+ * @param starty the start y position
+ * @param width the width of the area
+ * @param height the height of the area
+ */
+ protected void drawBackAndBorders(Area area, float startx, float starty,
+ float width, float height) {
+ BorderProps bpsBefore = (BorderProps) area.getTrait(Trait.BORDER_BEFORE);
+ BorderProps bpsAfter = (BorderProps) area.getTrait(Trait.BORDER_AFTER);
+ BorderProps bpsStart = (BorderProps) area.getTrait(Trait.BORDER_START);
+ BorderProps bpsEnd = (BorderProps) area.getTrait(Trait.BORDER_END);
+
+ // draw background
+ Trait.Background back;
+ back = (Trait.Background) area.getTrait(Trait.BACKGROUND);
+ if (back != null) {
+
+ // Calculate padding rectangle
+ float sx = startx;
+ float sy = starty;
+ float paddRectWidth = width;
+ float paddRectHeight = height;
+
+ if (bpsStart != null) {
+ sx += bpsStart.width / 1000f;
+ paddRectWidth -= bpsStart.width / 1000f;
+ }
+ if (bpsBefore != null) {
+ sy += bpsBefore.width / 1000f;
+ paddRectHeight -= bpsBefore.width / 1000f;
+ }
+ if (bpsEnd != null) {
+ paddRectWidth -= bpsEnd.width / 1000f;
+ }
+ if (bpsAfter != null) {
+ paddRectHeight -= bpsAfter.width / 1000f;
+ }
+
+ if (back.getColor() != null) {
+ updateFillColor(back.getColor());
+ fillRect(sx, sy, paddRectWidth, paddRectHeight);
+ }
+
+ // background image
+ if (back.getFopImage() != null) {
+ FopImage fopimage = back.getFopImage();
+ if (fopimage != null && fopimage.load(FopImage.DIMENSIONS)) {
+ saveGraphicsState();
+ clipRect(sx, sy, paddRectWidth, paddRectHeight);
+ int horzCount = (int) ((paddRectWidth * 1000 / fopimage
+ .getIntrinsicWidth()) + 1.0f);
+ int vertCount = (int) ((paddRectHeight * 1000 / fopimage
+ .getIntrinsicHeight()) + 1.0f);
+ if (back.getRepeat() == EN_NOREPEAT) {
+ horzCount = 1;
+ vertCount = 1;
+ } else if (back.getRepeat() == EN_REPEATX) {
+ vertCount = 1;
+ } else if (back.getRepeat() == EN_REPEATY) {
+ horzCount = 1;
+ }
+ // change from points to millipoints
+ sx *= 1000;
+ sy *= 1000;
+ if (horzCount == 1) {
+ sx += back.getHoriz();
+ }
+ if (vertCount == 1) {
+ sy += back.getVertical();
+ }
+ for (int x = 0; x < horzCount; x++) {
+ for (int y = 0; y < vertCount; y++) {
+ // place once
+ Rectangle2D pos;
+ // Image positions are relative to the currentIP/BP
+ pos = new Rectangle2D.Float(
+ sx - currentIPPosition
+ + (x * fopimage.getIntrinsicWidth()),
+ sy - currentBPPosition
+ + (y * fopimage.getIntrinsicHeight()),
+ fopimage.getIntrinsicWidth(),
+ fopimage.getIntrinsicHeight());
+ drawImage(back.getURL(), pos, null);
+ }
+ }
+ restoreGraphicsState();
+ } else {
+ log.warn(
+ "Can't find background image: " + back.getURL());
+ }
+ }
+ }
+
+ Rectangle2D.Float borderRect = new Rectangle2D.Float(startx, starty, width, height);
+ drawBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
+ }
+
+ /**
+ * Draws borders.
+ * @param borderRect the border rectangle
+ * @param bpsBefore the border specification on the before side
+ * @param bpsAfter the border specification on the after side
+ * @param bpsStart the border specification on the start side
+ * @param bpsEnd the border specification on the end side
+ */
+ protected void drawBorders(Rectangle2D.Float borderRect,
+ final BorderProps bpsBefore, final BorderProps bpsAfter,
+ final BorderProps bpsStart, final BorderProps bpsEnd) {
+ if (bpsBefore == null && bpsAfter == null && bpsStart == null && bpsEnd == null) {
+ return; //no borders to paint
+ }
+ if (qualityBeforeSpeed) {
+ drawQualityBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
+ } else {
+ drawFastBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
+ }
+ }
+
+ /**
+ * Draws borders. Borders are drawn as shaded rectangles with no clipping.
+ * @param borderRect the border rectangle
+ * @param bpsBefore the border specification on the before side
+ * @param bpsAfter the border specification on the after side
+ * @param bpsStart the border specification on the start side
+ * @param bpsEnd the border specification on the end side
+ */
+ protected void drawFastBorders(Rectangle2D.Float borderRect,
+ final BorderProps bpsBefore, final BorderProps bpsAfter,
+ final BorderProps bpsStart, final BorderProps bpsEnd) {
+ float startx = borderRect.x;
+ float starty = borderRect.y;
+ float width = borderRect.width;
+ float height = borderRect.height;
+ if (bpsBefore != null) {
+ float borderWidth = bpsBefore.width / 1000f;
+ updateFillColor(bpsBefore.color);
+ fillRect(startx, starty, width, borderWidth);
+ }
+ if (bpsAfter != null) {
+ float borderWidth = bpsAfter.width / 1000f;
+ updateFillColor(bpsAfter.color);
+ fillRect(startx, (starty + height - borderWidth),
+ width, borderWidth);
+ }
+ if (bpsStart != null) {
+ float borderWidth = bpsStart.width / 1000f;
+ updateFillColor(bpsStart.color);
+ fillRect(startx, starty, borderWidth, height);
+ }
+ if (bpsEnd != null) {
+ float borderWidth = bpsEnd.width / 1000f;
+ updateFillColor(bpsEnd.color);
+ fillRect((startx + width - borderWidth), starty, borderWidth, height);
+ }
+ }
+
+ /**
+ * Draws borders. Borders are drawn in-memory and painted as a bitmap.
+ * @param borderRect the border rectangle
+ * @param bpsBefore the border specification on the before side
+ * @param bpsAfter the border specification on the after side
+ * @param bpsStart the border specification on the start side
+ * @param bpsEnd the border specification on the end side
+ */
+ protected void drawQualityBorders(Rectangle2D.Float borderRect,
+ final BorderProps bpsBefore, final BorderProps bpsAfter,
+ final BorderProps bpsStart, final BorderProps bpsEnd) {
+ Graphics2DAdapter g2a = getGraphics2DAdapter();
+ final Rectangle.Float effBorderRect = new Rectangle2D.Float(
+ borderRect.x - (currentIPPosition / 1000f),
+ borderRect.y - (currentBPPosition / 1000f),
+ borderRect.width,
+ borderRect.height);
+ final Rectangle paintRect = new Rectangle(
+ (int)Math.round(borderRect.x * 1000f),
+ (int)Math.round(borderRect.y * 1000f),
+ (int)Math.floor(borderRect.width * 1000f) + 1,
+ (int)Math.floor(borderRect.height * 1000f) + 1);
+ //Add one pixel wide safety margin around the paint area
+ int pixelWidth = (int)Math.round(UnitConv.in2mpt(1) / userAgent.getTargetResolution());
+ final int xoffset = (int)Math.round(-effBorderRect.x * 1000f) + pixelWidth;
+ final int yoffset = pixelWidth;
+ paintRect.x += xoffset;
+ paintRect.y += yoffset;
+ paintRect.width += 2 * pixelWidth;
+ paintRect.height += 2 * pixelWidth;
+
+ RendererContext rc = createRendererContext(paintRect.x, paintRect.y,
+ paintRect.width, paintRect.height, null);
+ Map atts = new java.util.HashMap();
+ atts.put(CONV_MODE, "bitmap");
+ atts.put(SRC_TRANSPARENCY, "true");
+ rc.setProperty(RendererContextConstants.FOREIGN_ATTRIBUTES, atts);
+
+ Graphics2DImagePainter painter = new Graphics2DImagePainter() {
+
+ public void paint(Graphics2D g2d, Rectangle2D area) {
+ g2d.translate(xoffset, yoffset);
+ g2d.scale(1000, 1000);
+ float startx = effBorderRect.x;
+ float starty = effBorderRect.y;
+ float width = effBorderRect.width;
+ float height = effBorderRect.height;
+ boolean[] b = new boolean[] {
+ (bpsBefore != null), (bpsEnd != null),
+ (bpsAfter != null), (bpsStart != null)};
+ if (!b[0] && !b[1] && !b[2] && !b[3]) {
+ return;
+ }
+ float[] bw = new float[] {
+ (b[0] ? bpsBefore.width / 1000f : 0.0f),
+ (b[1] ? bpsEnd.width / 1000f : 0.0f),
+ (b[2] ? bpsAfter.width / 1000f : 0.0f),
+ (b[3] ? bpsStart.width / 1000f : 0.0f)};
+ float[] clipw = new float[] {
+ BorderProps.getClippedWidth(bpsBefore) / 1000f,
+ BorderProps.getClippedWidth(bpsEnd) / 1000f,
+ BorderProps.getClippedWidth(bpsAfter) / 1000f,
+ BorderProps.getClippedWidth(bpsStart) / 1000f};
+ starty += clipw[0];
+ height -= clipw[0];
+ height -= clipw[2];
+ startx += clipw[3];
+ width -= clipw[3];
+ width -= clipw[1];
+
+ boolean[] slant = new boolean[] {
+ (b[3] && b[0]), (b[0] && b[1]), (b[1] && b[2]), (b[2] && b[3])};
+ if (bpsBefore != null) {
+ //endTextObject();
+
+ float sx1 = startx;
+ float sx2 = (slant[0] ? sx1 + bw[3] - clipw[3] : sx1);
+ float ex1 = startx + width;
+ float ex2 = (slant[1] ? ex1 - bw[1] + clipw[1] : ex1);
+ float outery = starty - clipw[0];
+ float clipy = outery + clipw[0];
+ float innery = outery + bw[0];
+
+ //saveGraphicsState();
+ Graphics2D g = (Graphics2D)g2d.create();
+ moveTo(sx1, clipy);
+ float sx1a = sx1;
+ float ex1a = ex1;
+ if (bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
+ if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
+ sx1a -= clipw[3];
+ }
+ if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
+ ex1a += clipw[1];
+ }
+ lineTo(sx1a, outery);
+ lineTo(ex1a, outery);
+ }
+ lineTo(ex1, clipy);
+ lineTo(ex2, innery);
+ lineTo(sx2, innery);
+ closePath();
+ //clip();
+ g.clip(currentPath);
+ currentPath = null;
+ Rectangle2D.Float lineRect = new Rectangle2D.Float(
+ sx1a, outery, ex1a - sx1a, innery - outery);
+ Java2DRenderer.drawBorderLine(lineRect, true, true,
+ bpsBefore.style, bpsBefore.color, g);
+ //restoreGraphicsState();
+ }
+ if (bpsEnd != null) {
+ //endTextObject();
+
+ float sy1 = starty;
+ float sy2 = (slant[1] ? sy1 + bw[0] - clipw[0] : sy1);
+ float ey1 = starty + height;
+ float ey2 = (slant[2] ? ey1 - bw[2] + clipw[2] : ey1);
+ float outerx = startx + width + clipw[1];
+ float clipx = outerx - clipw[1];
+ float innerx = outerx - bw[1];
+
+ //saveGraphicsState();
+ Graphics2D g = (Graphics2D)g2d.create();
+ moveTo(clipx, sy1);
+ float sy1a = sy1;
+ float ey1a = ey1;
+ if (bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
+ if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
+ sy1a -= clipw[0];
+ }
+ if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
+ ey1a += clipw[2];
+ }
+ lineTo(outerx, sy1a);
+ lineTo(outerx, ey1a);
+ }
+ lineTo(clipx, ey1);
+ lineTo(innerx, ey2);
+ lineTo(innerx, sy2);
+ closePath();
+ //clip();
+ g.setClip(currentPath);
+ currentPath = null;
+ Rectangle2D.Float lineRect = new Rectangle2D.Float(
+ innerx, sy1a, outerx - innerx, ey1a - sy1a);
+ Java2DRenderer.drawBorderLine(lineRect, false, false,
+ bpsEnd.style, bpsEnd.color, g);
+ //restoreGraphicsState();
+ }
+ if (bpsAfter != null) {
+ //endTextObject();
+
+ float sx1 = startx;
+ float sx2 = (slant[3] ? sx1 + bw[3] - clipw[3] : sx1);
+ float ex1 = startx + width;
+ float ex2 = (slant[2] ? ex1 - bw[1] + clipw[1] : ex1);
+ float outery = starty + height + clipw[2];
+ float clipy = outery - clipw[2];
+ float innery = outery - bw[2];
+
+ //saveGraphicsState();
+ Graphics2D g = (Graphics2D)g2d.create();
+ moveTo(ex1, clipy);
+ float sx1a = sx1;
+ float ex1a = ex1;
+ if (bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
+ if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
+ sx1a -= clipw[3];
+ }
+ if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
+ ex1a += clipw[1];
+ }
+ lineTo(ex1a, outery);
+ lineTo(sx1a, outery);
+ }
+ lineTo(sx1, clipy);
+ lineTo(sx2, innery);
+ lineTo(ex2, innery);
+ closePath();
+ //clip();
+ g.setClip(currentPath);
+ currentPath = null;
+ Rectangle2D.Float lineRect = new Rectangle2D.Float(
+ sx1a, innery, ex1a - sx1a, outery - innery);
+ Java2DRenderer.drawBorderLine(lineRect, true, false,
+ bpsAfter.style, bpsAfter.color, g);
+ //restoreGraphicsState();
+ }
+ if (bpsStart != null) {
+ //endTextObject();
+
+ float sy1 = starty;
+ float sy2 = (slant[0] ? sy1 + bw[0] - clipw[0] : sy1);
+ float ey1 = sy1 + height;
+ float ey2 = (slant[3] ? ey1 - bw[2] + clipw[2] : ey1);
+ float outerx = startx - clipw[3];
+ float clipx = outerx + clipw[3];
+ float innerx = outerx + bw[3];
+
+ //saveGraphicsState();
+ Graphics2D g = (Graphics2D)g2d.create();
+ moveTo(clipx, ey1);
+ float sy1a = sy1;
+ float ey1a = ey1;
+ if (bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
+ if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
+ sy1a -= clipw[0];
+ }
+ if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
+ ey1a += clipw[2];
+ }
+ lineTo(outerx, ey1a);
+ lineTo(outerx, sy1a);
+ }
+ lineTo(clipx, sy1);
+ lineTo(innerx, sy2);
+ lineTo(innerx, ey2);
+ closePath();
+ //clip();
+ g.setClip(currentPath);
+ currentPath = null;
+ Rectangle2D.Float lineRect = new Rectangle2D.Float(
+ outerx, sy1a, innerx - outerx, ey1a - sy1a);
+ Java2DRenderer.drawBorderLine(lineRect, false, false,
+ bpsStart.style, bpsStart.color, g);
+ //restoreGraphicsState();
+ }
+ }
+
+ public Dimension getImageSize() {
+ return paintRect.getSize();
+ }
+
+ };
+ try {
+ g2a.paintImage(painter, rc,
+ paintRect.x - xoffset, paintRect.y, paintRect.width, paintRect.height);
+ } catch (IOException ioe) {
+ handleIOTrouble(ioe);
+ }
+ }
+
+
+
+}
--- /dev/null
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.fop.render.pcl;
+
+import org.apache.fop.fo.extensions.ExtensionElementMapping;
+import org.apache.fop.render.RendererContext;
+import org.apache.fop.util.QName;
+
+/**
+ * Wrapper on the RendererContext to access the information structure for drawing
+ * the XML document.
+ */
+public class PCLRendererContext extends RendererContext.RendererContextWrapper {
+
+ /**
+ * Wrap the render context to allow easier access to its values.
+ *
+ * @param context the renderer context
+ * @return the PCL-specific renderer context wrapper
+ */
+ public static PCLRendererContext wrapRendererContext(RendererContext context) {
+ PCLRendererContext pcli = new PCLRendererContext(context);
+ return pcli;
+ }
+
+ /**
+ * Main constructor
+ * @param context the RendererContent instance
+ */
+ public PCLRendererContext(RendererContext context) {
+ super(context);
+ }
+
+ /** @return true if the SVG image should be rendered as a bitmap */
+ public boolean paintAsBitmap() {
+ QName qName = new QName(ExtensionElementMapping.URI, null, "conversion-mode");
+ return getForeignAttributes() != null
+ && "bitmap".equalsIgnoreCase((String)getForeignAttributes().get(qName));
+ }
+
+ /** @return true if clipping is disabled inside the PCLGraphics2D. */
+ public boolean isClippingDisabled() {
+ QName qName = new QName(ExtensionElementMapping.URI, null, "disable-clipping");
+ return getForeignAttributes() != null
+ && "true".equalsIgnoreCase((String)getForeignAttributes().get(qName));
+ }
+
+ public boolean isSourceTransparency() {
+ QName qName = new QName(ExtensionElementMapping.URI, null, "source-transparency");
+ return getForeignAttributes() != null
+ && "true".equalsIgnoreCase((String)getForeignAttributes().get(qName));
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright 2005 The Apache Software Foundation.\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+package org.apache.fop.render.pcl;\r
+\r
+import org.apache.fop.apps.FOUserAgent;\r
+import org.apache.fop.apps.MimeConstants;\r
+import org.apache.fop.render.AbstractRendererMaker;\r
+import org.apache.fop.render.Renderer;\r
+\r
+/**\r
+ * RendererMaker for the PCL Renderer.\r
+ */\r
+public class PCLRendererMaker extends AbstractRendererMaker {\r
+\r
+ private static final String[] MIMES = new String[] {\r
+ MimeConstants.MIME_PCL,\r
+ MimeConstants.MIME_PCL_ALT};\r
+ \r
+ \r
+ /**@see org.apache.fop.render.AbstractRendererMaker */\r
+ public Renderer makeRenderer(FOUserAgent ua) {\r
+ return new PCLRenderer();\r
+ }\r
+\r
+ /** @see org.apache.fop.render.AbstractRendererMaker#needsOutputStream() */\r
+ public boolean needsOutputStream() {\r
+ return true;\r
+ }\r
+\r
+ /** @see org.apache.fop.render.AbstractRendererMaker#getSupportedMimeTypes() */\r
+ public String[] getSupportedMimeTypes() {\r
+ return MIMES;\r
+ }\r
+\r
+}\r
--- /dev/null
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.fop.render.pcl;
+
+// FOP
+import org.apache.fop.render.AbstractGenericSVGHandler;
+import org.apache.fop.render.Renderer;
+
+/**
+ * PCL XML handler for SVG. Uses Apache Batik for SVG processing.
+ * This handler handles XML for foreign objects when rendering to HP GL/2.
+ * It renders SVG to HP GL/2 using the PCLGraphics2D.
+ * @see PCLGraphics2DAdapter
+ */
+public class PCLSVGHandler extends AbstractGenericSVGHandler {
+
+ /** @see org.apache.fop.render.XMLHandler#supportsRenderer(org.apache.fop.render.Renderer) */
+ public boolean supportsRenderer(Renderer renderer) {
+ return (renderer instanceof PCLRenderer);
+ }
+
+}
+
--- /dev/null
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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: AFPElementMapping.java 397875 2006-04-28 11:58:33Z manuel $ */
+
+package org.apache.fop.render.pcl.extensions;
+
+import java.util.HashMap;
+
+import org.apache.fop.fo.ElementMapping;
+
+/**
+ * PCL-specific extensions for Apache FOP.
+ */
+public class PCLElementMapping extends ElementMapping {
+
+ /** The namespace used for PCL extensions */
+ public static final String NAMESPACE = "http://xmlgraphics.apache.org/fop/extensions/pcl";
+
+ /** The usual namespace prefix used for PCL extensions */
+ public static final String NAMESPACE_PREFIX = "pcl";
+
+ /** Main constructor */
+ public PCLElementMapping() {
+ this.namespaceURI = NAMESPACE;
+ }
+
+ /** @see org.apache.fop.fo.ElementMapping#initialize() */
+ protected void initialize() {
+
+ if (foObjs == null) {
+ foObjs = new HashMap();
+ //No extension elements, yet, only attributes
+ }
+
+ }
+
+}
--- /dev/null
+<!--
+ Copyright 2005-2006 The Apache Software Foundation
+
+ Licensed 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$ -->
+<HTML>
+<TITLE>org.apache.fop.render.pcl Package</TITLE>
+<BODY>
+<P>PCL Renderer (Supports PCL5 and HP GL/2)</P>
+</BODY>
+</HTML>
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed 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.fop.render.pcl;
-
-import java.awt.RenderingHints;
-import java.awt.color.ColorSpace;
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorConvertOp;
-import java.awt.image.RenderedImage;
-
-/**
- * Default implementation of the MonochromeBitmapConverter which uses the Java Class Library
- * to convert grayscale bitmaps to monochrome bitmaps.
- */
-public class DefaultMonochromeBitmapConverter implements
- MonochromeBitmapConverter {
-
- /** @see MonochromeBitmapConverter#setHint(java.lang.String, java.lang.String) */
- public void setHint(String name, String value) {
- //ignore, not supported
- }
-
- /** @see MonochromeBitmapConverter#convertToMonochrome(java.awt.image.BufferedImage) */
- public RenderedImage convertToMonochrome(BufferedImage img) {
- BufferedImage buf = new BufferedImage(img.getWidth(), img.getHeight(),
- BufferedImage.TYPE_BYTE_BINARY);
- RenderingHints hints = new RenderingHints(null);
- //This hint doesn't seem to make a difference :-(
- hints.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
- ColorConvertOp op = new ColorConvertOp(
- ColorSpace.getInstance(ColorSpace.CS_GRAY), hints);
- op.filter(img, buf);
- return buf;
- }
-
-}
+++ /dev/null
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed 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.fop.render.pcl;
-
-import java.awt.RenderingHints;
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorModel;
-import java.awt.image.DataBuffer;
-import java.awt.image.IndexColorModel;
-import java.awt.image.RenderedImage;
-import java.awt.image.renderable.ParameterBlock;
-
-import javax.media.jai.ColorCube;
-import javax.media.jai.ImageLayout;
-import javax.media.jai.JAI;
-import javax.media.jai.KernelJAI;
-import javax.media.jai.LookupTableJAI;
-import javax.media.jai.PlanarImage;
-
-/**
- * Implementation of the MonochromeBitmapConverter which uses Java Advanced Imaging (JAI)
- * to convert grayscale bitmaps to monochrome bitmaps. JAI provides better dithering options
- * including error diffusion dithering.
- * <p>
- * If you call setHint("quality", "true") on the instance you can enabled error diffusion
- * dithering which produces a nicer result but is also a lot slower.
- */
-public class JAIMonochromeBitmapConverter implements
- MonochromeBitmapConverter {
-
- private boolean isErrorDiffusion = false;
-
- /** @see MonochromeBitmapConverter#setHint(java.lang.String, java.lang.String) */
- public void setHint(String name, String value) {
- if ("quality".equalsIgnoreCase(name)) {
- isErrorDiffusion = "true".equalsIgnoreCase(value);
- }
- }
-
- /** @see MonochromeBitmapConverter#convertToMonochrome(java.awt.image.BufferedImage) */
- public RenderedImage convertToMonochrome(BufferedImage img) {
- if (img.getColorModel().getColorSpace().getNumComponents() != 1) {
- throw new IllegalArgumentException("Source image must be a grayscale image!");
- }
-
- // Load the ParameterBlock for the dithering operation
- // and set the operation name.
- ParameterBlock pb = new ParameterBlock();
- pb.addSource(img);
- String opName = null;
- if (isErrorDiffusion) {
- opName = "errordiffusion";
- LookupTableJAI lut = new LookupTableJAI(new byte[] {(byte)0x00, (byte)0xff});
- pb.add(lut);
- pb.add(KernelJAI.ERROR_FILTER_FLOYD_STEINBERG);
- } else {
- opName = "ordereddither";
- //Create the color cube.
- ColorCube colorMap = ColorCube.createColorCube(DataBuffer.TYPE_BYTE,
- 0, new int[] {2});
- pb.add(colorMap);
- pb.add(KernelJAI.DITHER_MASK_441);
- }
-
- //Create an image layout for a monochrome b/w image
- ImageLayout layout = new ImageLayout();
- byte[] map = new byte[] {(byte)0x00, (byte)0xff};
- ColorModel cm = new IndexColorModel(1, 2, map, map, map);
- layout.setColorModel(cm);
-
- // Create a hint containing the layout.
- RenderingHints hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout);
-
- // Dither the image.
- PlanarImage dst = JAI.create(opName, pb, hints);
-
- //Convert it to a BufferedImage
- return dst.getAsBufferedImage();
- }
-
-}
+++ /dev/null
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed 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.fop.render.pcl;
-
-import java.awt.image.BufferedImage;
-import java.awt.image.RenderedImage;
-
-/**
- * Interface for converters that convert grayscale images to monochrome (1-bit) bitmap images.
- */
-public interface MonochromeBitmapConverter {
-
- /**
- * Sets a hint to the implementation
- * @param name the name of the hint
- * @param value the value
- */
- void setHint(String name, String value);
-
- /**
- * Converts a grayscale bitmap image to a monochrome (1-bit) b/w bitmap image.
- * @param img the grayscale image
- * @return the converted monochrome image
- */
- RenderedImage convertToMonochrome(BufferedImage img);
-
-}
+++ /dev/null
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed 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.fop.render.pcl;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Graphics2D;
-import java.awt.color.ColorSpace;
-import java.awt.geom.AffineTransform;
-import java.awt.image.BufferedImage;
-import java.awt.image.BufferedImageOp;
-import java.awt.image.ByteLookupTable;
-import java.awt.image.ColorConvertOp;
-import java.awt.image.ColorModel;
-import java.awt.image.DataBuffer;
-import java.awt.image.IndexColorModel;
-import java.awt.image.LookupOp;
-import java.awt.image.Raster;
-import java.awt.image.RenderedImage;
-import java.awt.image.WritableRaster;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.util.Locale;
-
-import org.apache.fop.util.UnitConv;
-import org.apache.xmlgraphics.image.GraphicsUtil;
-
-/**
- * This class provides methods for generating PCL print files.
- */
-public class PCLGenerator {
-
- /** The ESC (escape) character */
- public static final char ESC = '\033';
-
- /** A list of all supported resolutions in PCL (values in dpi) */
- public static final int[] PCL_RESOLUTIONS = new int[] {75, 100, 150, 200, 300, 600};
-
- private final DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US);
- private final DecimalFormat df2 = new DecimalFormat("0.##", symbols);
- private final DecimalFormat df4 = new DecimalFormat("0.####", symbols);
-
- private OutputStream out;
-
- private boolean currentSourceTransparency = true;
- private boolean currentPatternTransparency = true;
-
- private int maxBitmapResolution = PCL_RESOLUTIONS[PCL_RESOLUTIONS.length - 1];
-
- /**
- * Main constructor.
- * @param out the OutputStream to write the PCL stream to
- */
- public PCLGenerator(OutputStream out) {
- this.out = out;
- }
-
- /**
- * Main constructor.
- * @param out the OutputStream to write the PCL stream to
- * @param maxResolution the maximum resolution to encode bitmap images at
- */
- public PCLGenerator(OutputStream out, int maxResolution) {
- this(out);
- boolean found = false;
- for (int i = 0; i < PCL_RESOLUTIONS.length; i++) {
- if (PCL_RESOLUTIONS[i] == maxResolution) {
- found = true;
- break;
- }
- }
- if (!found) {
- throw new IllegalArgumentException("Illegal value for maximum resolution!");
- }
- this.maxBitmapResolution = maxResolution;
- }
-
- /** @return the OutputStream that this generator writes to */
- public OutputStream getOutputStream() {
- return this.out;
- }
-
- /** @return the maximum resolution to encode bitmap images at */
- public int getMaximumBitmapResolution() {
- return this.maxBitmapResolution;
- }
-
- /**
- * Writes a PCL escape command to the output stream.
- * @param cmd the command (without the ESCAPE character)
- * @throws IOException In case of an I/O error
- */
- public void writeCommand(String cmd) throws IOException {
- out.write(27); //ESC
- out.write(cmd.getBytes("US-ASCII"));
- }
-
- /**
- * Writes raw text (in ISO-8859-1 encoding) to the output stream.
- * @param s the text
- * @throws IOException In case of an I/O error
- */
- public void writeText(String s) throws IOException {
- out.write(s.getBytes("ISO-8859-1"));
- }
-
- /**
- * Formats a double value with two decimal positions for PCL output.
- *
- * @param value value to format
- * @return the formatted value
- */
- public final String formatDouble2(double value) {
- return df2.format(value);
- }
-
- /**
- * Formats a double value with four decimal positions for PCL output.
- *
- * @param value value to format
- * @return the formatted value
- */
- public final String formatDouble4(double value) {
- return df4.format(value);
- }
-
- /**
- * Sends the universal end of language command (UEL).
- * @throws IOException In case of an I/O error
- */
- public void universalEndOfLanguage() throws IOException {
- writeCommand("%-12345X");
- }
-
- /**
- * Resets the printer and restores the user default environment.
- * @throws IOException In case of an I/O error
- */
- public void resetPrinter() throws IOException {
- writeCommand("E");
- }
-
- /**
- * Sends the job separation command.
- * @throws IOException In case of an I/O error
- */
- public void separateJobs() throws IOException {
- writeCommand("&l1T");
- }
-
- /**
- * Sends the form feed character.
- * @throws IOException In case of an I/O error
- */
- public void formFeed() throws IOException {
- out.write(12); //=OC ("FF", Form feed)
- }
-
- /**
- * Sets the unit of measure.
- * @param value the resolution value (units per inch)
- * @throws IOException In case of an I/O error
- */
- public void setUnitOfMeasure(int value) throws IOException {
- writeCommand("&u" + value + "D");
- }
-
- /**
- * Sets the raster graphics resolution
- * @param value the resolution value (units per inch)
- * @throws IOException In case of an I/O error
- */
- public void setRasterGraphicsResolution(int value) throws IOException {
- writeCommand("*t" + value + "R");
- }
-
- /**
- * Selects the page size.
- * @param selector the integer representing the page size
- * @throws IOException In case of an I/O error
- */
- public void selectPageSize(int selector) throws IOException {
- writeCommand("&l" + selector + "A");
- }
-
- /**
- * Selects the paper source. The parameter is usually printer-specific. Usually, "1" is the
- * default tray, "2" is the manual paper feed, "3" is the manual envelope feed, "4" is the
- * "lower" tray and "7" is "auto-select". Consult the technical reference for your printer
- * for all available values.
- * @param selector the integer representing the paper source/tray
- * @throws IOException In case of an I/O error
- */
- public void selectPaperSource(int selector) throws IOException {
- writeCommand("&l" + selector + "H");
- }
-
- /**
- * Clears the horizontal margins.
- * @throws IOException In case of an I/O error
- */
- public void clearHorizontalMargins() throws IOException {
- writeCommand("9");
- }
-
- /**
- * The Top Margin command designates the number of lines between
- * the top of the logical page and the top of the text area.
- * @param numberOfLines the number of lines (See PCL specification for details)
- * @throws IOException In case of an I/O error
- */
- public void setTopMargin(int numberOfLines) throws IOException {
- writeCommand("&l" + numberOfLines + "E");
- }
-
- /**
- * The Text Length command can be used to define the bottom border. See the PCL specification
- * for details.
- * @param numberOfLines the number of lines
- * @throws IOException In case of an I/O error
- */
- public void setTextLength(int numberOfLines) throws IOException {
- writeCommand("&l" + numberOfLines + "F");
- }
-
- /**
- * Sets the Vertical Motion Index (VMI).
- * @param value the VMI value
- * @throws IOException In case of an I/O error
- */
- public void setVMI(double value) throws IOException {
- writeCommand("&l" + formatDouble4(value) + "C");
- }
-
- /**
- * Sets the cursor to a new absolute coordinate.
- * @param x the X coordinate (in millipoints)
- * @param y the Y coordinate (in millipoints)
- * @throws IOException In case of an I/O error
- */
- public void setCursorPos(double x, double y) throws IOException {
- if (x < 0) {
- //A negative x value will result in a relative movement so go to "0" first.
- //But this will most probably have no effect anyway since you can't paint to the left
- //of the logical page
- writeCommand("&a0h" + formatDouble2(x / 100) + "h" + formatDouble2(y / 100) + "V");
- } else {
- writeCommand("&a" + formatDouble2(x / 100) + "h" + formatDouble2(y / 100) + "V");
- }
- }
-
- /**
- * Pushes the current cursor position on a stack (stack size: max 20 entries)
- * @throws IOException In case of an I/O error
- */
- public void pushCursorPos() throws IOException {
- writeCommand("&f0S");
- }
-
- /**
- * Pops the current cursor position from the stack.
- * @throws IOException In case of an I/O error
- */
- public void popCursorPos() throws IOException {
- writeCommand("&f1S");
- }
-
- /**
- * Changes the current print direction while maintaining the current cursor position.
- * @param rotate the rotation angle (counterclockwise), one of 0, 90, 180 and 270.
- * @throws IOException In case of an I/O error
- */
- public void changePrintDirection(int rotate) throws IOException {
- writeCommand("&a" + rotate + "P");
- }
-
- /**
- * Enters the HP GL/2 mode.
- * @param restorePreviousHPGL2Cursor true if the previous HP GL/2 pen position should be
- * restored, false if the current position is maintained
- * @throws IOException In case of an I/O error
- */
- public void enterHPGL2Mode(boolean restorePreviousHPGL2Cursor) throws IOException {
- if (restorePreviousHPGL2Cursor) {
- writeCommand("%0B");
- } else {
- writeCommand("%1B");
- }
- }
-
- /**
- * Enters the PCL mode.
- * @param restorePreviousPCLCursor true if the previous PCL cursor position should be restored,
- * false if the current position is maintained
- * @throws IOException In case of an I/O error
- */
- public void enterPCLMode(boolean restorePreviousPCLCursor) throws IOException {
- if (restorePreviousPCLCursor) {
- writeCommand("%0A");
- } else {
- writeCommand("%1A");
- }
- }
-
- /**
- * Generate a filled rectangle at the current cursor position.
- *
- * @param w the width in millipoints
- * @param h the height in millipoints
- * @param col the fill color
- * @throws IOException In case of an I/O error
- */
- protected void fillRect(int w, int h, Color col) throws IOException {
- if ((w == 0) || (h == 0)) {
- return;
- }
- if (h < 0) {
- h *= -1;
- } else {
- //y += h;
- }
-
- setPatternTransparencyMode(false);
- writeCommand("*c" + formatDouble4(w / 100) + "h"
- + formatDouble4(h / 100) + "V");
- int lineshade = convertToPCLShade(col);
- writeCommand("*c" + lineshade + "G");
- writeCommand("*c2P");
- // Reset pattern transparency mode.
- setPatternTransparencyMode(true);
- }
-
- /**
- * Sets the source transparency mode.
- * @param transparent true if transparent, false for opaque
- * @throws IOException In case of an I/O error
- */
- public void setSourceTransparencyMode(boolean transparent) throws IOException {
- setTransparencyMode(transparent, currentPatternTransparency);
- }
-
- /**
- * Sets the pattern transparency mode.
- * @param transparent true if transparent, false for opaque
- * @throws IOException In case of an I/O error
- */
- public void setPatternTransparencyMode(boolean transparent) throws IOException {
- setTransparencyMode(currentSourceTransparency, transparent);
- }
-
- /**
- * Sets the transparency modes.
- * @param source source transparency: true if transparent, false for opaque
- * @param pattern pattern transparency: true if transparent, false for opaque
- * @throws IOException In case of an I/O error
- */
- public void setTransparencyMode(boolean source, boolean pattern) throws IOException {
- if (source != currentSourceTransparency && pattern != currentPatternTransparency) {
- writeCommand("*v" + (source ? '0' : '1') + "n" + (pattern ? '0' : '1') + "O");
- } else if (source != currentSourceTransparency) {
- writeCommand("*v" + (source ? '0' : '1') + "N");
- } else if (pattern != currentPatternTransparency) {
- writeCommand("*v" + (pattern ? '0' : '1') + "O");
- }
- this.currentSourceTransparency = source;
- this.currentPatternTransparency = pattern;
- }
-
- /**
- * Convert an RGB color value to a grayscale from 0 to 100.
- * @param r the red component
- * @param g the green component
- * @param b the blue component
- * @return the gray value
- */
- public final int convertToGray(int r, int g, int b) {
- return (r * 30 + g * 59 + b * 11) / 100;
- }
-
- /**
- * Convert a Color value to a PCL shade value (0-100).
- * @param col the color
- * @return the PCL shade value (100=black)
- */
- public final int convertToPCLShade(Color col) {
- float gray = convertToGray(col.getRed(), col.getGreen(), col.getBlue()) / 255f;
- return (int)(100 - (gray * 100f));
- }
-
- /**
- * Select the current pattern
- * @param patternID the pattern ID (<ESC>*c#G command)
- * @param pattern the pattern type (<ESC>*v#T command)
- * @throws IOException In case of an I/O error
- */
- public void selectCurrentPattern(int patternID, int pattern) throws IOException {
- if (pattern > 1) {
- writeCommand("*c" + patternID + "G");
- }
- writeCommand("*v" + pattern + "T");
- }
-
- /**
- * Indicates whether an image is a monochrome (b/w) image.
- * @param img the image
- * @return true if it's a monochrome image
- */
- public static boolean isMonochromeImage(RenderedImage img) {
- ColorModel cm = img.getColorModel();
- if (cm instanceof IndexColorModel) {
- IndexColorModel icm = (IndexColorModel)cm;
- return icm.getMapSize() == 2;
- } else {
- return false;
- }
- }
-
- /**
- * Indicates whether an image is a grayscale image.
- * @param img the image
- * @return true if it's a grayscale image
- */
- public static boolean isGrayscaleImage(RenderedImage img) {
- return (img.getColorModel().getColorSpace().getNumComponents() == 1);
- }
-
- private MonochromeBitmapConverter createMonochromeBitmapConverter() {
- MonochromeBitmapConverter converter = null;
- try {
- String clName = "org.apache.fop.render.pcl.JAIMonochromeBitmapConverter";
- Class clazz = Class.forName(clName);
- converter = (MonochromeBitmapConverter)clazz.newInstance();
- } catch (ClassNotFoundException cnfe) {
- // Class was not compiled so is not available. Simply ignore.
- } catch (LinkageError le) {
- // This can happen if fop was build with support for a
- // particular provider (e.g. a binary fop distribution)
- // but the required support files (i.e. JAI) are not
- // available in the current runtime environment.
- // Simply continue with the backup implementation.
- } catch (InstantiationException e) {
- // Problem instantiating the class, simply continue with the backup implementation
- } catch (IllegalAccessException e) {
- // Problem instantiating the class, simply continue with the backup implementation
- }
- if (converter == null) {
- converter = new DefaultMonochromeBitmapConverter();
- }
- return converter;
- }
-
- private int calculatePCLResolution(int resolution) {
- return calculatePCLResolution(resolution, false);
- }
-
- /**
- * Calculates the ideal PCL resolution for a given resolution.
- * @param resolution the input resolution
- * @param increased true if you want to go to a higher resolution, for example if you
- * convert grayscale or color images to monochrome images so dithering has
- * a chance to generate better quality.
- * @return the resulting PCL resolution (one of 75, 100, 150, 200, 300, 600)
- */
- private int calculatePCLResolution(int resolution, boolean increased) {
- int choice = -1;
- for (int i = PCL_RESOLUTIONS.length - 2; i >= 0; i--) {
- if (resolution > PCL_RESOLUTIONS[i]) {
- int idx = i + 1;
- if (idx < PCL_RESOLUTIONS.length - 2) {
- idx += increased ? 2 : 0;
- } else if (idx < PCL_RESOLUTIONS.length - 1) {
- idx += increased ? 1 : 0;
- }
- choice = idx;
- break;
- //return PCL_RESOLUTIONS[idx];
- }
- }
- if (choice < 0) {
- choice = (increased ? 2 : 0);
- }
- while (choice > 0 && PCL_RESOLUTIONS[choice] > getMaximumBitmapResolution()) {
- choice--;
- }
- return PCL_RESOLUTIONS[choice];
- }
-
- private boolean isValidPCLResolution(int resolution) {
- return resolution == calculatePCLResolution(resolution);
- }
-
- private Dimension getAdjustedDimension(Dimension orgDim, double orgResolution,
- int pclResolution) {
- if (orgResolution == pclResolution) {
- return orgDim;
- } else {
- Dimension result = new Dimension();
- result.width = (int)Math.round((double)orgDim.width * pclResolution / orgResolution);
- result.height = (int)Math.round((double)orgDim.height * pclResolution / orgResolution);
- return result;
- }
- }
-
- //Threshold table to convert an alpha channel (8-bit) into a clip mask (1-bit)
- private static final byte[] THRESHOLD_TABLE = new byte[256];
- static { // Initialize the arrays
- for (int i = 0; i < 256; i++) {
- THRESHOLD_TABLE[i] = (byte) ((i < 240) ? 255 : 0);
- }
- }
-
- private RenderedImage getMask(RenderedImage img, Dimension targetDim) {
- ColorModel cm = img.getColorModel();
- if (cm.hasAlpha()) {
- BufferedImage alpha = new BufferedImage(img.getWidth(), img.getHeight(),
- BufferedImage.TYPE_BYTE_GRAY);
- Raster raster = img.getData();
- GraphicsUtil.copyBand(raster, cm.getNumColorComponents(), alpha.getRaster(), 0);
-
- BufferedImageOp op1 = new LookupOp(new ByteLookupTable(0, THRESHOLD_TABLE), null);
- BufferedImage alphat = op1.filter(alpha, null);
-
- BufferedImage mask;
- if (true) {
- mask = new BufferedImage(targetDim.width, targetDim.height,
- BufferedImage.TYPE_BYTE_BINARY);
- } else {
- byte[] arr = {(byte)0, (byte)0xff};
- ColorModel colorModel = new IndexColorModel(1, 2, arr, arr, arr);
- WritableRaster wraster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
- targetDim.width, targetDim.height, 1, 1, null);
- mask = new BufferedImage(colorModel, wraster, false, null);
- }
-
- Graphics2D g2d = mask.createGraphics();
- try {
- AffineTransform at = new AffineTransform();
- double sx = targetDim.getWidth() / img.getWidth();
- double sy = targetDim.getHeight() / img.getHeight();
- at.scale(sx, sy);
- g2d.drawRenderedImage(alphat, at);
- } finally {
- g2d.dispose();
- }
- /*
- try {
- BatchDiffer.saveAsPNG(alpha, new java.io.File("D:/out-alpha.png"));
- BatchDiffer.saveAsPNG(mask, new java.io.File("D:/out-mask.png"));
- } catch (IOException e) {
- e.printStackTrace();
- }*/
- return mask;
- } else {
- return null;
- }
- }
-
- /**
- * Paint a bitmap at the current cursor position. The bitmap is converted to a monochrome
- * (1-bit) bitmap image.
- * @param img the bitmap image
- * @param targetDim the target Dimention (in mpt)
- * @param sourceTransparency true if the background should not be erased
- * @throws IOException In case of an I/O error
- */
- public void paintBitmap(RenderedImage img, Dimension targetDim, boolean sourceTransparency)
- throws IOException {
- double targetResolution = img.getWidth() / UnitConv.mpt2in(targetDim.width);
- int resolution = (int)Math.round(targetResolution);
- int effResolution = calculatePCLResolution(resolution, true);
- Dimension orgDim = new Dimension(img.getWidth(), img.getHeight());
- Dimension effDim = getAdjustedDimension(orgDim, targetResolution, effResolution);
- boolean scaled = !orgDim.equals(effDim);
-
- boolean monochrome = isMonochromeImage(img);
- if (!monochrome) {
- //Transparency mask disabled. Doesn't work reliably
- final boolean transparencyDisabled = true;
- RenderedImage mask = (transparencyDisabled ? null : getMask(img, effDim));
- if (mask != null) {
- pushCursorPos();
- selectCurrentPattern(0, 1); //Solid white
- setTransparencyMode(true, true);
- paintMonochromeBitmap(mask, effResolution);
- popCursorPos();
- }
-
- BufferedImage src = null;
- if (img instanceof BufferedImage && !scaled) {
- if (!isGrayscaleImage(img) || img.getColorModel().hasAlpha()) {
- src = new BufferedImage(effDim.width, effDim.height,
- BufferedImage.TYPE_BYTE_GRAY);
- ColorConvertOp op = new ColorConvertOp(
- ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
- op.filter((BufferedImage)img, src);
- } else {
- src = (BufferedImage)img;
- }
- }
- if (src == null) {
- src = new BufferedImage(effDim.width, effDim.height,
- BufferedImage.TYPE_BYTE_GRAY);
- Graphics2D g2d = src.createGraphics();
- try {
- AffineTransform at = new AffineTransform();
- double sx = effDim.getWidth() / orgDim.getWidth();
- double sy = effDim.getHeight() / orgDim.getHeight();
- at.scale(sx, sy);
- g2d.drawRenderedImage(img, at);
- } finally {
- g2d.dispose();
- }
- }
- MonochromeBitmapConverter converter = createMonochromeBitmapConverter();
- converter.setHint("quality", "false");
-
- BufferedImage buf = (BufferedImage)converter.convertToMonochrome(src);
-
- RenderedImage red = buf;
- selectCurrentPattern(0, 0); //Solid black
- setTransparencyMode(sourceTransparency || mask != null, true);
- paintMonochromeBitmap(red, effResolution);
- } else {
- //TODO untested!
- RenderedImage effImg = img;
- if (scaled) {
- BufferedImage buf = new BufferedImage(effDim.width, effDim.height,
- BufferedImage.TYPE_BYTE_BINARY);
- Graphics2D g2d = buf.createGraphics();
- try {
- AffineTransform at = new AffineTransform();
- double sx = effDim.getWidth() / orgDim.getWidth();
- double sy = effDim.getHeight() / orgDim.getHeight();
- at.scale(sx, sy);
- g2d.drawRenderedImage(img, at);
- } finally {
- g2d.dispose();
- }
- effImg = buf;
- }
- setSourceTransparencyMode(sourceTransparency);
- selectCurrentPattern(0, 0); //Solid black
- paintMonochromeBitmap(effImg, effResolution);
- }
- }
-
- /**
- * Paint a bitmap at the current cursor position. The bitmap must be a monochrome
- * (1-bit) bitmap image.
- * @param img the bitmap image (must be 1-bit b/w)
- * @param resolution the resolution of the image (must be a PCL resolution)
- * @throws IOException In case of an I/O error
- */
- public void paintMonochromeBitmap(RenderedImage img, int resolution) throws IOException {
- if (!isValidPCLResolution(resolution)) {
- throw new IllegalArgumentException("Invalid PCL resolution: " + resolution);
- }
- setRasterGraphicsResolution(resolution);
- writeCommand("*r0f" + img.getHeight() + "t" + img.getWidth() + "s1A");
- Raster raster = img.getData();
- boolean monochrome = isMonochromeImage(img);
- if (!monochrome) {
- throw new IllegalArgumentException("img must be a monochrome image");
- }
-
- int x = 0;
- int y = 0;
- int imgw = img.getWidth();
- int imgh = img.getHeight();
- int bytewidth = (imgw / 8);
- if ((imgw % 8) != 0) {
- bytewidth++;
- }
- byte ib;
- byte[] rle = new byte[bytewidth * 2]; //compressed (RLE)
- byte[] uncompressed = new byte[bytewidth]; //uncompressed
- int lastcount = -1;
- byte lastbyte = 0;
- int rlewidth = 0;
-
- // Transfer graphics data
- for (y = 0; y < imgh; y++) {
- ib = 0;
- for (x = 0; x < imgw; x++) {
- int sample = raster.getSample(x, y, 0);
- //Set image bit for black
- if ((sample == 0)) {
- ib |= (1 << (7 - (x % 8)));
- }
-
- //RLE encoding
- if ((x % 8) == 7 || ((x + 1) == imgw)) {
- if (rlewidth < bytewidth) {
- if (lastcount >= 0) {
- if (ib == lastbyte) {
- lastcount++;
- } else {
- rle[rlewidth++] = (byte)(lastcount & 0xFF);
- rle[rlewidth++] = lastbyte;
- lastbyte = ib;
- lastcount = 0;
- }
- } else {
- lastbyte = ib;
- lastcount = 0;
- }
- if (lastcount == 255 || ((x + 1) == imgw)) {
- rle[rlewidth++] = (byte)(lastcount & 0xFF);
- rle[rlewidth++] = lastbyte;
- lastbyte = 0;
- lastcount = -1;
- }
- }
- uncompressed[x / 8] = ib;
- ib = 0;
- }
- }
- if (rlewidth < bytewidth) {
- writeCommand("*b1m" + rlewidth + "W");
- this.out.write(rle, 0, rlewidth);
- } else {
- writeCommand("*b0m" + bytewidth + "W");
- this.out.write(uncompressed);
- }
- lastcount = -1;
- rlewidth = 0;
- }
-
- // End raster graphics
- writeCommand("*rB");
- }
-
-}
+++ /dev/null
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed 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.fop.render.pcl;
-
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.GraphicsConfiguration;
-import java.awt.GraphicsEnvironment;
-import java.awt.Image;
-import java.awt.Paint;
-import java.awt.Shape;
-import java.awt.Stroke;
-import java.awt.font.FontRenderContext;
-import java.awt.font.GlyphVector;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-import java.awt.image.BufferedImage;
-import java.awt.image.ImageObserver;
-import java.awt.image.RenderedImage;
-import java.awt.image.renderable.RenderableImage;
-import java.io.IOException;
-import java.text.AttributedCharacterIterator;
-
-import org.apache.fop.util.UnitConv;
-import org.apache.xmlgraphics.java2d.AbstractGraphics2D;
-import org.apache.xmlgraphics.java2d.GraphicContext;
-
-/**
- * Graphics2D implementation implementing PCL and HP GL/2.
- * Note: This class cannot be used stand-alone to create full PCL documents.
- */
-public class PCLGraphics2D extends AbstractGraphics2D {
-
- /** The PCL generator */
- protected PCLGenerator gen;
-
- private boolean failOnUnsupportedFeature = true;
- private boolean clippingDisabled = false;
-
- /**
- * Create a new PCLGraphics2D.
- * @param gen the PCL Generator to paint with
- */
- public PCLGraphics2D(PCLGenerator gen) {
- super(true);
- this.gen = gen;
- }
-
- /**
- * Copy constructor
- * @param g parent PCLGraphics2D
- */
- public PCLGraphics2D(PCLGraphics2D g) {
- super(true);
- this.gen = g.gen;
- }
-
- /** @see java.awt.Graphics#create() */
- public Graphics create() {
- PCLGraphics2D copy = new PCLGraphics2D(this);
- copy.setGraphicContext((GraphicContext)getGraphicContext().clone());
- return copy;
- }
-
- /** @see java.awt.Graphics#dispose() */
- public void dispose() {
- this.gen = null;
- }
-
- /**
- * Sets the GraphicContext
- * @param c GraphicContext to use
- */
- public void setGraphicContext(GraphicContext c) {
- this.gc = c;
- }
-
- /**
- * Allows to disable all clipping operations.
- * @param value true if clipping should be disabled.
- */
- public void setClippingDisabled(boolean value) {
- this.clippingDisabled = value;
- }
-
- /**
- * Central handler for IOExceptions for this class.
- * @param ioe IOException to handle
- */
- public void handleIOException(IOException ioe) {
- //TODO Surely, there's a better way to do this.
- ioe.printStackTrace();
- }
-
- /**
- * Raises an UnsupportedOperationException if this instance is configured to do so and an
- * unsupported feature has been requested. Clients can make use of this to fall back to
- * a more compatible way of painting a PCL graphic.
- * @param msg the error message to be displayed
- */
- protected void handleUnsupportedFeature(String msg) {
- if (this.failOnUnsupportedFeature) {
- throw new UnsupportedOperationException(msg);
- }
- }
-
- /** @see java.awt.Graphics2D#getDeviceConfiguration() */
- public GraphicsConfiguration getDeviceConfiguration() {
- return GraphicsEnvironment.getLocalGraphicsEnvironment().
- getDefaultScreenDevice().getDefaultConfiguration();
- }
-
- /**
- * Applies a new Stroke object.
- * @param stroke Stroke object to use
- * @throws IOException In case of an I/O problem
- */
- protected void applyStroke(Stroke stroke) throws IOException {
- if (stroke instanceof BasicStroke) {
- BasicStroke bs = (BasicStroke)stroke;
-
- float[] da = bs.getDashArray();
- if (da != null) {
-
- gen.writeText("UL1,");
- int len = Math.min(20, da.length);
- float patternLen = 0.0f;
- for (int idx = 0; idx < len; idx++) {
- patternLen += da[idx];
- }
- if (len == 1) {
- patternLen *= 2;
- }
- for (int idx = 0; idx < len; idx++) {
- float perc = da[idx] * 100 / patternLen;
- gen.writeText(gen.formatDouble2(perc));
- if (idx < da.length - 1) {
- gen.writeText(",");
- }
- }
- if (len == 1) {
- gen.writeText("," + gen.formatDouble2(da[0] * 100 / patternLen ));
-
- }
- gen.writeText(";");
- /* TODO Dash phase NYI
- float offset = bs.getDashPhase();
- gen.writeln(gen.formatDouble4(offset) + " setdash");
- */
- Point2D ptLen = new Point2D.Double(patternLen, 0);
- //interpret as absolute length
- getTransform().deltaTransform(ptLen, ptLen);
- double transLen = UnitConv.pt2mm(ptLen.distance(0, 0));
- gen.writeText("LT1," + gen.formatDouble4(transLen) + ",1;");
- } else {
- gen.writeText("LT;");
- }
-
- gen.writeText("LA1"); //line cap
- int ec = bs.getEndCap();
- switch (ec) {
- case BasicStroke.CAP_BUTT:
- gen.writeText(",1");
- break;
- case BasicStroke.CAP_ROUND:
- gen.writeText(",4");
- break;
- case BasicStroke.CAP_SQUARE:
- gen.writeText(",2");
- break;
- default: System.err.println("Unsupported line cap: " + ec);
- }
-
- gen.writeText(",2"); //line join
- int lj = bs.getLineJoin();
- switch (lj) {
- case BasicStroke.JOIN_MITER:
- gen.writeText(",1");
- break;
- case BasicStroke.JOIN_ROUND:
- gen.writeText(",4");
- break;
- case BasicStroke.JOIN_BEVEL:
- gen.writeText(",5");
- break;
- default: System.err.println("Unsupported line join: " + lj);
- }
-
- float ml = bs.getMiterLimit();
- gen.writeText(",3" + gen.formatDouble4(ml));
-
- float lw = bs.getLineWidth();
- Point2D ptSrc = new Point2D.Double(lw, 0);
- //Pen widths are set as absolute metric values (WU0;)
- Point2D ptDest = getTransform().deltaTransform(ptSrc, null);
- double transDist = UnitConv.pt2mm(ptDest.distance(0, 0));
- //System.out.println("--" + ptDest.distance(0, 0) + " " + transDist);
- gen.writeText(";PW" + gen.formatDouble4(transDist) + ";");
-
- } else {
- handleUnsupportedFeature("Unsupported Stroke: " + stroke.getClass().getName());
- }
- }
-
- /**
- * Applies a new Paint object.
- * @param paint Paint object to use
- * @throws IOException In case of an I/O problem
- */
- protected void applyPaint(Paint paint) throws IOException {
- if (paint instanceof Color) {
- Color col = (Color)paint;
- int shade = gen.convertToPCLShade(col);
- gen.writeText("TR0;FT10," + shade + ";");
- } else {
- handleUnsupportedFeature("Unsupported Paint: " + paint.getClass().getName());
- }
- }
-
- private void writeClip(Shape imclip) throws IOException {
- if (clippingDisabled) {
- return;
- }
- if (imclip == null) {
- //gen.writeText("IW;");
- } else {
- handleUnsupportedFeature("Clipping is not supported. Shape: " + imclip);
- /* This is an attempt to clip using the "InputWindow" (IW) but this only allows to
- * clip a rectangular area. Force falling back to bitmap mode for now.
- Rectangle2D bounds = imclip.getBounds2D();
- Point2D p1 = new Point2D.Double(bounds.getX(), bounds.getY());
- Point2D p2 = new Point2D.Double(
- bounds.getX() + bounds.getWidth(), bounds.getY() + bounds.getHeight());
- getTransform().transform(p1, p1);
- getTransform().transform(p2, p2);
- gen.writeText("IW" + gen.formatDouble4(p1.getX())
- + "," + gen.formatDouble4(p2.getY())
- + "," + gen.formatDouble4(p2.getX())
- + "," + gen.formatDouble4(p1.getY()) + ";");
- */
- }
- }
-
- /** @see java.awt.Graphics2D#draw(java.awt.Shape) */
- public void draw(Shape s) {
- try {
- AffineTransform trans = getTransform();
-
- Shape imclip = getClip();
- writeClip(imclip);
-
- if (!Color.black.equals(getColor())) {
- //TODO PCL 5 doesn't support colored pens, PCL5c has a pen color (PC) command
- handleUnsupportedFeature("Only black is supported as stroke color: " + getColor());
- }
- applyStroke(getStroke());
-
- PathIterator iter = s.getPathIterator(trans);
- processPathIteratorStroke(iter);
- writeClip(null);
- } catch (IOException ioe) {
- handleIOException(ioe);
- }
- }
-
- /** @see java.awt.Graphics2D#fill(java.awt.Shape) */
- public void fill(Shape s) {
- try {
- AffineTransform trans = getTransform();
- Shape imclip = getClip();
- writeClip(imclip);
-
- applyPaint(getPaint());
-
- PathIterator iter = s.getPathIterator(trans);
- processPathIteratorFill(iter);
- writeClip(null);
- } catch (IOException ioe) {
- handleIOException(ioe);
- }
- }
-
- /**
- * Processes a path iterator generating the nexessary painting operations.
- * @param iter PathIterator to process
- * @throws IOException In case of an I/O problem.
- */
- public void processPathIteratorStroke(PathIterator iter) throws IOException {
- gen.writeText("\n");
- double[] vals = new double[6];
- boolean penDown = false;
- double x = 0;
- double y = 0;
- StringBuffer sb = new StringBuffer(256);
- penUp(sb);
- while (!iter.isDone()) {
- int type = iter.currentSegment(vals);
- if (type == PathIterator.SEG_CLOSE) {
- gen.writeText("PM;");
- gen.writeText(sb.toString());
- gen.writeText("PM2;EP;");
- sb.setLength(0);
- iter.next();
- continue;
- } else if (type == PathIterator.SEG_MOVETO) {
- gen.writeText(sb.toString());
- sb.setLength(0);
- if (penDown) {
- penUp(sb);
- penDown = false;
- }
- } else {
- if (!penDown) {
- penDown(sb);
- penDown = true;
- }
- }
- switch (type) {
- case PathIterator.SEG_CLOSE:
- break;
- case PathIterator.SEG_MOVETO:
- x = vals[0];
- y = vals[1];
- plotAbsolute(x, y, sb);
- gen.writeText(sb.toString());
- sb.setLength(0);
- break;
- case PathIterator.SEG_LINETO:
- x = vals[0];
- y = vals[1];
- plotAbsolute(x, y, sb);
- break;
- case PathIterator.SEG_CUBICTO:
- x = vals[4];
- y = vals[5];
- bezierAbsolute(vals[0], vals[1], vals[2], vals[3], x, y, sb);
- break;
- case PathIterator.SEG_QUADTO:
- double originX = x;
- double originY = y;
- x = vals[2];
- y = vals[3];
- quadraticBezierAbsolute(originX, originY, vals[0], vals[1], x, y, sb);
- break;
- default:
- break;
- }
- iter.next();
- }
- sb.append("\n");
- gen.writeText(sb.toString());
- }
-
- /**
- * Processes a path iterator generating the nexessary painting operations.
- * @param iter PathIterator to process
- * @throws IOException In case of an I/O problem.
- */
- public void processPathIteratorFill(PathIterator iter) throws IOException {
- gen.writeText("\n");
- double[] vals = new double[6];
- boolean penDown = false;
- double x = 0;
- double y = 0;
- boolean pendingPM0 = true;
- StringBuffer sb = new StringBuffer(256);
- penUp(sb);
- while (!iter.isDone()) {
- int type = iter.currentSegment(vals);
- if (type == PathIterator.SEG_CLOSE) {
- sb.append("PM1;");
- iter.next();
- continue;
- } else if (type == PathIterator.SEG_MOVETO) {
- if (penDown) {
- penUp(sb);
- penDown = false;
- }
- } else {
- if (!penDown) {
- penDown(sb);
- penDown = true;
- }
- }
- switch (type) {
- case PathIterator.SEG_MOVETO:
- x = vals[0];
- y = vals[1];
- plotAbsolute(x, y, sb);
- break;
- case PathIterator.SEG_LINETO:
- x = vals[0];
- y = vals[1];
- plotAbsolute(x, y, sb);
- break;
- case PathIterator.SEG_CUBICTO:
- x = vals[4];
- y = vals[5];
- bezierAbsolute(vals[0], vals[1], vals[2], vals[3], x, y, sb);
- break;
- case PathIterator.SEG_QUADTO:
- double originX = x;
- double originY = y;
- x = vals[2];
- y = vals[3];
- quadraticBezierAbsolute(originX, originY, vals[0], vals[1], x, y, sb);
- break;
- default:
- throw new IllegalStateException("Must not get here");
- }
- if (pendingPM0) {
- pendingPM0 = false;
- sb.append("PM;");
- }
- iter.next();
- }
- sb.append("PM2;");
- fillPolygon(iter.getWindingRule(), sb);
- sb.append("\n");
- gen.writeText(sb.toString());
- }
-
- private void fillPolygon(int windingRule, StringBuffer sb) {
- int fillMethod = (windingRule == PathIterator.WIND_EVEN_ODD ? 0 : 1);
- sb.append("FP").append(fillMethod).append(";");
- }
-
- private void plotAbsolute(double x, double y, StringBuffer sb) {
- sb.append("PA").append(gen.formatDouble4(x));
- sb.append(",").append(gen.formatDouble4(y)).append(";");
- }
-
- private void bezierAbsolute(double x1, double y1, double x2, double y2, double x3, double y3,
- StringBuffer sb) {
- sb.append("BZ").append(gen.formatDouble4(x1));
- sb.append(",").append(gen.formatDouble4(y1));
- sb.append(",").append(gen.formatDouble4(x2));
- sb.append(",").append(gen.formatDouble4(y2));
- sb.append(",").append(gen.formatDouble4(x3));
- sb.append(",").append(gen.formatDouble4(y3)).append(";");
- }
-
- private void quadraticBezierAbsolute(double originX, double originY,
- double x1, double y1, double x2, double y2, StringBuffer sb) {
- //Quadratic Bezier curve can be mapped to a normal bezier curve
- //See http://pfaedit.sourceforge.net/bezier.html
- double nx1 = originX + (2.0 / 3.0) * (x1 - originX);
- double ny1 = originY + (2.0 / 3.0) * (y1 - originY);
-
- double nx2 = nx1 + (1.0 / 3.0) * (x2 - originX);
- double ny2 = ny1 + (1.0 / 3.0) * (y2 - originY);
-
- bezierAbsolute(nx1, ny1, nx2, ny2, x2, y2, sb);
- }
-
- private void penDown(StringBuffer sb) {
- sb.append("PD;");
- }
-
- private void penUp(StringBuffer sb) {
- sb.append("PU;");
- }
-
- /** @see java.awt.Graphics2D#drawString(java.lang.String, float, float) */
- public void drawString(String s, float x, float y) {
- java.awt.Font awtFont = getFont();
- FontRenderContext frc = getFontRenderContext();
- GlyphVector gv = awtFont.createGlyphVector(frc, s);
- Shape glyphOutline = gv.getOutline(x, y);
- fill(glyphOutline);
- }
-
- /** @see java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float) */
- public void drawString(AttributedCharacterIterator iterator, float x,
- float y) {
- // TODO Auto-generated method stub
- handleUnsupportedFeature("drawString NYI");
- }
-
- /**
- * @see java.awt.Graphics2D#drawRenderedImage(java.awt.image.RenderedImage,
- * java.awt.geom.AffineTransform)
- */
- public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
- handleUnsupportedFeature("Bitmap images are not supported");
- }
-
- /**
- * @see java.awt.Graphics2D#drawRenderableImage(java.awt.image.renderable.RenderableImage,
- * java.awt.geom.AffineTransform)
- */
- public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
- handleUnsupportedFeature("Bitmap images are not supported");
- }
-
- /**
- * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, int, int,
- * java.awt.image.ImageObserver)
- */
- public boolean drawImage(Image img, int x, int y, int width, int height,
- ImageObserver observer) {
- handleUnsupportedFeature("Bitmap images are not supported");
- return false;
- }
-
- /**
- * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, java.awt.image.ImageObserver)
- */
- public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
- handleUnsupportedFeature("Bitmap images are not supported");
- return false;
- /*
- * First attempt disabled.
- * Reasons: Lack of transparency control, positioning and rotation issues
- final int width = img.getWidth(observer);
- final int height = img.getHeight(observer);
- if (width == -1 || height == -1) {
- return false;
- }
-
- Dimension size = new Dimension(width, height);
- BufferedImage buf = buildBufferedImage(size);
-
- java.awt.Graphics2D g = buf.createGraphics();
- try {
- g.setComposite(AlphaComposite.SrcOver);
- g.setBackground(new Color(255, 255, 255));
- g.setPaint(new Color(255, 255, 255));
- g.fillRect(0, 0, width, height);
- g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight()));
-
- if (!g.drawImage(img, 0, 0, observer)) {
- return false;
- }
- } finally {
- g.dispose();
- }
-
- try {
- AffineTransform at = getTransform();
- gen.enterPCLMode(false);
- //Shape imclip = getClip(); Clipping is not available in PCL
- Point2D p1 = new Point2D.Double(x, y);
- at.transform(p1, p1);
- pclContext.getTransform().transform(p1, p1);
- gen.setCursorPos(p1.getX(), p1.getY());
- gen.paintBitmap(buf, 72);
- gen.enterHPGL2Mode(false);
- } catch (IOException ioe) {
- handleIOException(ioe);
- }
-
- return true;*/
- }
-
- /** @see java.awt.Graphics#copyArea(int, int, int, int, int, int) */
- public void copyArea(int x, int y, int width, int height, int dx, int dy) {
- // TODO Auto-generated method stub
- handleUnsupportedFeature("copyArea NYI");
- }
-
- /** @see java.awt.Graphics#setXORMode(java.awt.Color) */
- public void setXORMode(Color c1) {
- // TODO Auto-generated method stub
- handleUnsupportedFeature("setXORMode NYI");
- }
-
- /**
- * Used to create proper font metrics
- */
- private Graphics2D fmg;
-
- {
- BufferedImage bi = new BufferedImage(1, 1,
- BufferedImage.TYPE_INT_ARGB);
-
- fmg = bi.createGraphics();
- }
-
- /**
- * Creates a buffered image.
- * @param size dimensions of the image to be created
- * @return the buffered image
- */
- protected BufferedImage buildBufferedImage(Dimension size) {
- return new BufferedImage(size.width, size.height,
- BufferedImage.TYPE_BYTE_GRAY);
- }
-
- /** @see java.awt.Graphics#getFontMetrics(java.awt.Font) */
- public java.awt.FontMetrics getFontMetrics(java.awt.Font f) {
- return fmg.getFontMetrics(f);
- }
-
-}
+++ /dev/null
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed 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.fop.render.pcl;
-
-import java.awt.Dimension;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-
-import org.apache.commons.io.output.ByteArrayOutputStream;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.fop.render.AbstractGraphics2DAdapter;
-import org.apache.fop.render.Graphics2DImagePainter;
-import org.apache.fop.render.RendererContext;
-import org.apache.fop.util.UnitConv;
-import org.apache.xmlgraphics.java2d.GraphicContext;
-
-/**
- * Graphics2DAdapter implementation for PCL and HP GL/2.
- */
-public class PCLGraphics2DAdapter extends AbstractGraphics2DAdapter {
-
- /** logging instance */
- private static Log log = LogFactory.getLog(PCLGraphics2DAdapter.class);
-
- /**
- * Main constructor
- */
- public PCLGraphics2DAdapter() {
- }
-
- /** @see org.apache.fop.render.Graphics2DAdapter */
- public void paintImage(Graphics2DImagePainter painter,
- RendererContext context,
- int x, int y, int width, int height) throws IOException {
- PCLRendererContext pclContext = PCLRendererContext.wrapRendererContext(context);
- PCLRenderer pcl = (PCLRenderer)context.getRenderer();
- PCLGenerator gen = pcl.gen;
-
- // get the 'width' and 'height' attributes of the image/document
- Dimension dim = painter.getImageSize();
- float imw = (float)dim.getWidth();
- float imh = (float)dim.getHeight();
-
- boolean painted = false;
- boolean paintAsBitmap = pclContext.paintAsBitmap();
- if (!paintAsBitmap) {
- ByteArrayOutputStream baout = new ByteArrayOutputStream();
- PCLGenerator tempGen = new PCLGenerator(baout, gen.getMaximumBitmapResolution());
- try {
- GraphicContext ctx = (GraphicContext)pcl.getGraphicContext().clone();
-
- AffineTransform prepareHPGL2 = new AffineTransform();
- prepareHPGL2.scale(0.001, 0.001);
- ctx.setTransform(prepareHPGL2);
-
- PCLGraphics2D graphics = new PCLGraphics2D(tempGen);
- graphics.setGraphicContext(ctx);
- graphics.setClippingDisabled(pclContext.isClippingDisabled());
- Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
- painter.paint(graphics, area);
-
- //If we arrive here, the graphic is natively paintable, so write the graphic
- pcl.saveGraphicsState();
- pcl.setCursorPos(x, y);
- gen.writeCommand("*c" + gen.formatDouble4(width / 100f) + "x"
- + gen.formatDouble4(height / 100f) + "Y");
- gen.writeCommand("*c0T");
- gen.enterHPGL2Mode(false);
- gen.writeText("\nIN;");
- gen.writeText("SP1;");
- //One Plotter unit is 0.025mm!
- double scale = imw / UnitConv.mm2pt(imw * 0.025);
- gen.writeText("SC0," + gen.formatDouble4(scale)
- + ",0,-" + gen.formatDouble4(scale) + ",2;");
- gen.writeText("IR0,100,0,100;");
- gen.writeText("PU;PA0,0;\n");
- baout.writeTo(gen.getOutputStream()); //Buffer is written to output stream
- gen.writeText("\n");
-
- gen.enterPCLMode(false);
- pcl.restoreGraphicsState();
- painted = true;
- } catch (UnsupportedOperationException uoe) {
- log.debug(
- "Cannot paint graphic natively. Falling back to bitmap painting. Reason: "
- + uoe.getMessage());
- }
- }
-
- if (!painted) {
- //Fallback solution: Paint to a BufferedImage
- int resolution = (int)Math.round(context.getUserAgent().getTargetResolution());
- BufferedImage bi = paintToBufferedImage(painter, pclContext, resolution, true, false);
-
- pcl.setCursorPos(x, y);
- gen.paintBitmap(bi, new Dimension(width, height), pclContext.isSourceTransparency());
- }
- }
-
-}
+++ /dev/null
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed 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.fop.render.pcl;
-
-import java.awt.Dimension;
-import java.awt.Rectangle;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.fop.util.UnitConv;
-
-/**
- * This class represents a page format with PCL-specific properties.
- */
-public class PCLPageDefinition {
-
- private static List pageDefinitions;
- private static PCLPageDefinition defaultPageDefinition;
-
- private String name;
- private int selector;
- private Dimension physicalPageSize;
- private Rectangle logicalPageRect;
- private boolean landscape;
-
- static {
- createPageDefinitions();
- }
-
- /**
- * Main constructor
- * @param name the name of the page definition
- * @param selector the selector used by the <ESC>&l#A command (page size)
- * @param physicalPageSize the physical page size
- * @param logicalPageRect the rectangle defining the logical page
- * @param landscape true if it is a landscape format
- */
- public PCLPageDefinition(String name, int selector, Dimension physicalPageSize,
- Rectangle logicalPageRect, boolean landscape) {
- this.name = name;
- this.selector = selector;
- this.physicalPageSize = physicalPageSize;
- this.logicalPageRect = logicalPageRect;
- this.landscape = landscape;
- }
-
- /** @return the name of the page definition */
- public String getName() {
- return this.name;
- }
-
- /** @return the selector used by the <ESC>&l#A command (page size) */
- public int getSelector() {
- return this.selector;
- }
-
- /** @return true if it is a landscape format */
- public boolean isLandscapeFormat() {
- return this.landscape;
- }
-
- /** @return the physical page size */
- public Dimension getPhysicalPageSize() {
- return this.physicalPageSize;
- }
-
- /** @return the rectangle defining the logical page */
- public Rectangle getLogicalPageRect() {
- return this.logicalPageRect;
- }
-
- private boolean matches(long width, long height, int errorMargin) {
- return (Math.abs(this.physicalPageSize.width - width) < errorMargin)
- && (Math.abs(this.physicalPageSize.height - height) < errorMargin);
- }
-
- /** @see java.lang.Object#toString() */
- public String toString() {
- return getName();
- }
-
- /**
- * Tries to determine a matching page definition.
- * @param width the physical page width (in mpt)
- * @param height the physical page height (in mpt)
- * @param errorMargin the error margin for detecting the right page definition
- * @return the page definition or null if no match was found
- */
- public static PCLPageDefinition getPageDefinition(long width, long height, int errorMargin) {
- Iterator iter = pageDefinitions.iterator();
- while (iter.hasNext()) {
- PCLPageDefinition def = (PCLPageDefinition)iter.next();
- if (def.matches(width, height, errorMargin)) {
- return def;
- }
- }
- return null;
- }
-
- /** @return the default page definition (letter) */
- public static PCLPageDefinition getDefaultPageDefinition() {
- return defaultPageDefinition;
- }
-
- /**
- * Converts an offset values for logical pages to millipoints. The values are given as pixels
- * in a 300dpi environment.
- * @param offset the offset as given in the PCL 5 specification (under "Printable Area")
- * @return the converted value in millipoints
- */
- private static int convert300dpiDotsToMpt(int offset) {
- return (int)Math.round(((double)offset) * 72000 / 300);
- }
-
- private static Dimension createPhysicalPageSizeInch(float width, float height) {
- return new Dimension(
- (int)Math.round(UnitConv.in2mpt(width)),
- (int)Math.round(UnitConv.in2mpt(height)));
- }
-
- private static Dimension createPhysicalPageSizeMm(float width, float height) {
- return new Dimension(
- (int)Math.round(UnitConv.mm2mpt(width)),
- (int)Math.round(UnitConv.mm2mpt(height)));
- }
-
- private static Rectangle createLogicalPageRect(int x, int y, int width, int height) {
- return new Rectangle(convert300dpiDotsToMpt(x), convert300dpiDotsToMpt(y),
- convert300dpiDotsToMpt(width), convert300dpiDotsToMpt(height));
- }
-
- private static void createPageDefinitions() {
- pageDefinitions = new java.util.ArrayList();
- pageDefinitions.add(new PCLPageDefinition("Letter", 2,
- createPhysicalPageSizeInch(8.5f, 11),
- createLogicalPageRect(75, 0, 2400, 3300), false));
- defaultPageDefinition = new PCLPageDefinition("Legal", 3,
- createPhysicalPageSizeInch(8.5f, 14),
- createLogicalPageRect(75, 0, 2400, 4200), false);
- pageDefinitions.add(defaultPageDefinition);
- pageDefinitions.add(new PCLPageDefinition("Executive", 1,
- createPhysicalPageSizeInch(7.25f, 10.5f),
- createLogicalPageRect(75, 0, 2025, 3150), false));
- pageDefinitions.add(new PCLPageDefinition("Ledger", 6,
- createPhysicalPageSizeInch(11, 17),
- createLogicalPageRect(75, 0, 3150, 5100), false));
- pageDefinitions.add(new PCLPageDefinition("A4", 26,
- createPhysicalPageSizeMm(210, 297),
- createLogicalPageRect(71, 0, 2338, 3507), false));
- pageDefinitions.add(new PCLPageDefinition("A3", 27,
- createPhysicalPageSizeMm(297, 420),
- createLogicalPageRect(71, 0, 3365, 4960), false));
-
- //TODO Add envelope definitions
-
- pageDefinitions.add(new PCLPageDefinition("LetterL", 2,
- createPhysicalPageSizeInch(11, 8.5f),
- createLogicalPageRect(60, 0, 3180, 2550), true));
- pageDefinitions.add(new PCLPageDefinition("LegalL", 3,
- createPhysicalPageSizeInch(14, 8.5f),
- createLogicalPageRect(60, 0, 4080, 2550), true));
- pageDefinitions.add(new PCLPageDefinition("ExecutiveL", 1,
- createPhysicalPageSizeInch(10.5f, 7.25f),
- createLogicalPageRect(60, 0, 3030, 2175), true));
- pageDefinitions.add(new PCLPageDefinition("LedgerL", 6,
- createPhysicalPageSizeInch(17, 11),
- createLogicalPageRect(60, 0, 4980, 3300), true));
- pageDefinitions.add(new PCLPageDefinition("A4L", 26,
- createPhysicalPageSizeMm(297, 210),
- createLogicalPageRect(59, 0, 3389, 2480), true));
- pageDefinitions.add(new PCLPageDefinition("A3L", 27,
- createPhysicalPageSizeMm(420, 297),
- createLogicalPageRect(59, 0, 4842, 3507), true));
- }
-
-}
+++ /dev/null
-/*
- * Copyright 1999-2006 The Apache Software Foundation.
- *
- * Licensed 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.fop.render.pcl;
-
-//Java
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.color.ColorSpace;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorModel;
-import java.awt.image.ComponentColorModel;
-import java.awt.image.DataBuffer;
-import java.awt.image.DataBufferByte;
-import java.awt.image.PixelInterleavedSampleModel;
-import java.awt.image.Raster;
-import java.awt.image.RenderedImage;
-import java.awt.image.SampleModel;
-import java.awt.image.WritableRaster;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.List;
-import java.util.Map;
-import java.util.Stack;
-
-import org.w3c.dom.Document;
-
-import org.apache.xmlgraphics.java2d.GraphicContext;
-
-// FOP
-import org.apache.avalon.framework.configuration.Configuration;
-import org.apache.avalon.framework.configuration.ConfigurationException;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.fop.apps.FOPException;
-import org.apache.fop.apps.MimeConstants;
-import org.apache.fop.area.Area;
-import org.apache.fop.area.Block;
-import org.apache.fop.area.BlockViewport;
-import org.apache.fop.area.CTM;
-import org.apache.fop.area.PageViewport;
-import org.apache.fop.area.Trait;
-import org.apache.fop.area.inline.AbstractTextArea;
-import org.apache.fop.area.inline.ForeignObject;
-import org.apache.fop.area.inline.Image;
-import org.apache.fop.area.inline.InlineArea;
-import org.apache.fop.area.inline.SpaceArea;
-import org.apache.fop.area.inline.TextArea;
-import org.apache.fop.area.inline.Viewport;
-import org.apache.fop.area.inline.WordArea;
-import org.apache.fop.fo.extensions.ExtensionElementMapping;
-import org.apache.fop.fonts.Font;
-import org.apache.fop.fonts.FontInfo;
-import org.apache.fop.image.EPSImage;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.image.ImageFactory;
-import org.apache.fop.image.XMLImage;
-import org.apache.fop.render.Graphics2DAdapter;
-import org.apache.fop.render.Graphics2DImagePainter;
-import org.apache.fop.render.PrintRenderer;
-import org.apache.fop.render.RendererContext;
-import org.apache.fop.render.RendererContextConstants;
-import org.apache.fop.render.java2d.FontMetricsMapper;
-import org.apache.fop.render.java2d.FontSetup;
-import org.apache.fop.render.java2d.Java2DRenderer;
-import org.apache.fop.render.pcl.extensions.PCLElementMapping;
-import org.apache.fop.traits.BorderProps;
-import org.apache.fop.util.QName;
-import org.apache.fop.util.UnitConv;
-
-/**
- * Renderer for the PCL 5 printer language. It also uses HP GL/2 for certain graphic elements.
- */
-public class PCLRenderer extends PrintRenderer {
-
- /** logging instance */
- private static Log log = LogFactory.getLog(PCLRenderer.class);
-
- /** The MIME type for PCL */
- public static final String MIME_TYPE = MimeConstants.MIME_PCL_ALT;
-
- private static final QName CONV_MODE
- = new QName(ExtensionElementMapping.URI, null, "conversion-mode");
- private static final QName SRC_TRANSPARENCY
- = new QName(ExtensionElementMapping.URI, null, "source-transparency");
-
- /** The OutputStream to write the PCL stream to */
- protected OutputStream out;
-
- /** The PCL generator */
- protected PCLGenerator gen;
- private boolean ioTrouble = false;
-
- private Stack graphicContextStack = new Stack();
- private GraphicContext graphicContext = new GraphicContext();
-
- private PCLPageDefinition currentPageDefinition;
- private int currentPrintDirection = 0;
- private GeneralPath currentPath = null;
- private java.awt.Color currentFillColor = null;
-
- /**
- * Controls whether appearance is more important than speed. False can cause some FO feature
- * to be ignored (like the advanced borders).
- */
- private boolean qualityBeforeSpeed = false;
-
- /**
- * Controls whether all text should be painted as text. This is a fallback setting in case
- * the mixture of native and bitmapped text does not provide the necessary quality.
- */
- private boolean allTextAsBitmaps = false;
-
- /**
- * Create the PCL renderer
- */
- public PCLRenderer() {
- }
-
- /**
- * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
- */
- public void configure(Configuration cfg) throws ConfigurationException {
- super.configure(cfg);
- String rendering = cfg.getChild("rendering").getValue(null);
- if ("quality".equalsIgnoreCase(rendering)) {
- this.qualityBeforeSpeed = true;
- } else if ("speed".equalsIgnoreCase(rendering)) {
- this.qualityBeforeSpeed = false;
- } else if (rendering != null) {
- throw new ConfigurationException(
- "Valid values for 'rendering' are 'quality' and 'speed'. Value found: "
- + rendering);
- }
- String textRendering = cfg.getChild("text-rendering").getValue(null);
- if ("bitmap".equalsIgnoreCase(textRendering)) {
- this.allTextAsBitmaps = true;
- } else if ("auto".equalsIgnoreCase(textRendering)) {
- this.allTextAsBitmaps = false;
- } else if (textRendering != null) {
- throw new ConfigurationException(
- "Valid values for 'text-rendering' are 'auto' and 'bitmap'. Value found: "
- + textRendering);
- }
- }
-
- /**
- * @see org.apache.fop.render.Renderer#setupFontInfo(org.apache.fop.fonts.FontInfo)
- */
- public void setupFontInfo(FontInfo inFontInfo) {
- //Don't call super.setupFontInfo() here!
- //The PCLRenderer uses the Java2D FontSetup which needs a special font setup
- //create a temp Image to test font metrics on
- fontInfo = inFontInfo;
- BufferedImage fontImage = new BufferedImage(100, 100,
- BufferedImage.TYPE_INT_RGB);
- Graphics2D g = fontImage.createGraphics();
- //The next line is important to get accurate font metrics!
- g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
- RenderingHints.VALUE_FRACTIONALMETRICS_ON);
- FontSetup.setup(fontInfo, g);
- }
-
- /**
- * Central exception handler for I/O exceptions.
- * @param ioe IOException to handle
- */
- protected void handleIOTrouble(IOException ioe) {
- if (!ioTrouble) {
- log.error("Error while writing to target file", ioe);
- ioTrouble = true;
- }
- }
-
- /** @see org.apache.fop.render.Renderer#getGraphics2DAdapter() */
- public Graphics2DAdapter getGraphics2DAdapter() {
- return new PCLGraphics2DAdapter();
- }
-
- /** @return the GraphicContext used to track coordinate system transformations */
- public GraphicContext getGraphicContext() {
- return this.graphicContext;
- }
-
- /** @return the target resolution */
- protected int getResolution() {
- int resolution = (int)Math.round(userAgent.getTargetResolution());
- if (resolution <= 300) {
- return 300;
- } else {
- return 600;
- }
- }
-
- /**
- * Sets the current font (NOTE: Hard-coded font mappings ATM!)
- * @param name the font name (internal F* names for now)
- * @param size the font size
- * @param text the text to be rendered (used to determine if there are non-printable chars)
- * @return true if the font can be mapped to PCL
- * @throws IOException if an I/O problem occurs
- */
- public boolean setFont(String name, float size, String text) throws IOException {
- byte[] encoded = text.getBytes("ISO-8859-1");
- for (int i = 0, c = encoded.length; i < c; i++) {
- if (encoded[i] == 0x3F && text.charAt(i) != '?') {
- return false;
- }
- }
- int fontcode = 0;
- if (name.length() > 1 && name.charAt(0) == 'F') {
- try {
- fontcode = Integer.parseInt(name.substring(1));
- } catch (Exception e) {
- log.error(e);
- }
- }
- //Note "(ON" selects ISO 8859-1 symbol set as used by PCLGenerator
- String formattedSize = gen.formatDouble2(size / 1000);
- switch (fontcode) {
- case 1: // F1 = Helvetica
- // gen.writeCommand("(8U");
- // gen.writeCommand("(s1p" + formattedSize + "v0s0b24580T");
- // Arial is more common among PCL5 printers than Helvetica - so use Arial
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v0s0b16602T");
- break;
- case 2: // F2 = Helvetica Oblique
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v1s0b16602T");
- break;
- case 3: // F3 = Helvetica Bold
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v0s3b16602T");
- break;
- case 4: // F4 = Helvetica Bold Oblique
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v1s3b16602T");
- break;
- case 5: // F5 = Times Roman
- // gen.writeCommand("(8U");
- // gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
- // Times New is more common among PCL5 printers than Times - so use Times New
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v0s0b16901T");
- break;
- case 6: // F6 = Times Italic
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v1s0b16901T");
- break;
- case 7: // F7 = Times Bold
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v0s3b16901T");
- break;
- case 8: // F8 = Times Bold Italic
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v1s3b16901T");
- break;
- case 9: // F9 = Courier
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
- + "h0s0b4099T");
- break;
- case 10: // F10 = Courier Oblique
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
- + "h1s0b4099T");
- break;
- case 11: // F11 = Courier Bold
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
- + "h0s3b4099T");
- break;
- case 12: // F12 = Courier Bold Oblique
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
- + "h1s3b4099T");
- break;
- case 13: // F13 = Symbol
-
- return false;
- //gen.writeCommand("(19M");
- //gen.writeCommand("(s1p" + formattedSize + "v0s0b16686T");
- // ECMA Latin 1 Symbol Set in Times Roman???
- // gen.writeCommand("(9U");
- // gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
- //break;
- case 14: // F14 = Zapf Dingbats
-
- return false;
- //gen.writeCommand("(14L");
- //gen.writeCommand("(s1p" + formattedSize + "v0s0b45101T");
- //break;
- default:
- //gen.writeCommand("(0N");
- //gen.writeCommand("(s" + formattedSize + "V");
- return false;
- }
- return true;
- }
-
- /** @see org.apache.fop.render.Renderer#startRenderer(java.io.OutputStream) */
- public void startRenderer(OutputStream outputStream) throws IOException {
- log.debug("Rendering areas to PCL...");
- this.out = outputStream;
- this.gen = new PCLGenerator(out, getResolution());
-
- gen.universalEndOfLanguage();
- gen.writeText("@PJL COMMENT Produced by " + userAgent.getProducer() + "\n");
- if (userAgent.getTitle() != null) {
- gen.writeText("@PJL JOB NAME = \"" + userAgent.getTitle() + "\"\n");
- }
- gen.writeText("@PJL SET RESOLUTION = " + getResolution() + "\n");
- gen.writeText("@PJL ENTER LANGUAGE = PCL\n");
- gen.resetPrinter();
- gen.setUnitOfMeasure(getResolution());
- gen.setRasterGraphicsResolution(getResolution());
- }
-
- /** @see org.apache.fop.render.Renderer#stopRenderer() */
- public void stopRenderer() throws IOException {
- gen.separateJobs();
- gen.resetPrinter();
- gen.universalEndOfLanguage();
- }
-
- /** @see org.apache.fop.render.AbstractRenderer */
- public String getMimeType() {
- return MIME_TYPE;
- }
-
- /**
- * @see org.apache.fop.render.AbstractRenderer#renderPage(org.apache.fop.area.PageViewport)
- */
- public void renderPage(PageViewport page) throws IOException, FOPException {
- saveGraphicsState();
-
- //Paper source
- String paperSource = page.getForeignAttributeValue(
- new QName(PCLElementMapping.NAMESPACE, null, "paper-source"));
- if (paperSource != null) {
- gen.selectPaperSource(Integer.parseInt(paperSource));
- }
-
- //Page size
- final long pagewidth = Math.round(page.getViewArea().getWidth());
- final long pageheight = Math.round(page.getViewArea().getHeight());
- selectPageFormat(pagewidth, pageheight);
-
- super.renderPage(page);
-
- //Eject page
- gen.formFeed();
- restoreGraphicsState();
- }
-
- private void selectPageFormat(long pagewidth, long pageheight) throws IOException {
- this.currentPageDefinition = PCLPageDefinition.getPageDefinition(
- pagewidth, pageheight, 1000);
-
- if (this.currentPageDefinition == null) {
- this.currentPageDefinition = PCLPageDefinition.getDefaultPageDefinition();
- log.warn("Paper type could not be determined. Falling back to: "
- + this.currentPageDefinition.getName());
- }
- log.debug("page size: " + currentPageDefinition.getPhysicalPageSize());
- log.debug("logical page: " + currentPageDefinition.getLogicalPageRect());
- if (this.currentPageDefinition.isLandscapeFormat()) {
- gen.writeCommand("&l1O"); //Orientation
- } else {
- gen.writeCommand("&l0O"); //Orientation
- }
- gen.selectPageSize(this.currentPageDefinition.getSelector());
-
- gen.clearHorizontalMargins();
- gen.setTopMargin(0);
- }
-
- /** Saves the current graphics state on the stack. */
- protected void saveGraphicsState() {
- graphicContextStack.push(graphicContext);
- graphicContext = (GraphicContext)graphicContext.clone();
- }
-
- /** Restores the last graphics state from the stack. */
- protected void restoreGraphicsState() {
- graphicContext = (GraphicContext)graphicContextStack.pop();
- }
-
- /**
- * Clip an area. write a clipping operation given coordinates in the current
- * transform. Coordinates are in points.
- *
- * @param x the x coordinate
- * @param y the y coordinate
- * @param width the width of the area
- * @param height the height of the area
- */
- protected void clipRect(float x, float y, float width, float height) {
- //PCL cannot clip (only HP GL/2 can)
- }
-
- private Point2D transformedPoint(float x, float y) {
- return transformedPoint(Math.round(x), Math.round(y));
- }
-
- private Point2D transformedPoint(int x, int y) {
- AffineTransform at = graphicContext.getTransform();
- if (log.isTraceEnabled()) {
- log.trace("Current transform: " + at);
- }
- Point2D.Float orgPoint = new Point2D.Float(x, y);
- Point2D.Float transPoint = new Point2D.Float();
- at.transform(orgPoint, transPoint);
- //At this point we have the absolute position in FOP's coordinate system
-
- //Now get PCL coordinates taking the current print direction and the logical page
- //into account.
- Dimension pageSize = currentPageDefinition.getPhysicalPageSize();
- Rectangle logRect = currentPageDefinition.getLogicalPageRect();
- switch (currentPrintDirection) {
- case 0:
- transPoint.x -= logRect.x;
- transPoint.y -= logRect.y;
- break;
- case 90:
- float ty = transPoint.x;
- transPoint.x = pageSize.height - transPoint.y;
- transPoint.y = ty;
- transPoint.x -= logRect.y;
- transPoint.y -= logRect.x;
- break;
- case 180:
- transPoint.x = pageSize.width - transPoint.x;
- transPoint.y = pageSize.height - transPoint.y;
- transPoint.x -= pageSize.width - logRect.x - logRect.width;
- transPoint.y -= pageSize.height - logRect.y - logRect.height;
- //The next line is odd and is probably necessary due to the default value of the
- //Text Length command: "1/2 inch less than maximum text length"
- //I wonder why this isn't necessary for the 90 degree rotation. *shrug*
- transPoint.y -= UnitConv.in2mpt(0.5);
- break;
- case 270:
- float tx = transPoint.y;
- transPoint.y = pageSize.width - transPoint.x;
- transPoint.x = tx;
- transPoint.x -= pageSize.height - logRect.y - logRect.height;
- transPoint.y -= pageSize.width - logRect.x - logRect.width;
- break;
- default:
- throw new IllegalStateException("Illegal print direction: " + currentPrintDirection);
- }
- return transPoint;
- }
-
- private void changePrintDirection() {
- AffineTransform at = graphicContext.getTransform();
- int newDir;
- try {
- if (at.getScaleX() == 0 && at.getScaleY() == 0
- && at.getShearX() == 1 && at.getShearY() == -1) {
- newDir = 90;
- } else if (at.getScaleX() == -1 && at.getScaleY() == -1
- && at.getShearX() == 0 && at.getShearY() == 0) {
- newDir = 180;
- } else if (at.getScaleX() == 0 && at.getScaleY() == 0
- && at.getShearX() == -1 && at.getShearY() == 1) {
- newDir = 270;
- } else {
- newDir = 0;
- }
- if (newDir != this.currentPrintDirection) {
- this.currentPrintDirection = newDir;
- gen.changePrintDirection(this.currentPrintDirection);
- }
- } catch (IOException ioe) {
- handleIOTrouble(ioe);
- }
- }
-
- /**
- * @see org.apache.fop.render.AbstractRenderer#startVParea(CTM, Rectangle2D)
- */
- protected void startVParea(CTM ctm, Rectangle2D clippingRect) {
- saveGraphicsState();
- AffineTransform at = new AffineTransform(ctm.toArray());
- graphicContext.transform(at);
- changePrintDirection();
- if (log.isDebugEnabled()) {
- log.debug("startVPArea: " + at + " --> " + graphicContext.getTransform());
- }
- }
-
- /**
- * @see org.apache.fop.render.AbstractRenderer#endVParea()
- */
- protected void endVParea() {
- restoreGraphicsState();
- changePrintDirection();
- if (log.isDebugEnabled()) {
- log.debug("endVPArea() --> " + graphicContext.getTransform());
- }
- }
-
- /**
- * Handle block traits.
- * The block could be any sort of block with any positioning
- * so this should render the traits such as border and background
- * in its position.
- *
- * @param block the block to render the traits
- */
- protected void handleBlockTraits(Block block) {
- int borderPaddingStart = block.getBorderAndPaddingWidthStart();
- int borderPaddingBefore = block.getBorderAndPaddingWidthBefore();
-
- float startx = currentIPPosition / 1000f;
- float starty = currentBPPosition / 1000f;
- float width = block.getIPD() / 1000f;
- float height = block.getBPD() / 1000f;
-
- startx += block.getStartIndent() / 1000f;
- startx -= block.getBorderAndPaddingWidthStart() / 1000f;
-
- width += borderPaddingStart / 1000f;
- width += block.getBorderAndPaddingWidthEnd() / 1000f;
- height += borderPaddingBefore / 1000f;
- height += block.getBorderAndPaddingWidthAfter() / 1000f;
-
- drawBackAndBorders(block, startx, starty, width, height);
- }
-
- /**
- * @see org.apache.fop.render.AbstractRenderer#renderText(TextArea)
- */
- protected void renderText(final TextArea text) {
- renderInlineAreaBackAndBorders(text);
-
- String fontname = getInternalFontNameForArea(text);
- int fontsize = text.getTraitAsInteger(Trait.FONT_SIZE);
-
- //Determine position
- int saveIP = currentIPPosition;
- int rx = currentIPPosition + text.getBorderAndPaddingWidthStart();
- int bl = currentBPPosition + text.getOffset() + text.getBaselineOffset();
-
- try {
- final Color col = (Color)text.getTrait(Trait.COLOR);
- boolean pclFont = allTextAsBitmaps
- ? false
- : setFont(fontname, fontsize, text.getText());
- if (pclFont) {
- //this.currentFill = col;
- if (col != null) {
- //useColor(ct);
- gen.setTransparencyMode(true, false);
- gen.selectCurrentPattern(gen.convertToPCLShade(col), 2);
- }
-
- saveGraphicsState();
- graphicContext.translate(rx, bl);
- setCursorPos(0, 0);
- gen.setTransparencyMode(true, true);
-
- super.renderText(text); //Updates IPD and renders words and spaces
- restoreGraphicsState();
- } else {
- //Use Java2D to paint different fonts via bitmap
- final Font font = getFontFromArea(text);
- final int baseline = text.getBaselineOffset();
-
- //for cursive fonts, so the text isn't clipped
- int extraWidth = font.getFontSize() / 3;
- final FontMetricsMapper mapper = (FontMetricsMapper)fontInfo.getMetricsFor(
- font.getFontName());
- int maxAscent = mapper.getMaxAscent(font.getFontSize()) / 1000;
- final int additionalBPD = maxAscent - baseline;
-
- Graphics2DAdapter g2a = getGraphics2DAdapter();
- final Rectangle paintRect = new Rectangle(
- rx, currentBPPosition + text.getOffset() - additionalBPD,
- text.getIPD() + extraWidth, text.getBPD() + additionalBPD);
- RendererContext rc = createRendererContext(paintRect.x, paintRect.y,
- paintRect.width, paintRect.height, null);
- Map atts = new java.util.HashMap();
- atts.put(CONV_MODE, "bitmap");
- atts.put(SRC_TRANSPARENCY, "true");
- rc.setProperty(RendererContextConstants.FOREIGN_ATTRIBUTES, atts);
-
- Graphics2DImagePainter painter = new Graphics2DImagePainter() {
-
- public void paint(Graphics2D g2d, Rectangle2D area) {
- g2d.setFont(mapper.getFont(font.getFontSize()));
- g2d.translate(0, baseline + additionalBPD);
- g2d.scale(1000, 1000);
- g2d.setColor(col);
- Java2DRenderer.renderText(text, g2d, font);
- }
-
- public Dimension getImageSize() {
- return paintRect.getSize();
- }
-
- };
- g2a.paintImage(painter, rc,
- paintRect.x, paintRect.y, paintRect.width, paintRect.height);
- currentIPPosition = saveIP + text.getAllocIPD();
- }
-
- //renderTextDecoration(tf, fontsize, area, bl, rx);
- } catch (IOException ioe) {
- handleIOTrouble(ioe);
- }
- }
-
- /**
- * Sets the current cursor position. The coordinates are transformed to the absolute position
- * on the logical PCL page and then passed on to the PCLGenerator.
- * @param x the x coordinate (in millipoints)
- * @param y the y coordinate (in millipoints)
- */
- void setCursorPos(float x, float y) {
- try {
- Point2D transPoint = transformedPoint(x, y);
- gen.setCursorPos(transPoint.getX(), transPoint.getY());
- } catch (IOException ioe) {
- handleIOTrouble(ioe);
- }
- }
-
- /**
- * @see org.apache.fop.render.AbstractPathOrientedRenderer#clip()
- */
- protected void clip() {
- if (currentPath == null) {
- throw new IllegalStateException("No current path available!");
- }
- //TODO Find a good way to do clipping. PCL itself cannot clip.
- currentPath = null;
- }
-
- /**
- * @see org.apache.fop.render.AbstractPathOrientedRenderer#closePath()
- */
- protected void closePath() {
- currentPath.closePath();
- }
-
- /**
- * @see org.apache.fop.render.AbstractPathOrientedRenderer#lineTo(float, float)
- */
- protected void lineTo(float x, float y) {
- if (currentPath == null) {
- currentPath = new GeneralPath();
- }
- currentPath.lineTo(x, y);
- }
-
- /**
- * @see org.apache.fop.render.AbstractPathOrientedRenderer#moveTo(float, float)
- */
- protected void moveTo(float x, float y) {
- if (currentPath == null) {
- currentPath = new GeneralPath();
- }
- currentPath.moveTo(x, y);
- }
-
- /**
- * Fill a rectangular area.
- * @param x the x coordinate (in pt)
- * @param y the y coordinate (in pt)
- * @param width the width of the rectangle
- * @param height the height of the rectangle
- */
- protected void fillRect(float x, float y, float width, float height) {
- try {
- setCursorPos(x * 1000, y * 1000);
- gen.fillRect((int)(width * 1000), (int)(height * 1000),
- this.currentFillColor);
- } catch (IOException ioe) {
- handleIOTrouble(ioe);
- }
- }
-
- /**
- * Sets the new current fill color.
- * @param color the color
- */
- protected void updateFillColor(java.awt.Color color) {
- this.currentFillColor = color;
- }
-
- /**
- * @see org.apache.fop.render.AbstractRenderer#renderWord(org.apache.fop.area.inline.WordArea)
- */
- protected void renderWord(WordArea word) {
- //Font font = getFontFromArea(word.getParentArea());
-
- String s = word.getWord();
-
- try {
- gen.writeText(s);
- } catch (IOException ioe) {
- handleIOTrouble(ioe);
- }
-
- super.renderWord(word);
- }
-
- /**
- * @see org.apache.fop.render.AbstractRenderer#renderSpace(org.apache.fop.area.inline.SpaceArea)
- */
- protected void renderSpace(SpaceArea space) {
- AbstractTextArea textArea = (AbstractTextArea)space.getParentArea();
- String s = space.getSpace();
- char sp = s.charAt(0);
- Font font = getFontFromArea(textArea);
-
- int tws = (space.isAdjustable()
- ? textArea.getTextWordSpaceAdjust()
- + 2 * textArea.getTextLetterSpaceAdjust()
- : 0);
-
- double dx = (font.getCharWidth(sp) + tws) / 100f;
- try {
- gen.writeCommand("&a+" + gen.formatDouble2(dx) + "H");
- } catch (IOException ioe) {
- handleIOTrouble(ioe);
- }
- super.renderSpace(space);
- }
-
- /**
- * Render an inline viewport.
- * This renders an inline viewport by clipping if necessary.
- * @param viewport the viewport to handle
- * @todo Copied from AbstractPathOrientedRenderer
- */
- public void renderViewport(Viewport viewport) {
-
- float x = currentIPPosition / 1000f;
- float y = (currentBPPosition + viewport.getOffset()) / 1000f;
- float width = viewport.getIPD() / 1000f;
- float height = viewport.getBPD() / 1000f;
- // TODO: Calculate the border rect correctly.
- float borderPaddingStart = viewport.getBorderAndPaddingWidthStart() / 1000f;
- float borderPaddingBefore = viewport.getBorderAndPaddingWidthBefore() / 1000f;
- float bpwidth = borderPaddingStart
- + (viewport.getBorderAndPaddingWidthEnd() / 1000f);
- float bpheight = borderPaddingBefore
- + (viewport.getBorderAndPaddingWidthAfter() / 1000f);
-
- drawBackAndBorders(viewport, x, y, width + bpwidth, height + bpheight);
-
- if (viewport.getClip()) {
- saveGraphicsState();
-
- clipRect(x + borderPaddingStart, y + borderPaddingBefore, width, height);
- }
- super.renderViewport(viewport);
-
- if (viewport.getClip()) {
- restoreGraphicsState();
- }
- }
-
- /**
- * @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List)
- */
- protected void renderBlockViewport(BlockViewport bv, List children) {
- // clip and position viewport if necessary
-
- // save positions
- int saveIP = currentIPPosition;
- int saveBP = currentBPPosition;
- //String saveFontName = currentFontName;
-
- CTM ctm = bv.getCTM();
- int borderPaddingStart = bv.getBorderAndPaddingWidthStart();
- int borderPaddingBefore = bv.getBorderAndPaddingWidthBefore();
- float x, y;
- x = (float)(bv.getXOffset() + containingIPPosition) / 1000f;
- y = (float)(bv.getYOffset() + containingBPPosition) / 1000f;
- //This is the content-rect
- float width = (float)bv.getIPD() / 1000f;
- float height = (float)bv.getBPD() / 1000f;
-
-
- if (bv.getPositioning() == Block.ABSOLUTE
- || bv.getPositioning() == Block.FIXED) {
-
- currentIPPosition = bv.getXOffset();
- currentBPPosition = bv.getYOffset();
-
- //For FIXED, we need to break out of the current viewports to the
- //one established by the page. We save the state stack for restoration
- //after the block-container has been painted. See below.
- List breakOutList = null;
- if (bv.getPositioning() == Block.FIXED) {
- breakOutList = breakOutOfStateStack();
- }
-
- CTM tempctm = new CTM(containingIPPosition, containingBPPosition);
- ctm = tempctm.multiply(ctm);
-
- //Adjust for spaces (from margin or indirectly by start-indent etc.
- x += bv.getSpaceStart() / 1000f;
- currentIPPosition += bv.getSpaceStart();
-
- y += bv.getSpaceBefore() / 1000f;
- currentBPPosition += bv.getSpaceBefore();
-
- float bpwidth = (borderPaddingStart + bv.getBorderAndPaddingWidthEnd()) / 1000f;
- float bpheight = (borderPaddingBefore + bv.getBorderAndPaddingWidthAfter()) / 1000f;
-
- drawBackAndBorders(bv, x, y, width + bpwidth, height + bpheight);
-
- //Now adjust for border/padding
- currentIPPosition += borderPaddingStart;
- currentBPPosition += borderPaddingBefore;
-
- Rectangle2D clippingRect = null;
- if (bv.getClip()) {
- clippingRect = new Rectangle(currentIPPosition, currentBPPosition,
- bv.getIPD(), bv.getBPD());
- }
-
- startVParea(ctm, clippingRect);
- currentIPPosition = 0;
- currentBPPosition = 0;
- renderBlocks(bv, children);
- endVParea();
-
- if (breakOutList != null) {
- restoreStateStackAfterBreakOut(breakOutList);
- }
-
- currentIPPosition = saveIP;
- currentBPPosition = saveBP;
- } else {
-
- currentBPPosition += bv.getSpaceBefore();
-
- //borders and background in the old coordinate system
- handleBlockTraits(bv);
-
- //Advance to start of content area
- currentIPPosition += bv.getStartIndent();
-
- CTM tempctm = new CTM(containingIPPosition, currentBPPosition);
- ctm = tempctm.multiply(ctm);
-
- //Now adjust for border/padding
- currentBPPosition += borderPaddingBefore;
-
- Rectangle2D clippingRect = null;
- if (bv.getClip()) {
- clippingRect = new Rectangle(currentIPPosition, currentBPPosition,
- bv.getIPD(), bv.getBPD());
- }
-
- startVParea(ctm, clippingRect);
- currentIPPosition = 0;
- currentBPPosition = 0;
- renderBlocks(bv, children);
- endVParea();
-
- currentIPPosition = saveIP;
- currentBPPosition = saveBP;
-
- currentBPPosition += (int)(bv.getAllocBPD());
- }
- //currentFontName = saveFontName;
- }
-
- private List breakOutOfStateStack() {
- log.debug("Block.FIXED --> break out");
- List breakOutList = new java.util.ArrayList();
- while (!this.graphicContextStack.empty()) {
- breakOutList.add(0, this.graphicContext);
- restoreGraphicsState();
- }
- return breakOutList;
- }
-
- private void restoreStateStackAfterBreakOut(List breakOutList) {
- log.debug("Block.FIXED --> restoring context after break-out");
- for (int i = 0, c = breakOutList.size(); i < c; i++) {
- saveGraphicsState();
- this.graphicContext = (GraphicContext)breakOutList.get(i);
- }
- }
-
- /**
- * @see org.apache.fop.render.AbstractRenderer#renderImage(Image, Rectangle2D)
- */
- public void renderImage(Image image, Rectangle2D pos) {
- drawImage(image.getURL(), pos, image.getForeignAttributes());
- }
-
- /**
- * Draw an image at the indicated location.
- * @param url the URI/URL of the image
- * @param pos the position of the image
- * @param foreignAttributes an optional Map with foreign attributes, may be null
- */
- protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) {
- url = ImageFactory.getURL(url);
- ImageFactory fact = userAgent.getFactory().getImageFactory();
- FopImage fopimage = fact.getImage(url, userAgent);
- if (fopimage == null) {
- return;
- }
- if (!fopimage.load(FopImage.DIMENSIONS)) {
- return;
- }
- String mime = fopimage.getMimeType();
- if ("text/xml".equals(mime)) {
- if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
- return;
- }
- Document doc = ((XMLImage) fopimage).getDocument();
- String ns = ((XMLImage) fopimage).getNameSpace();
-
- renderDocument(doc, ns, pos, foreignAttributes);
- } else if ("image/svg+xml".equals(mime)) {
- if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
- return;
- }
- Document doc = ((XMLImage) fopimage).getDocument();
- String ns = ((XMLImage) fopimage).getNameSpace();
-
- renderDocument(doc, ns, pos, foreignAttributes);
- } else if (fopimage instanceof EPSImage) {
- log.warn("EPS images are not supported by this renderer");
- } else {
- if (!fopimage.load(FopImage.BITMAP)) {
- log.error("Bitmap image could not be processed: " + fopimage);
- return;
- }
- byte[] imgmap = fopimage.getBitmaps();
-
- ColorModel cm = new ComponentColorModel(
- ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB),
- new int[] {8, 8, 8},
- false, false,
- ColorModel.OPAQUE, DataBuffer.TYPE_BYTE);
- int imgw = fopimage.getWidth();
- int imgh = fopimage.getHeight();
- SampleModel sampleModel = new PixelInterleavedSampleModel(
- DataBuffer.TYPE_BYTE, imgw, imgh, 3, imgw * 3, new int[] {0, 1, 2});
- DataBuffer dbuf = new DataBufferByte(imgmap, imgw * imgh * 3);
-
- WritableRaster raster = Raster.createWritableRaster(sampleModel,
- dbuf, null);
-
- // Combine the color model and raster into a buffered image
- RenderedImage img = new BufferedImage(cm, raster, false, null);
-
- try {
- setCursorPos(this.currentIPPosition + (int)pos.getX(),
- this.currentBPPosition + (int)pos.getY());
- gen.paintBitmap(img,
- new Dimension((int)pos.getWidth(), (int)pos.getHeight()),
- false);
- } catch (IOException ioe) {
- handleIOTrouble(ioe);
- }
- }
- }
-
- /**
- * @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D)
- */
- public void renderForeignObject(ForeignObject fo, Rectangle2D pos) {
- Document doc = fo.getDocument();
- String ns = fo.getNameSpace();
- renderDocument(doc, ns, pos, fo.getForeignAttributes());
- }
-
- /**
- * Common method to render the background and borders for any inline area.
- * The all borders and padding are drawn outside the specified area.
- * @param area the inline area for which the background, border and padding is to be
- * rendered
- * @todo Copied from AbstractPathOrientedRenderer
- */
- protected void renderInlineAreaBackAndBorders(InlineArea area) {
- float x = currentIPPosition / 1000f;
- float y = (currentBPPosition + area.getOffset()) / 1000f;
- float width = area.getIPD() / 1000f;
- float height = area.getBPD() / 1000f;
- float borderPaddingStart = area.getBorderAndPaddingWidthStart() / 1000f;
- float borderPaddingBefore = area.getBorderAndPaddingWidthBefore() / 1000f;
- float bpwidth = borderPaddingStart
- + (area.getBorderAndPaddingWidthEnd() / 1000f);
- float bpheight = borderPaddingBefore
- + (area.getBorderAndPaddingWidthAfter() / 1000f);
-
- if (height != 0.0f || bpheight != 0.0f && bpwidth != 0.0f) {
- drawBackAndBorders(area, x, y - borderPaddingBefore
- , width + bpwidth
- , height + bpheight);
- }
- }
-
- /**
- * Draw the background and borders. This draws the background and border
- * traits for an area given the position.
- *
- * @param area the area whose traits are used
- * @param startx the start x position
- * @param starty the start y position
- * @param width the width of the area
- * @param height the height of the area
- */
- protected void drawBackAndBorders(Area area, float startx, float starty,
- float width, float height) {
- BorderProps bpsBefore = (BorderProps) area.getTrait(Trait.BORDER_BEFORE);
- BorderProps bpsAfter = (BorderProps) area.getTrait(Trait.BORDER_AFTER);
- BorderProps bpsStart = (BorderProps) area.getTrait(Trait.BORDER_START);
- BorderProps bpsEnd = (BorderProps) area.getTrait(Trait.BORDER_END);
-
- // draw background
- Trait.Background back;
- back = (Trait.Background) area.getTrait(Trait.BACKGROUND);
- if (back != null) {
-
- // Calculate padding rectangle
- float sx = startx;
- float sy = starty;
- float paddRectWidth = width;
- float paddRectHeight = height;
-
- if (bpsStart != null) {
- sx += bpsStart.width / 1000f;
- paddRectWidth -= bpsStart.width / 1000f;
- }
- if (bpsBefore != null) {
- sy += bpsBefore.width / 1000f;
- paddRectHeight -= bpsBefore.width / 1000f;
- }
- if (bpsEnd != null) {
- paddRectWidth -= bpsEnd.width / 1000f;
- }
- if (bpsAfter != null) {
- paddRectHeight -= bpsAfter.width / 1000f;
- }
-
- if (back.getColor() != null) {
- updateFillColor(back.getColor());
- fillRect(sx, sy, paddRectWidth, paddRectHeight);
- }
-
- // background image
- if (back.getFopImage() != null) {
- FopImage fopimage = back.getFopImage();
- if (fopimage != null && fopimage.load(FopImage.DIMENSIONS)) {
- saveGraphicsState();
- clipRect(sx, sy, paddRectWidth, paddRectHeight);
- int horzCount = (int) ((paddRectWidth * 1000 / fopimage
- .getIntrinsicWidth()) + 1.0f);
- int vertCount = (int) ((paddRectHeight * 1000 / fopimage
- .getIntrinsicHeight()) + 1.0f);
- if (back.getRepeat() == EN_NOREPEAT) {
- horzCount = 1;
- vertCount = 1;
- } else if (back.getRepeat() == EN_REPEATX) {
- vertCount = 1;
- } else if (back.getRepeat() == EN_REPEATY) {
- horzCount = 1;
- }
- // change from points to millipoints
- sx *= 1000;
- sy *= 1000;
- if (horzCount == 1) {
- sx += back.getHoriz();
- }
- if (vertCount == 1) {
- sy += back.getVertical();
- }
- for (int x = 0; x < horzCount; x++) {
- for (int y = 0; y < vertCount; y++) {
- // place once
- Rectangle2D pos;
- // Image positions are relative to the currentIP/BP
- pos = new Rectangle2D.Float(
- sx - currentIPPosition
- + (x * fopimage.getIntrinsicWidth()),
- sy - currentBPPosition
- + (y * fopimage.getIntrinsicHeight()),
- fopimage.getIntrinsicWidth(),
- fopimage.getIntrinsicHeight());
- drawImage(back.getURL(), pos, null);
- }
- }
- restoreGraphicsState();
- } else {
- log.warn(
- "Can't find background image: " + back.getURL());
- }
- }
- }
-
- Rectangle2D.Float borderRect = new Rectangle2D.Float(startx, starty, width, height);
- drawBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
- }
-
- /**
- * Draws borders.
- * @param borderRect the border rectangle
- * @param bpsBefore the border specification on the before side
- * @param bpsAfter the border specification on the after side
- * @param bpsStart the border specification on the start side
- * @param bpsEnd the border specification on the end side
- */
- protected void drawBorders(Rectangle2D.Float borderRect,
- final BorderProps bpsBefore, final BorderProps bpsAfter,
- final BorderProps bpsStart, final BorderProps bpsEnd) {
- if (bpsBefore == null && bpsAfter == null && bpsStart == null && bpsEnd == null) {
- return; //no borders to paint
- }
- if (qualityBeforeSpeed) {
- drawQualityBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
- } else {
- drawFastBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
- }
- }
-
- /**
- * Draws borders. Borders are drawn as shaded rectangles with no clipping.
- * @param borderRect the border rectangle
- * @param bpsBefore the border specification on the before side
- * @param bpsAfter the border specification on the after side
- * @param bpsStart the border specification on the start side
- * @param bpsEnd the border specification on the end side
- */
- protected void drawFastBorders(Rectangle2D.Float borderRect,
- final BorderProps bpsBefore, final BorderProps bpsAfter,
- final BorderProps bpsStart, final BorderProps bpsEnd) {
- float startx = borderRect.x;
- float starty = borderRect.y;
- float width = borderRect.width;
- float height = borderRect.height;
- if (bpsBefore != null) {
- float borderWidth = bpsBefore.width / 1000f;
- updateFillColor(bpsBefore.color);
- fillRect(startx, starty, width, borderWidth);
- }
- if (bpsAfter != null) {
- float borderWidth = bpsAfter.width / 1000f;
- updateFillColor(bpsAfter.color);
- fillRect(startx, (starty + height - borderWidth),
- width, borderWidth);
- }
- if (bpsStart != null) {
- float borderWidth = bpsStart.width / 1000f;
- updateFillColor(bpsStart.color);
- fillRect(startx, starty, borderWidth, height);
- }
- if (bpsEnd != null) {
- float borderWidth = bpsEnd.width / 1000f;
- updateFillColor(bpsEnd.color);
- fillRect((startx + width - borderWidth), starty, borderWidth, height);
- }
- }
-
- /**
- * Draws borders. Borders are drawn in-memory and painted as a bitmap.
- * @param borderRect the border rectangle
- * @param bpsBefore the border specification on the before side
- * @param bpsAfter the border specification on the after side
- * @param bpsStart the border specification on the start side
- * @param bpsEnd the border specification on the end side
- */
- protected void drawQualityBorders(Rectangle2D.Float borderRect,
- final BorderProps bpsBefore, final BorderProps bpsAfter,
- final BorderProps bpsStart, final BorderProps bpsEnd) {
- Graphics2DAdapter g2a = getGraphics2DAdapter();
- final Rectangle.Float effBorderRect = new Rectangle2D.Float(
- borderRect.x - (currentIPPosition / 1000f),
- borderRect.y - (currentBPPosition / 1000f),
- borderRect.width,
- borderRect.height);
- final Rectangle paintRect = new Rectangle(
- (int)Math.round(borderRect.x * 1000f),
- (int)Math.round(borderRect.y * 1000f),
- (int)Math.floor(borderRect.width * 1000f) + 1,
- (int)Math.floor(borderRect.height * 1000f) + 1);
- //Add one pixel wide safety margin around the paint area
- int pixelWidth = (int)Math.round(UnitConv.in2mpt(1) / userAgent.getTargetResolution());
- final int xoffset = (int)Math.round(-effBorderRect.x * 1000f) + pixelWidth;
- final int yoffset = pixelWidth;
- paintRect.x += xoffset;
- paintRect.y += yoffset;
- paintRect.width += 2 * pixelWidth;
- paintRect.height += 2 * pixelWidth;
-
- RendererContext rc = createRendererContext(paintRect.x, paintRect.y,
- paintRect.width, paintRect.height, null);
- Map atts = new java.util.HashMap();
- atts.put(CONV_MODE, "bitmap");
- atts.put(SRC_TRANSPARENCY, "true");
- rc.setProperty(RendererContextConstants.FOREIGN_ATTRIBUTES, atts);
-
- Graphics2DImagePainter painter = new Graphics2DImagePainter() {
-
- public void paint(Graphics2D g2d, Rectangle2D area) {
- g2d.translate(xoffset, yoffset);
- g2d.scale(1000, 1000);
- float startx = effBorderRect.x;
- float starty = effBorderRect.y;
- float width = effBorderRect.width;
- float height = effBorderRect.height;
- boolean[] b = new boolean[] {
- (bpsBefore != null), (bpsEnd != null),
- (bpsAfter != null), (bpsStart != null)};
- if (!b[0] && !b[1] && !b[2] && !b[3]) {
- return;
- }
- float[] bw = new float[] {
- (b[0] ? bpsBefore.width / 1000f : 0.0f),
- (b[1] ? bpsEnd.width / 1000f : 0.0f),
- (b[2] ? bpsAfter.width / 1000f : 0.0f),
- (b[3] ? bpsStart.width / 1000f : 0.0f)};
- float[] clipw = new float[] {
- BorderProps.getClippedWidth(bpsBefore) / 1000f,
- BorderProps.getClippedWidth(bpsEnd) / 1000f,
- BorderProps.getClippedWidth(bpsAfter) / 1000f,
- BorderProps.getClippedWidth(bpsStart) / 1000f};
- starty += clipw[0];
- height -= clipw[0];
- height -= clipw[2];
- startx += clipw[3];
- width -= clipw[3];
- width -= clipw[1];
-
- boolean[] slant = new boolean[] {
- (b[3] && b[0]), (b[0] && b[1]), (b[1] && b[2]), (b[2] && b[3])};
- if (bpsBefore != null) {
- //endTextObject();
-
- float sx1 = startx;
- float sx2 = (slant[0] ? sx1 + bw[3] - clipw[3] : sx1);
- float ex1 = startx + width;
- float ex2 = (slant[1] ? ex1 - bw[1] + clipw[1] : ex1);
- float outery = starty - clipw[0];
- float clipy = outery + clipw[0];
- float innery = outery + bw[0];
-
- //saveGraphicsState();
- Graphics2D g = (Graphics2D)g2d.create();
- moveTo(sx1, clipy);
- float sx1a = sx1;
- float ex1a = ex1;
- if (bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
- if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
- sx1a -= clipw[3];
- }
- if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
- ex1a += clipw[1];
- }
- lineTo(sx1a, outery);
- lineTo(ex1a, outery);
- }
- lineTo(ex1, clipy);
- lineTo(ex2, innery);
- lineTo(sx2, innery);
- closePath();
- //clip();
- g.clip(currentPath);
- currentPath = null;
- Rectangle2D.Float lineRect = new Rectangle2D.Float(
- sx1a, outery, ex1a - sx1a, innery - outery);
- Java2DRenderer.drawBorderLine(lineRect, true, true,
- bpsBefore.style, bpsBefore.color, g);
- //restoreGraphicsState();
- }
- if (bpsEnd != null) {
- //endTextObject();
-
- float sy1 = starty;
- float sy2 = (slant[1] ? sy1 + bw[0] - clipw[0] : sy1);
- float ey1 = starty + height;
- float ey2 = (slant[2] ? ey1 - bw[2] + clipw[2] : ey1);
- float outerx = startx + width + clipw[1];
- float clipx = outerx - clipw[1];
- float innerx = outerx - bw[1];
-
- //saveGraphicsState();
- Graphics2D g = (Graphics2D)g2d.create();
- moveTo(clipx, sy1);
- float sy1a = sy1;
- float ey1a = ey1;
- if (bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
- if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
- sy1a -= clipw[0];
- }
- if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
- ey1a += clipw[2];
- }
- lineTo(outerx, sy1a);
- lineTo(outerx, ey1a);
- }
- lineTo(clipx, ey1);
- lineTo(innerx, ey2);
- lineTo(innerx, sy2);
- closePath();
- //clip();
- g.setClip(currentPath);
- currentPath = null;
- Rectangle2D.Float lineRect = new Rectangle2D.Float(
- innerx, sy1a, outerx - innerx, ey1a - sy1a);
- Java2DRenderer.drawBorderLine(lineRect, false, false,
- bpsEnd.style, bpsEnd.color, g);
- //restoreGraphicsState();
- }
- if (bpsAfter != null) {
- //endTextObject();
-
- float sx1 = startx;
- float sx2 = (slant[3] ? sx1 + bw[3] - clipw[3] : sx1);
- float ex1 = startx + width;
- float ex2 = (slant[2] ? ex1 - bw[1] + clipw[1] : ex1);
- float outery = starty + height + clipw[2];
- float clipy = outery - clipw[2];
- float innery = outery - bw[2];
-
- //saveGraphicsState();
- Graphics2D g = (Graphics2D)g2d.create();
- moveTo(ex1, clipy);
- float sx1a = sx1;
- float ex1a = ex1;
- if (bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
- if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
- sx1a -= clipw[3];
- }
- if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
- ex1a += clipw[1];
- }
- lineTo(ex1a, outery);
- lineTo(sx1a, outery);
- }
- lineTo(sx1, clipy);
- lineTo(sx2, innery);
- lineTo(ex2, innery);
- closePath();
- //clip();
- g.setClip(currentPath);
- currentPath = null;
- Rectangle2D.Float lineRect = new Rectangle2D.Float(
- sx1a, innery, ex1a - sx1a, outery - innery);
- Java2DRenderer.drawBorderLine(lineRect, true, false,
- bpsAfter.style, bpsAfter.color, g);
- //restoreGraphicsState();
- }
- if (bpsStart != null) {
- //endTextObject();
-
- float sy1 = starty;
- float sy2 = (slant[0] ? sy1 + bw[0] - clipw[0] : sy1);
- float ey1 = sy1 + height;
- float ey2 = (slant[3] ? ey1 - bw[2] + clipw[2] : ey1);
- float outerx = startx - clipw[3];
- float clipx = outerx + clipw[3];
- float innerx = outerx + bw[3];
-
- //saveGraphicsState();
- Graphics2D g = (Graphics2D)g2d.create();
- moveTo(clipx, ey1);
- float sy1a = sy1;
- float ey1a = ey1;
- if (bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
- if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
- sy1a -= clipw[0];
- }
- if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
- ey1a += clipw[2];
- }
- lineTo(outerx, ey1a);
- lineTo(outerx, sy1a);
- }
- lineTo(clipx, sy1);
- lineTo(innerx, sy2);
- lineTo(innerx, ey2);
- closePath();
- //clip();
- g.setClip(currentPath);
- currentPath = null;
- Rectangle2D.Float lineRect = new Rectangle2D.Float(
- outerx, sy1a, innerx - outerx, ey1a - sy1a);
- Java2DRenderer.drawBorderLine(lineRect, false, false,
- bpsStart.style, bpsStart.color, g);
- //restoreGraphicsState();
- }
- }
-
- public Dimension getImageSize() {
- return paintRect.getSize();
- }
-
- };
- try {
- g2a.paintImage(painter, rc,
- paintRect.x - xoffset, paintRect.y, paintRect.width, paintRect.height);
- } catch (IOException ioe) {
- handleIOTrouble(ioe);
- }
- }
-
-
-
-}
+++ /dev/null
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed 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.fop.render.pcl;
-
-import org.apache.fop.fo.extensions.ExtensionElementMapping;
-import org.apache.fop.render.RendererContext;
-import org.apache.fop.util.QName;
-
-/**
- * Wrapper on the RendererContext to access the information structure for drawing
- * the XML document.
- */
-public class PCLRendererContext extends RendererContext.RendererContextWrapper {
-
- /**
- * Wrap the render context to allow easier access to its values.
- *
- * @param context the renderer context
- * @return the PCL-specific renderer context wrapper
- */
- public static PCLRendererContext wrapRendererContext(RendererContext context) {
- PCLRendererContext pcli = new PCLRendererContext(context);
- return pcli;
- }
-
- /**
- * Main constructor
- * @param context the RendererContent instance
- */
- public PCLRendererContext(RendererContext context) {
- super(context);
- }
-
- /** @return true if the SVG image should be rendered as a bitmap */
- public boolean paintAsBitmap() {
- QName qName = new QName(ExtensionElementMapping.URI, null, "conversion-mode");
- return getForeignAttributes() != null
- && "bitmap".equalsIgnoreCase((String)getForeignAttributes().get(qName));
- }
-
- /** @return true if clipping is disabled inside the PCLGraphics2D. */
- public boolean isClippingDisabled() {
- QName qName = new QName(ExtensionElementMapping.URI, null, "disable-clipping");
- return getForeignAttributes() != null
- && "true".equalsIgnoreCase((String)getForeignAttributes().get(qName));
- }
-
- public boolean isSourceTransparency() {
- QName qName = new QName(ExtensionElementMapping.URI, null, "source-transparency");
- return getForeignAttributes() != null
- && "true".equalsIgnoreCase((String)getForeignAttributes().get(qName));
- }
-
-
-}
\ No newline at end of file
+++ /dev/null
-/*\r
- * Copyright 2005 The Apache Software Foundation.\r
- * \r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- * \r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/* $Id$ */\r
-\r
-package org.apache.fop.render.pcl;\r
-\r
-import org.apache.fop.apps.FOUserAgent;\r
-import org.apache.fop.apps.MimeConstants;\r
-import org.apache.fop.render.AbstractRendererMaker;\r
-import org.apache.fop.render.Renderer;\r
-\r
-/**\r
- * RendererMaker for the PCL Renderer.\r
- */\r
-public class PCLRendererMaker extends AbstractRendererMaker {\r
-\r
- private static final String[] MIMES = new String[] {\r
- MimeConstants.MIME_PCL,\r
- MimeConstants.MIME_PCL_ALT};\r
- \r
- \r
- /**@see org.apache.fop.render.AbstractRendererMaker */\r
- public Renderer makeRenderer(FOUserAgent ua) {\r
- return new PCLRenderer();\r
- }\r
-\r
- /** @see org.apache.fop.render.AbstractRendererMaker#needsOutputStream() */\r
- public boolean needsOutputStream() {\r
- return true;\r
- }\r
-\r
- /** @see org.apache.fop.render.AbstractRendererMaker#getSupportedMimeTypes() */\r
- public String[] getSupportedMimeTypes() {\r
- return MIMES;\r
- }\r
-\r
-}\r
+++ /dev/null
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed 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.fop.render.pcl;
-
-// FOP
-import org.apache.fop.render.AbstractGenericSVGHandler;
-import org.apache.fop.render.Renderer;
-
-/**
- * PCL XML handler for SVG. Uses Apache Batik for SVG processing.
- * This handler handles XML for foreign objects when rendering to HP GL/2.
- * It renders SVG to HP GL/2 using the PCLGraphics2D.
- * @see PCLGraphics2DAdapter
- */
-public class PCLSVGHandler extends AbstractGenericSVGHandler {
-
- /** @see org.apache.fop.render.XMLHandler#supportsRenderer(org.apache.fop.render.Renderer) */
- public boolean supportsRenderer(Renderer renderer) {
- return (renderer instanceof PCLRenderer);
- }
-
-}
-
+++ /dev/null
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed 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: AFPElementMapping.java 397875 2006-04-28 11:58:33Z manuel $ */
-
-package org.apache.fop.render.pcl.extensions;
-
-import java.util.HashMap;
-
-import org.apache.fop.fo.ElementMapping;
-
-/**
- * PCL-specific extensions for Apache FOP.
- */
-public class PCLElementMapping extends ElementMapping {
-
- /** The namespace used for PCL extensions */
- public static final String NAMESPACE = "http://xmlgraphics.apache.org/fop/extensions/pcl";
-
- /** The usual namespace prefix used for PCL extensions */
- public static final String NAMESPACE_PREFIX = "pcl";
-
- /** Main constructor */
- public PCLElementMapping() {
- this.namespaceURI = NAMESPACE;
- }
-
- /** @see org.apache.fop.fo.ElementMapping#initialize() */
- protected void initialize() {
-
- if (foObjs == null) {
- foObjs = new HashMap();
- //No extension elements, yet, only attributes
- }
-
- }
-
-}
+++ /dev/null
-<!--
- Copyright 2005-2006 The Apache Software Foundation
-
- Licensed 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$ -->
-<HTML>
-<TITLE>org.apache.fop.render.pcl Package</TITLE>
-<BODY>
-<P>PCL Renderer (Supports PCL5 and HP GL/2)</P>
-</BODY>
-</HTML>
\ No newline at end of file