| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.fop.afp; |
| |
| import java.awt.Point; |
| import java.io.IOException; |
| import java.io.ObjectInputStream; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.apache.xmlgraphics.java2d.color.ColorConverter; |
| import org.apache.xmlgraphics.java2d.color.DefaultColorConverter; |
| |
| import org.apache.fop.afp.fonts.AFPPageFonts; |
| import org.apache.fop.util.AbstractPaintingState; |
| |
| /** |
| * This keeps information about the current painting state when writing to an |
| * AFP datastream. |
| */ |
| public class AFPPaintingState extends org.apache.fop.util.AbstractPaintingState { |
| |
| private static final long serialVersionUID = 8206711712452344473L; |
| |
| private static Log log = LogFactory.getLog("org.apache.xmlgraphics.afp"); |
| |
| /** the portrait rotation */ |
| private int portraitRotation; |
| |
| /** the landscape rotation */ |
| private int landscapeRotation = 270; |
| |
| /** color image support */ |
| private boolean colorImages; |
| |
| /** dithering quality setting (0.0f..1.0f) */ |
| private float ditheringQuality; |
| |
| /** image encoding quality setting (0.0f..1.0f) */ |
| private float bitmapEncodingQuality; |
| |
| /** color image handler */ |
| private transient ColorConverter colorConverter; |
| |
| /** |
| * true if certain image formats may be embedded unchanged in their native |
| * format. |
| */ |
| private boolean nativeImagesSupported; |
| |
| private boolean canEmbedJpeg; |
| |
| /** |
| * true if CMYK images (requires IOCA FS45 suppport on the target platform) |
| * may be generated |
| */ |
| private boolean cmykImagesSupported; |
| |
| /** default value for image depth */ |
| private int bitsPerPixel = 8; |
| |
| /** the output resolution */ |
| private int resolution = 240; // 240 dpi |
| |
| /** |
| * A configurable value to correct the line width so that the output matches the expected. Different |
| * devices may need different values. |
| */ |
| private float lineWidthCorrection = AFPConstants.LINE_WIDTH_CORRECTION; |
| |
| /** determines whether GOCA is enabled or disabled */ |
| private boolean gocaEnabled = true; |
| /** determines whether to stroke text in GOCA mode or to use text operators where possible */ |
| private boolean strokeGocaText; |
| |
| |
| /** use page segment with F11 and F45 images*/ |
| private boolean pSeg; |
| |
| private boolean gocaPSeg; |
| |
| /** use FS45 images*/ |
| private boolean fs45; |
| |
| /** the current page */ |
| private transient AFPPagePaintingState pagePaintingState; |
| |
| // /** reference orientation */ |
| // private int orientation = 0; |
| |
| /** a unit converter */ |
| private final transient AFPUnitConverter unitConv; |
| |
| public AFPPaintingState() { |
| colorConverter = GrayScaleColorConverter.getInstance(); |
| pagePaintingState = new AFPPagePaintingState(); |
| unitConv = new AFPUnitConverter(this); |
| } |
| |
| private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { |
| ois.defaultReadObject(); |
| } |
| |
| /** |
| * Sets the rotation to be used for portrait pages, valid values are 0 |
| * (default), 90, 180, 270. |
| * |
| * @param rotation |
| * The rotation in degrees. |
| */ |
| public void setPortraitRotation(int rotation) { |
| if (rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270) { |
| portraitRotation = rotation; |
| } else { |
| throw new IllegalArgumentException("The portrait rotation must be one" |
| + " of the values 0, 90, 180, 270"); |
| |
| } |
| } |
| |
| /** |
| * Returns the rotation to be used for portrait pages |
| * |
| * @return the rotation to be used for portrait pages |
| */ |
| protected int getPortraitRotation() { |
| return this.portraitRotation; |
| } |
| |
| /** |
| * Sets the rotation to be used for landscape pages, valid values are 0, 90, |
| * 180, 270 (default). |
| * |
| * @param rotation |
| * The rotation in degrees. |
| */ |
| public void setLandscapeRotation(int rotation) { |
| if (rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270) { |
| landscapeRotation = rotation; |
| } else { |
| throw new IllegalArgumentException("The landscape rotation must be one" |
| + " of the values 0, 90, 180, 270"); |
| } |
| } |
| |
| /** |
| * Returns the landscape rotation |
| * |
| * @return the landscape rotation |
| */ |
| protected int getLandscapeRotation() { |
| return this.landscapeRotation; |
| } |
| |
| /** |
| * Sets the number of bits used per pixel |
| * |
| * @param bitsPerPixel |
| * number of bits per pixel |
| */ |
| public void setBitsPerPixel(int bitsPerPixel) { |
| switch (bitsPerPixel) { |
| case 1: |
| case 4: |
| case 8: |
| this.bitsPerPixel = bitsPerPixel; |
| break; |
| default: |
| log.warn("Invalid bits_per_pixel value, must be 1, 4 or 8."); |
| this.bitsPerPixel = 8; |
| break; |
| } |
| } |
| |
| /** |
| * Returns the number of bits per pixel |
| * |
| * @return the number of bits per pixel |
| */ |
| public int getBitsPerPixel() { |
| return this.bitsPerPixel; |
| } |
| |
| /** |
| * Sets whether images are color or not and instantiates a ColorHandler |
| * |
| * @param colorImages |
| * color image output |
| */ |
| public void setColorImages(boolean colorImages) { |
| this.colorImages = colorImages; |
| |
| if (colorImages) { |
| this.colorConverter = DefaultColorConverter.getInstance(); |
| } |
| |
| } |
| |
| /** |
| * Returns true if color images are to be used |
| * |
| * @return true if color images are to be used |
| */ |
| public boolean isColorImages() { |
| return this.colorImages; |
| } |
| |
| /** |
| * Used to convert color in respect of the colorImages flag |
| * |
| * @return the color converter |
| */ |
| public ColorConverter getColorConverter() { |
| return this.colorConverter; |
| } |
| |
| /** |
| * Sets whether images are natively supported or not in the AFP environment |
| * |
| * @param nativeImagesSupported |
| * true if images are natively supported in this AFP environment |
| */ |
| public void setNativeImagesSupported(boolean nativeImagesSupported) { |
| this.nativeImagesSupported = nativeImagesSupported; |
| } |
| |
| /** |
| * Returns true if images are supported natively in this AFP environment |
| * |
| * @return true if images are supported natively in this AFP environment |
| */ |
| public boolean isNativeImagesSupported() { |
| return this.nativeImagesSupported; |
| } |
| |
| /** |
| * Set whether or not JPEG images can be embedded within an AFP document. |
| * |
| * @param canEmbed true if the JPEG image can be embedded |
| */ |
| public void setCanEmbedJpeg(boolean canEmbed) { |
| canEmbedJpeg = canEmbed; |
| } |
| |
| /** |
| * Returns true if JPEGs can be embedded in an AFP document. |
| * |
| * @return true if JPEG embedding is allowed |
| */ |
| public boolean canEmbedJpeg() { |
| return canEmbedJpeg; |
| } |
| |
| /** |
| * Controls whether CMYK images (IOCA FS45) are enabled. By default, support |
| * is disabled for wider compatibility. When disabled, any CMYK image is |
| * converted to the selected color format. |
| * |
| * @param value |
| * true to enabled CMYK images |
| */ |
| public void setCMYKImagesSupported(boolean value) { |
| this.cmykImagesSupported = value; |
| } |
| |
| /** |
| * Indicates whether CMYK images (IOCA FS45) are enabled. |
| * |
| * @return true if IOCA FS45 is enabled |
| */ |
| public boolean isCMYKImagesSupported() { |
| return this.cmykImagesSupported; |
| } |
| |
| /** |
| * Gets the dithering quality setting to use when converting images to monochrome images. |
| * @return the dithering quality (a value between 0.0f and 1.0f) |
| */ |
| public float getDitheringQuality() { |
| return this.ditheringQuality; |
| } |
| |
| /** |
| * Sets the dithering quality setting to use when converting images to monochrome images. |
| * @param quality Defines the desired quality level for the conversion. |
| * Valid values: a value between 0.0f (fastest) and 1.0f (best) |
| */ |
| public void setDitheringQuality(float quality) { |
| quality = Math.max(quality, 0.0f); |
| quality = Math.min(quality, 1.0f); |
| this.ditheringQuality = quality; |
| } |
| |
| /** |
| * Gets the image encoding quality setting to use when encoding bitmap images. |
| * @return the encoding quality (a value between 0.0f and 1.0f, 1.0 meaning loss-less) |
| */ |
| public float getBitmapEncodingQuality() { |
| return this.bitmapEncodingQuality; |
| } |
| |
| /** |
| * Sets the image encoding quality setting to use when encoding bitmap images. |
| * @param quality Defines the desired quality level for the conversion. |
| * Valid values: a value between 0.0f (lowest) and 1.0f (best, loss-less) |
| */ |
| public void setBitmapEncodingQuality(float quality) { |
| quality = Math.max(quality, 0.0f); |
| quality = Math.min(quality, 1.0f); |
| this.bitmapEncodingQuality = quality; |
| } |
| |
| /** |
| * Sets the output/device resolution |
| * |
| * @param resolution |
| * the output resolution (dpi) |
| */ |
| public void setResolution(int resolution) { |
| if (log.isDebugEnabled()) { |
| log.debug("renderer-resolution set to: " + resolution + "dpi"); |
| } |
| this.resolution = resolution; |
| } |
| |
| /** |
| * Sets the line width correction |
| * |
| * @param correction the line width multiplying factor correction |
| */ |
| public void setLineWidthCorrection(float correction) { |
| if (log.isDebugEnabled()) { |
| log.debug("line width correction set to: " + correction); |
| } |
| this.lineWidthCorrection = correction; |
| } |
| |
| /** |
| * Returns the output/device resolution. |
| * |
| * @return the resolution in dpi |
| */ |
| public int getResolution() { |
| return this.resolution; |
| } |
| |
| /** |
| * Returns the line width correction. |
| * @return the correction |
| */ |
| public float getLineWidthCorrection() { |
| return this.lineWidthCorrection; |
| } |
| |
| /** |
| * Controls whether GOCA is enabled or disabled. |
| * @param enabled true if GOCA is enabled, false if it is disabled |
| */ |
| public void setGOCAEnabled(boolean enabled) { |
| this.gocaEnabled = enabled; |
| } |
| |
| /** |
| * Indicates whether GOCA is enabled or disabled. |
| * @return true if GOCA is enabled, false if GOCA is disabled |
| */ |
| public boolean isGOCAEnabled() { |
| return this.gocaEnabled; |
| } |
| |
| /** |
| * Controls whether to stroke text in GOCA mode or to use text operators where possible. |
| * @param stroke true to stroke, false to paint with text operators where possible |
| */ |
| public void setStrokeGOCAText(boolean stroke) { |
| this.strokeGocaText = stroke; |
| } |
| |
| /** |
| * Indicates whether to stroke text in GOCA mode or to use text operators where possible. |
| * @return true to stroke, false to paint with text operators where possible |
| */ |
| public boolean isStrokeGOCAText() { |
| return this.strokeGocaText; |
| } |
| |
| /** |
| * Whether FS11 and SF45 non-inline images should be wrapped in a page segment |
| * @return true iff images should be wrapped |
| */ |
| public boolean getWrapPSeg() { |
| return pSeg; |
| } |
| |
| /** |
| * Sets whether FS11 and FS45 non-inline images should be wrapped in a page segment |
| * @param pSeg true iff images should be wrapped |
| */ |
| public void setWrapPSeg(boolean pSeg) { |
| this.pSeg = pSeg; |
| } |
| |
| public boolean getWrapGocaPSeg() { |
| return gocaPSeg; |
| } |
| |
| public void setWrapGocaPSeg(boolean pSeg) { |
| this.gocaPSeg = pSeg; |
| } |
| |
| /** |
| * gets whether images should be FS45 |
| * @return true iff images should be FS45 |
| */ |
| public boolean getFS45() { |
| return fs45; |
| } |
| |
| /** |
| * sets whether images should be FS45 |
| * @param fs45 true iff images should be FS45 |
| */ |
| public void setFS45(boolean fs45) { |
| this.fs45 = fs45; |
| } |
| |
| |
| |
| /** {@inheritDoc} */ |
| @Override |
| protected AbstractData instantiateData() { |
| return new AFPData(); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| protected AbstractPaintingState instantiate() { |
| return new AFPPaintingState(); |
| } |
| |
| /** |
| * Returns the painting state of the current page |
| * |
| * @return the painting state of the current page |
| */ |
| protected AFPPagePaintingState getPagePaintingState() { |
| return this.pagePaintingState; |
| } |
| |
| /** |
| * Gets the current page fonts |
| * |
| * @return the current page fonts |
| */ |
| public AFPPageFonts getPageFonts() { |
| return pagePaintingState.getFonts(); |
| } |
| |
| /** |
| * Sets the page width |
| * |
| * @param pageWidth |
| * the page width |
| */ |
| public void setPageWidth(int pageWidth) { |
| pagePaintingState.setWidth(pageWidth); |
| } |
| |
| /** |
| * Returns the page width |
| * |
| * @return the page width |
| */ |
| public int getPageWidth() { |
| return pagePaintingState.getWidth(); |
| } |
| |
| /** |
| * Sets the page height |
| * |
| * @param pageHeight |
| * the page height |
| */ |
| public void setPageHeight(int pageHeight) { |
| pagePaintingState.setHeight(pageHeight); |
| } |
| |
| /** |
| * Returns the page height |
| * |
| * @return the page height |
| */ |
| public int getPageHeight() { |
| return pagePaintingState.getHeight(); |
| } |
| |
| /** |
| * Returns the page rotation |
| * |
| * @return the page rotation |
| */ |
| public int getPageRotation() { |
| return pagePaintingState.getOrientation(); |
| } |
| |
| /** |
| * Sets the uri of the current image |
| * |
| * @param uri |
| * the uri of the current image |
| */ |
| public void setImageUri(String uri) { |
| ((AFPData) getData()).imageUri = uri; |
| } |
| |
| /** |
| * Gets the uri of the current image |
| * |
| * @return the uri of the current image |
| */ |
| public String getImageUri() { |
| return ((AFPData) getData()).imageUri; |
| } |
| |
| /** |
| * Returns the currently derived rotation |
| * |
| * @return the currently derived rotation |
| */ |
| public int getRotation() { |
| return getData().getDerivedRotation(); |
| } |
| |
| /** |
| * Returns the unit converter |
| * |
| * @return the unit converter |
| */ |
| public AFPUnitConverter getUnitConverter() { |
| return this.unitConv; |
| } |
| |
| /** |
| * Returns a point on the current page, taking the current painting state |
| * into account. |
| * |
| * @param x |
| * the X-coordinate |
| * @param y |
| * the Y-coordinate |
| * @return a point on the current page |
| */ |
| public Point getPoint(int x, int y) { |
| Point p = new Point(); |
| int rotation = getRotation(); |
| switch (rotation) { |
| case 90: |
| p.x = y; |
| p.y = getPageWidth() - x; |
| break; |
| case 180: |
| p.x = getPageWidth() - x; |
| p.y = getPageHeight() - y; |
| break; |
| case 270: |
| p.x = getPageHeight() - y; |
| p.y = x; |
| break; |
| default: |
| p.x = x; |
| p.y = y; |
| break; |
| } |
| return p; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Object clone() { |
| AFPPaintingState paintingState = (AFPPaintingState) super.clone(); |
| paintingState.pagePaintingState = (AFPPagePaintingState) this.pagePaintingState.clone(); |
| paintingState.portraitRotation = this.portraitRotation; |
| paintingState.landscapeRotation = this.landscapeRotation; |
| paintingState.bitsPerPixel = this.bitsPerPixel; |
| paintingState.colorImages = this.colorImages; |
| paintingState.colorConverter = this.colorConverter; |
| paintingState.resolution = this.resolution; |
| return paintingState; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public String toString() { |
| return "AFPPaintingState{" + "portraitRotation=" + portraitRotation |
| + ", landscapeRotation=" + landscapeRotation + ", colorImages=" + colorImages |
| + ", bitsPerPixel=" + bitsPerPixel + ", resolution=" + resolution + ", pageState=" |
| + pagePaintingState + super.toString() + "}"; |
| } |
| |
| /** |
| * Page level state data |
| */ |
| private class AFPPagePaintingState implements Cloneable { |
| /** page width */ |
| private int width; |
| |
| /** page height */ |
| private int height; |
| |
| /** page fonts */ |
| private AFPPageFonts fonts = new AFPPageFonts(); |
| |
| /** page font count */ |
| private int fontCount; |
| |
| /** page orientation */ |
| private int orientation; |
| |
| /** |
| * Returns the page width |
| * |
| * @return the page width |
| */ |
| protected int getWidth() { |
| return width; |
| } |
| |
| /** |
| * Sets the page width |
| * |
| * @param width |
| * the page width |
| */ |
| protected void setWidth(int width) { |
| this.width = width; |
| } |
| |
| /** |
| * Returns the page height |
| * |
| * @return the page height |
| */ |
| protected int getHeight() { |
| return height; |
| } |
| |
| /** |
| * Sets the page height |
| * |
| * @param height |
| * the page height |
| */ |
| protected void setHeight(int height) { |
| this.height = height; |
| } |
| |
| /** |
| * Returns the page fonts |
| * |
| * @return the page fonts |
| */ |
| protected AFPPageFonts getFonts() { |
| return fonts; |
| } |
| |
| /** |
| * Sets the current page fonts |
| * |
| * @param fonts |
| * the current page fonts |
| */ |
| protected void setFonts(AFPPageFonts fonts) { |
| this.fonts = fonts; |
| } |
| |
| /** |
| * Increments and returns the current page font count |
| * |
| * @return increment and return the current page font count |
| */ |
| protected int incrementFontCount() { |
| return ++fontCount; |
| } |
| |
| /** |
| * Returns the current page orientation |
| * |
| * @return the current page orientation |
| */ |
| protected int getOrientation() { |
| return orientation; |
| } |
| |
| /** |
| * Sets the current page orientation |
| * |
| * @param orientation |
| * the current page orientation |
| */ |
| protected void setOrientation(int orientation) { |
| this.orientation = orientation; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Object clone() { |
| AFPPagePaintingState state = new AFPPagePaintingState(); |
| state.width = this.width; |
| state.height = this.height; |
| state.orientation = this.orientation; |
| state.fonts = new AFPPageFonts(this.fonts); |
| state.fontCount = this.fontCount; |
| return state; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public String toString() { |
| return "AFPPagePaintingState{width=" + width + ", height=" + height + ", orientation=" |
| + orientation + ", fonts=" + fonts + ", fontCount=" + fontCount + "}"; |
| } |
| } |
| |
| /** |
| * Block level state data |
| */ |
| // @SuppressFBWarnings("SE_INNER_CLASS") |
| private class AFPData extends org.apache.fop.util.AbstractPaintingState.AbstractData { |
| private static final long serialVersionUID = -1789481244175275686L; |
| |
| /** The current fill status */ |
| private boolean filled; |
| |
| private String imageUri; |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Object clone() { |
| AFPData obj = (AFPData) super.clone(); |
| obj.filled = this.filled; |
| obj.imageUri = this.imageUri; |
| return obj; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public String toString() { |
| return "AFPData{" + super.toString() + ", filled=" + filled + ", imageUri=" + imageUri |
| + "}"; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| protected AbstractData instantiate() { |
| return new AFPData(); |
| } |
| } |
| |
| } |