From: Adrian Cumiskey Date: Tue, 4 Nov 2008 15:30:38 +0000 (+0000) Subject: "fixed" block container handling fixed (see block-container_absolute-position_fixed... X-Git-Tag: fop-1_0~376^2~26 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=74355f1f4b9ce01d9ad26c4c42ad025daff1263f;p=xmlgraphics-fop.git "fixed" block container handling fixed (see block-container_absolute-position_fixed.xml). Barcode4J generating barcodes correctly for both GOCA and conversion-mode="bitmap". AbstractGenericSVGHandler now declares use of static final String BITMAP which is used by concrete subclasses and provides overridable methods. for buildGraphicsNode() and createPainter(). *State classes are now renamed *PaintingState. AFPImageGraphics2DFactory - painter is not overriden but is now instead prepared for y-axis inversion. AFPGraphics2DAdapter - commented lines removed. Inlining now only done when the graphic is a non conversion-mode="bitmap". git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AFPGOCAResources@711273 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/fop/AbstractData.java b/src/java/org/apache/fop/AbstractData.java deleted file mode 100644 index b689165a0..000000000 --- a/src/java/org/apache/fop/AbstractData.java +++ /dev/null @@ -1,128 +0,0 @@ -package org.apache.fop; - -import java.awt.Color; -import java.awt.geom.AffineTransform; -import java.io.Serializable; - -/** - * A base state data holding object - */ -public abstract class AbstractData implements Cloneable, Serializable { - - private static final long serialVersionUID = 5208418041189828624L; - - /** The current color */ - protected Color color = null; - - /** The current background color */ - protected Color backColor = null; - - /** The current font name */ - protected String fontName = null; - - /** The current font size */ - protected int fontSize = 0; - - /** The current line width */ - protected float lineWidth = 0; - - /** The dash array for the current basic stroke (line type) */ - protected float[] dashArray = null; - - /** The current transform */ - protected AffineTransform transform = null; - - /** - * Returns a newly create data object - * - * @return a new data object - */ - protected abstract AbstractData instantiate(); - - /** - * Concatenate the given AffineTransform with the current thus creating - * a new viewport. Note that all concatenation operations are logged - * so they can be replayed if necessary (ex. for block-containers with - * "fixed" positioning. - * - * @param at Transformation to perform - */ - public void concatenate(AffineTransform at) { - getTransform().concatenate(at); - } - - /** - * Get the current AffineTransform. - * - * @return the current transform - */ - public AffineTransform getTransform() { - if (transform == null) { - transform = new AffineTransform(); - } - return transform; - } - - /** - * Sets the current AffineTransform. - */ - public void setTransform(AffineTransform baseTransform) { - this.transform = baseTransform; - } - - /** - * Resets the current AffineTransform. - */ - public void clearTransform() { - transform = new AffineTransform(); - } - - /** - * Returns the derived rotation from the current transform - * - * @return the derived rotation from the current transform - */ - public int getDerivedRotation() { - AffineTransform at = getTransform(); - double sx = at.getScaleX(); - double sy = at.getScaleY(); - double shx = at.getShearX(); - double shy = at.getShearY(); - int rotation = 0; - if (sx == 0 && sy == 0 && shx > 0 && shy < 0) { - rotation = 270; - } else if (sx < 0 && sy < 0 && shx == 0 && shy == 0) { - rotation = 180; - } else if (sx == 0 && sy == 0 && shx < 0 && shy > 0) { - rotation = 90; - } else { - rotation = 0; - } - return rotation; - } - - /** {@inheritDoc} */ - public Object clone() { - AbstractData data = instantiate(); - data.color = this.color; - data.backColor = this.backColor; - data.fontName = this.fontName; - data.fontSize = this.fontSize; - data.lineWidth = this.lineWidth; - data.dashArray = this.dashArray; - data.transform = new AffineTransform(this.transform); - return data; - } - - /** {@inheritDoc} */ - public String toString() { - return "color=" + color - + ", backColor=" + backColor - + ", fontName=" + fontName - + ", fontSize=" + fontSize - + ", lineWidth=" + lineWidth - + ", dashArray=" + dashArray - + ", transform=" + transform; - } - -} \ No newline at end of file diff --git a/src/java/org/apache/fop/AbstractState.java b/src/java/org/apache/fop/AbstractState.java deleted file mode 100644 index 74719e8f8..000000000 --- a/src/java/org/apache/fop/AbstractState.java +++ /dev/null @@ -1,377 +0,0 @@ -/* - * 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; - -import java.awt.Color; -import java.awt.geom.AffineTransform; -import java.io.Serializable; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.Stack; - - -/** - * A base class which holds information about the current rendering state. - */ -public abstract class AbstractState implements Cloneable, Serializable { - - private static final long serialVersionUID = 5998356138437094188L; - - /** current state data */ - private AbstractData data = null; - - /** the state stack */ - private StateStack stateStack = new StateStack(); - - /** - * Instantiates a new state data object - * - * @return a new state data object - */ - protected abstract AbstractData instantiateData(); - - /** - * Instantiates a new state object - * - * @return a new state object - */ - protected abstract AbstractState instantiateState(); - - /** - * Returns the currently valid state - * - * @return the currently valid state - */ - public AbstractData getData() { - if (data == null) { - data = instantiateData(); - } - return data; - } - - /** - * Set the current color. - * Check if the new color is a change and then set the current color. - * - * @param col the color to set - * @return true if the color has changed - */ - public boolean setColor(Color col) { - if (!col.equals(getData().color)) { - getData().color = col; - return true; - } - return false; - } - - /** - * Get the color. - * - * @return the color - */ - public Color getColor() { - if (getData().color == null) { - getData().color = Color.black; - } - return getData().color; - } - - /** - * Get the background color. - * - * @return the background color - */ - public Color getBackColor() { - if (getData().backColor == null) { - getData().backColor = Color.white; - } - return getData().backColor; - } - - /** - * Set the current background color. - * Check if the new background color is a change and then set the current background color. - * - * @param col the background color to set - * @return true if the color has changed - */ - public boolean setBackColor(Color col) { - if (!col.equals(getData().backColor)) { - getData().backColor = col; - return true; - } - return false; - } - - /** - * Set the current font name - * - * @param internalFontName the internal font name - * @return true if the font name has changed - */ - public boolean setFontName(String internalFontName) { - if (!internalFontName.equals(getData().fontName)) { - getData().fontName = internalFontName; - return true; - } - return false; - } - - /** - * Gets the current font name - * - * @return the current font name - */ - public String getFontName() { - return getData().fontName; - } - - /** - * Gets the current font size - * - * @return the current font size - */ - public int getFontSize() { - return getData().fontSize; - } - - /** - * Set the current font size. - * Check if the font size is a change and then set the current font size. - * - * @param size the font size to set - * @return true if the font size has changed - */ - public boolean setFontSize(int size) { - if (size != getData().fontSize) { - getData().fontSize = size; - return true; - } - return false; - } - - /** - * Set the current line width. - * - * @param width the line width in points - * @return true if the line width has changed - */ - public boolean setLineWidth(float width) { - if (getData().lineWidth != width) { - getData().lineWidth = width; - return true; - } - return false; - } - - /** - * Returns the current line width - * - * @return the current line width - */ - public float getLineWidth() { - return getData().lineWidth; - } - - /** - * Sets the dash array (line type) for the current basic stroke - * - * @param dash the line dash array - * @return true if the dash array has changed - */ - public boolean setDashArray(float[] dash) { - if (!Arrays.equals(dash, getData().dashArray)) { - getData().dashArray = dash; - return true; - } - return false; - } - - /** - * Get the current transform. - * This gets the combination of all transforms in the - * current state. - * - * @return the calculate combined transform for the current state - */ - public AffineTransform getTransform() { - AffineTransform at = new AffineTransform(); - for (Iterator iter = stateStack.iterator(); iter.hasNext();) { - AbstractData data = (AbstractData)iter.next(); - AffineTransform stackTrans = data.getTransform(); - at.concatenate(stackTrans); - } - AffineTransform currentTrans = getData().getTransform(); - at.concatenate(currentTrans); - return at; - } - - /** - * Check the current transform. - * The transform for the current state is the combination of all - * transforms in the current state. The parameter is compared - * against this current transform. - * - * @param tf the transform the check against - * @return true if the new transform is different then the current transform - */ - public boolean checkTransform(AffineTransform tf) { - return !tf.equals(getData().getTransform()); - } - - /** - * Get a copy of the base transform for the page. Used to translate - * IPP/BPP values into X,Y positions when positioning is "fixed". - * - * @return the base transform, or null if the state stack is empty - */ - public AffineTransform getBaseTransform() { - if (stateStack.isEmpty()) { - return null; - } else { - AbstractData baseData = (AbstractData)stateStack.get(0); - return (AffineTransform) baseData.getTransform().clone(); - } - } - - /** - * Concatenates the given AffineTransform to the current one. - * - * @param at the transform to concatenate to the current level transform - */ - public void concatenate(AffineTransform at) { - getData().concatenate(at); - } - - /** - * Resets the current AffineTransform to the Base AffineTransform. - */ - public void resetTransform() { - getData().setTransform(getBaseTransform()); - } - - /** - * Clears the current AffineTransform to the Identity AffineTransform - */ - public void clearTransform() { - getData().clearTransform(); - } - - - /** - * Push the current state onto the stack. - * This call should be used when the Q operator is used - * so that the state is known when popped. - */ - public void push() { - AbstractData copy = (AbstractData)getData().clone(); - stateStack.push(copy); - } - - /** - * Pop the state from the stack and set current values to popped state. - * This should be called when a Q operator is used so - * the state is restored to the correct values. - * - * @return the restored state, null if the stack is empty - */ - public AbstractData pop() { - if (!stateStack.isEmpty()) { - setData((AbstractData)stateStack.pop()); - return this.data; - } else { - return null; - } - } - - /** - * Pushes all state data in the given list to the stack - * - * @param dataList a state data list - */ - public void pushAll(List/**/ dataList) { - Iterator it = dataList.iterator(); - while (it.hasNext()) { - // save current data on stack - push(); - setData((AbstractData)it.next()); - } - } - - /** - * Pops all state data from the stack - * - * @return a list of state data popped from the stack - */ - public List/**/ popAll() { - List/**/ dataList = new java.util.ArrayList/**/(); - AbstractData data; - while (true) { - data = getData(); - if (pop() == null) { - break; - } - // insert because of stack-popping - dataList.add(0, data); - } - return dataList; - } - - /** - * Sets the current state data - * - * @param currentData state data - */ - protected void setData(AbstractData data) { - this.data = data; - } - - /** - * Clears the state stack - */ - public void clear() { - stateStack.clear(); - setData(null); - } - - /** - * Return the state stack - * - * @return the state stack - */ - protected Stack/**/ getStateStack() { - return this.stateStack; - } - - /** {@inheritDoc} */ - public Object clone() { - AbstractState state = instantiateState(); - state.stateStack = new StateStack(this.stateStack); - state.data = (AbstractData)this.data.clone(); - return state; - } - - /** {@inheritDoc} */ - public String toString() { - return ", stateStack=" + stateStack - + ", currentData=" + data; - } -} diff --git a/src/java/org/apache/fop/StateStack.java b/src/java/org/apache/fop/StateStack.java deleted file mode 100644 index 0c73b4829..000000000 --- a/src/java/org/apache/fop/StateStack.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.apache.fop; - -import java.util.Collection; - -/** - * No copy constructor for java.util.Stack so extended and implemented one. - */ -class StateStack extends java.util.Stack { - - private static final long serialVersionUID = 4897178211223823041L; - - /** - * Default constructor - */ - public StateStack() { - super(); - } - - /** - * Copy constructor - * - * @param c initial contents of stack - */ - public StateStack(Collection c) { - elementCount = c.size(); - // 10% for growth - elementData = new Object[ - (int)Math.min((elementCount * 110L) / 100, Integer.MAX_VALUE)]; - c.toArray(elementData); - } -} \ No newline at end of file diff --git a/src/java/org/apache/fop/afp/AFPAbstractGraphicsObjectPainter.java b/src/java/org/apache/fop/afp/AFPAbstractGraphicsObjectPainter.java deleted file mode 100644 index 8c5e84012..000000000 --- a/src/java/org/apache/fop/afp/AFPAbstractGraphicsObjectPainter.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.fop.afp.modca.GraphicsObject; -import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; - -/** - * A simple AFP Graphics 2D painter - */ -public abstract class AFPAbstractGraphicsObjectPainter implements Graphics2DImagePainter { - /** Static logging instance */ - protected static Log log = LogFactory.getLog(AFPAbstractGraphicsObjectPainter.class); - - private final AFPGraphics2D graphics2D; - - /** - * Default constructor - */ - public AFPAbstractGraphicsObjectPainter() { - final boolean textAsShapes = false; - this.graphics2D = new AFPGraphics2D(textAsShapes); - } - - /** - * Constructor - * - * @param graphics the afp graphics 2d implementation - */ - public AFPAbstractGraphicsObjectPainter(AFPGraphics2D graphics) { - this.graphics2D = graphics; - } - - /** - * Sets the GOCA Graphics Object - * - * @param graphicsObject the GOCA Graphics Object - */ - public void setGraphicsObject(GraphicsObject graphicsObject) { - this.graphics2D.setGraphicsObject(graphicsObject); - } - -} \ No newline at end of file diff --git a/src/java/org/apache/fop/afp/AFPBorderPainter.java b/src/java/org/apache/fop/afp/AFPBorderPainter.java index 96f9ae78f..86960b7ff 100644 --- a/src/java/org/apache/fop/afp/AFPBorderPainter.java +++ b/src/java/org/apache/fop/afp/AFPBorderPainter.java @@ -33,10 +33,10 @@ public class AFPBorderPainter extends AbstractAFPPainter { /** * Main constructor * - * @param state the unit converter - * @param dataStream the afp datastream + * @param state the AFP painting state converter + * @param dataStream the AFP datastream */ - public AFPBorderPainter(AFPState state, DataStream dataStream) { + public AFPBorderPainter(AFPPaintingState state, DataStream dataStream) { super(state, dataStream); } diff --git a/src/java/org/apache/fop/afp/AFPGraphics2D.java b/src/java/org/apache/fop/afp/AFPGraphics2D.java index 21114bb88..d412e2b94 100644 --- a/src/java/org/apache/fop/afp/AFPGraphics2D.java +++ b/src/java/org/apache/fop/afp/AFPGraphics2D.java @@ -98,7 +98,7 @@ public class AFPGraphics2D extends AbstractGraphics2D { private AFPResourceInfo resourceInfo = null; /** Current AFP state */ - private AFPState state = null; + private AFPPaintingState state = null; /** The AFP FontInfo */ private FontInfo fontInfo; @@ -498,15 +498,15 @@ public class AFPGraphics2D extends AbstractGraphics2D { g2d.fillRect(0, 0, width, height); - int bufferedWidth = bufferedImage.getWidth(); - int bufferedHeight = bufferedImage.getHeight(); - Rectangle clipRect = new Rectangle(0, 0, bufferedWidth, bufferedHeight); + int imageWidth = bufferedImage.getWidth(); + int imageHeight = bufferedImage.getHeight(); + Rectangle clipRect = new Rectangle(0, 0, imageWidth, imageHeight); g2d.clip(clipRect); g2d.setComposite(gc.getComposite()); - boolean drawn = g2d.drawImage(img, 0, 0, bufferedWidth, bufferedHeight, observer); - g2d.dispose(); + boolean drawn = g2d.drawImage(img, 0, 0, imageWidth, imageHeight, observer); + g2d.dispose(); //drawn so dispose immediately to free system resource if (drawn) { try { @@ -575,11 +575,11 @@ public class AFPGraphics2D extends AbstractGraphics2D { } /** - * Sets the AFP state + * Sets the AFP painting state * - * @param state the AFP state + * @param state the AFP painting state */ - public void setState(AFPState state) { + public void setPaintingState(AFPPaintingState state) { this.state = state; } @@ -588,7 +588,7 @@ public class AFPGraphics2D extends AbstractGraphics2D { * * @return the AFP state */ - public AFPState getState() { + public AFPPaintingState getPaintingState() { return this.state; } diff --git a/src/java/org/apache/fop/afp/AFPPaintingState.java b/src/java/org/apache/fop/afp/AFPPaintingState.java new file mode 100644 index 000000000..60e4812b9 --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPPaintingState.java @@ -0,0 +1,516 @@ +/* + * 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 org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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 implements Cloneable { + + private static final long serialVersionUID = 8206711712452344473L; + + private static Log log = LogFactory.getLog("org.apache.xmlgraphics.afp"); + + /** the portrait rotation */ + private int portraitRotation = 0; + + /** the landscape rotation */ + private int landscapeRotation = 270; + + /** color image support */ + private boolean colorImages = false; + + /** images are supported in this AFP environment */ + private boolean nativeImages = false; + + /** default value for image depth */ + private int bitsPerPixel = 8; + + /** the output resolution */ + private int resolution = 240; // 240 dpi + + /** the current page */ + private AFPPagePaintingState pagePaintingState = new AFPPagePaintingState(); + +// /** reference orientation */ +// private int orientation = 0; + + /** a unit converter */ + private final transient AFPUnitConverter unitConv = new AFPUnitConverter(this); + + /** + * 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 + * + * @param colorImages + * color image output + */ + public void setColorImages(boolean colorImages) { + this.colorImages = colorImages; + } + + /** + * Returns true if color images are to be used + * + * @return true if color images are to be used + */ + public boolean isColorImages() { + return this.colorImages; + } + + /** + * Sets whether images are natively supported or not in the AFP environment + * + * @param nativeImages true if images are natively supported in this AFP environment + */ + public void setNativeImages(boolean nativeImages) { + this.nativeImages = nativeImages; + } + + /** + * Returns true if images are supported natively in this AFP environment + * + * @return true if images are supported natively in this AFP environment + */ + public boolean isNativeImages() { + return this.nativeImages; + } + + /** + * 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; + } + + /** + * Returns the output/device resolution. + * + * @return the resolution in dpi + */ + public int getResolution() { + return this.resolution; + } + + /** {@inheritDoc} */ + protected AbstractData instantiateData() { + return new AFPData(); + } + + /** {@inheritDoc} */ + 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; + } + + /** + * Sets if the current painted shape is to be filled + * + * @param fill true if the current painted shape is to be filled + * @return true if the fill value has changed + */ + protected boolean setFill(boolean fill) { + if (fill != ((AFPData)getData()).filled) { + ((AFPData)getData()).filled = fill; + return true; + } + return false; + } + + /** + * Gets the current page fonts + * + * @return the current page fonts + */ + public AFPPageFonts getPageFonts() { + return pagePaintingState.getFonts(); + } + + /** + * Increments and returns the page font count + * + * @return the page font count + */ + public int incrementPageFontCount() { + return pagePaintingState.incrementFontCount(); + } + + /** + * 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; + } + + /** {@inheritDoc} */ + public Object clone() { + AFPPaintingState state = (AFPPaintingState)super.clone(); + state.pagePaintingState = (AFPPagePaintingState)this.pagePaintingState.clone(); + state.portraitRotation = this.portraitRotation; + state.landscapeRotation = this.landscapeRotation; + state.bitsPerPixel = this.bitsPerPixel; + state.colorImages = this.colorImages; + state.resolution = this.resolution; + return state; + } + + /** {@inheritDoc} */ + 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 = 0; + + /** page height */ + private int height = 0; + + /** page fonts */ + private AFPPageFonts fonts = new AFPPageFonts(); + + /** page font count */ + private int fontCount = 0; + + /** page orientation */ + private int orientation = 0; + + /** + * 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} */ + 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} */ + public String toString() { + return "AFPPagePaintingState{width=" + width + + ", height=" + height + + ", orientation=" + orientation + + ", fonts=" + fonts + + ", fontCount=" + fontCount + + "}"; + } + } + + /** + * Block level state data + */ + private class AFPData extends org.apache.fop.util.AbstractPaintingState.AbstractData { + private static final long serialVersionUID = -1789481244175275686L; + + /** The current fill status */ + private boolean filled = false; + + private String imageUri = null; + + /** {@inheritDoc} */ + public Object clone() { + AFPData obj = (AFPData)super.clone(); + obj.filled = this.filled; + obj.imageUri = this.imageUri; + return obj; + } + + /** {@inheritDoc} */ + public String toString() { + return "AFPData{" + super.toString() + + ", filled=" + filled + + ", imageUri=" + imageUri + + "}"; + } + + /** {@inheritDoc} */ + protected AbstractData instantiate() { + return new AFPData(); + } + } + +} \ No newline at end of file diff --git a/src/java/org/apache/fop/afp/AFPRectanglePainter.java b/src/java/org/apache/fop/afp/AFPRectanglePainter.java index 56c60b440..81915a190 100644 --- a/src/java/org/apache/fop/afp/AFPRectanglePainter.java +++ b/src/java/org/apache/fop/afp/AFPRectanglePainter.java @@ -28,10 +28,10 @@ public class AFPRectanglePainter extends AbstractAFPPainter { /** * Main constructor * - * @param state the afp state + * @param state the AFP painting state * @param dataStream the afp datastream */ - public AFPRectanglePainter(AFPState state, DataStream dataStream) { + public AFPRectanglePainter(AFPPaintingState state, DataStream dataStream) { super(state, dataStream); } diff --git a/src/java/org/apache/fop/afp/AFPResourceLevel.java b/src/java/org/apache/fop/afp/AFPResourceLevel.java index 85cdefb4b..5e8d54aae 100644 --- a/src/java/org/apache/fop/afp/AFPResourceLevel.java +++ b/src/java/org/apache/fop/afp/AFPResourceLevel.java @@ -55,7 +55,7 @@ public class AFPResourceLevel { /** where the resource will reside in the AFP output */ - private int level = PRINT_FILE; // default is print-file level + private int level = PRINT_FILE; // default is print-file level (images) /** the external resource group file path */ private String extFilePath = null; diff --git a/src/java/org/apache/fop/afp/AFPResourceManager.java b/src/java/org/apache/fop/afp/AFPResourceManager.java index 111238be8..c912b8b17 100644 --- a/src/java/org/apache/fop/afp/AFPResourceManager.java +++ b/src/java/org/apache/fop/afp/AFPResourceManager.java @@ -68,10 +68,10 @@ public class AFPResourceManager { /** * Sets the outputstream * - * @param state the afp state + * @param state the AFP painting state * @param outputStream the outputstream */ - public void createDataStream(AFPState state, OutputStream outputStream) { + public void createDataStream(AFPPaintingState state, OutputStream outputStream) { this.dataStream = streamer.createDataStream(state); streamer.setOutputStream(outputStream); } diff --git a/src/java/org/apache/fop/afp/AFPState.java b/src/java/org/apache/fop/afp/AFPState.java deleted file mode 100644 index 7e63ea01e..000000000 --- a/src/java/org/apache/fop/afp/AFPState.java +++ /dev/null @@ -1,517 +0,0 @@ -/* - * 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 org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.fop.AbstractData; -import org.apache.fop.AbstractState; - -/** - * This keeps information about the current state when writing to an AFP datastream. - */ -public class AFPState extends org.apache.fop.AbstractState implements Cloneable { - - private static final long serialVersionUID = 8206711712452344473L; - - private static Log log = LogFactory.getLog("org.apache.xmlgraphics.afp"); - - /** the portrait rotation */ - private int portraitRotation = 0; - - /** the landscape rotation */ - private int landscapeRotation = 270; - - /** color image support */ - private boolean colorImages = false; - - /** images are supported in this AFP environment */ - private boolean nativeImages = false; - - /** default value for image depth */ - private int bitsPerPixel = 8; - - /** the output resolution */ - private int resolution = 240; // 240 dpi - - /** the current page */ - private AFPPageState pageState = new AFPPageState(); - -// /** reference orientation */ -// private int orientation = 0; - - /** a unit converter */ - private final transient AFPUnitConverter unitConv = new AFPUnitConverter(this); - - /** - * 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 - * - * @param colorImages - * color image output - */ - public void setColorImages(boolean colorImages) { - this.colorImages = colorImages; - } - - /** - * Returns true if color images are to be used - * - * @return true if color images are to be used - */ - public boolean isColorImages() { - return this.colorImages; - } - - /** - * Sets whether images are natively supported or not in the AFP environment - * - * @param nativeImages true if images are natively supported in this AFP environment - */ - public void setNativeImages(boolean nativeImages) { - this.nativeImages = nativeImages; - } - - /** - * Returns true if images are supported natively in this AFP environment - * - * @return true if images are supported natively in this AFP environment - */ - public boolean isNativeImages() { - return this.nativeImages; - } - - /** - * 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; - } - - /** - * Returns the output/device resolution. - * - * @return the resolution in dpi - */ - public int getResolution() { - return this.resolution; - } - - /** {@inheritDoc} */ - protected AbstractData instantiateData() { - return new AFPData(); - } - - /** {@inheritDoc} */ - protected AbstractState instantiateState() { - return new AFPState(); - } - - /** - * Returns the state of the current page - * - * @return the state of the current page - */ - protected AFPPageState getPageState() { - return this.pageState; - } - - /** - * Sets if the current painted shape is to be filled - * - * @param fill true if the current painted shape is to be filled - * @return true if the fill value has changed - */ - protected boolean setFill(boolean fill) { - if (fill != ((AFPData)getData()).filled) { - ((AFPData)getData()).filled = fill; - return true; - } - return false; - } - - /** - * Gets the current page fonts - * - * @return the current page fonts - */ - public AFPPageFonts getPageFonts() { - return pageState.getFonts(); - } - - /** - * Increments and returns the page font count - * - * @return the page font count - */ - public int incrementPageFontCount() { - return pageState.incrementFontCount(); - } - - /** - * Sets the page width - * - * @param pageWidth the page width - */ - public void setPageWidth(int pageWidth) { - pageState.setWidth(pageWidth); - } - - /** - * Returns the page width - * - * @return the page width - */ - public int getPageWidth() { - return pageState.getWidth(); - } - - /** - * Sets the page height - * - * @param pageHeight the page height - */ - public void setPageHeight(int pageHeight) { - pageState.setHeight(pageHeight); - } - - /** - * Returns the page height - * - * @return the page height - */ - public int getPageHeight() { - return pageState.getHeight(); - } - - /** - * Returns the page rotation - * - * @return the page rotation - */ - public int getPageRotation() { - return pageState.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; - } - - /** {@inheritDoc} */ - public Object clone() { - AFPState state = (AFPState)super.clone(); - state.pageState = (AFPPageState)this.pageState.clone(); - state.portraitRotation = this.portraitRotation; - state.landscapeRotation = this.landscapeRotation; - state.bitsPerPixel = this.bitsPerPixel; - state.colorImages = this.colorImages; - state.resolution = this.resolution; - return state; - } - - /** {@inheritDoc} */ - public String toString() { - return "AFPState{" + "portraitRotation=" + portraitRotation - + ", landscapeRotation=" + landscapeRotation - + ", colorImages=" + colorImages - + ", bitsPerPixel=" + bitsPerPixel - + ", resolution=" + resolution - + ", pageState=" + pageState - + super.toString() - + "}"; - } - - /** - * Page level state data - */ - private class AFPPageState implements Cloneable { - /** page width */ - private int width = 0; - - /** page height */ - private int height = 0; - - /** page fonts */ - private AFPPageFonts fonts = new AFPPageFonts(); - - /** page font count */ - private int fontCount = 0; - - /** page orientation */ - private int orientation = 0; - - /** - * 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} */ - public Object clone() { - AFPPageState state = new AFPPageState(); - 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} */ - public String toString() { - return "AFPPageState{width=" + width - + ", height=" + height - + ", orientation=" + orientation - + ", fonts=" + fonts - + ", fontCount=" + fontCount - + "}"; - } - } - - /** - * Block level state data - */ - private class AFPData extends org.apache.fop.AbstractData { - private static final long serialVersionUID = -1789481244175275686L; - - /** The current fill status */ - private boolean filled = false; - - private String imageUri = null; - - /** {@inheritDoc} */ - public Object clone() { - AFPData obj = (AFPData)super.clone(); - obj.filled = this.filled; - obj.imageUri = this.imageUri; - return obj; - } - - /** {@inheritDoc} */ - public String toString() { - return "AFPData{" + super.toString() - + ", filled=" + filled - + ", imageUri=" + imageUri - + "}"; - } - - /** {@inheritDoc} */ - protected AbstractData instantiate() { - return new AFPData(); - } - } - -} \ No newline at end of file diff --git a/src/java/org/apache/fop/afp/AFPStreamer.java b/src/java/org/apache/fop/afp/AFPStreamer.java index 42dcf4412..1d9367ef6 100644 --- a/src/java/org/apache/fop/afp/AFPStreamer.java +++ b/src/java/org/apache/fop/afp/AFPStreamer.java @@ -83,11 +83,11 @@ public class AFPStreamer implements Streamable { /** * Creates a new DataStream - * @param state the afp state * + * @param state the AFP painting state * @return a new {@link DataStream} */ - public DataStream createDataStream(AFPState state) { + public DataStream createDataStream(AFPPaintingState state) { try { this.tempFile = File.createTempFile(AFPDATASTREAM_TEMP_FILE_PREFIX, null); this.documentFile = new RandomAccessFile(tempFile, "rw"); diff --git a/src/java/org/apache/fop/afp/AFPTextHandler.java b/src/java/org/apache/fop/afp/AFPTextHandler.java index 3dee6ca2e..3f5ff7b33 100644 --- a/src/java/org/apache/fop/afp/AFPTextHandler.java +++ b/src/java/org/apache/fop/afp/AFPTextHandler.java @@ -71,7 +71,7 @@ public class AFPTextHandler implements TextHandler { GraphicsObject graphicsObj = g2d.getGraphicsObject(); Color col = g2d.getColor(); - AFPState state = g2d.getState(); + AFPPaintingState state = g2d.getPaintingState(); if (state.setColor(col)) { graphicsObj.setColor(col); } diff --git a/src/java/org/apache/fop/afp/AFPUnitConverter.java b/src/java/org/apache/fop/afp/AFPUnitConverter.java index 69282fc18..c5f37d25f 100644 --- a/src/java/org/apache/fop/afp/AFPUnitConverter.java +++ b/src/java/org/apache/fop/afp/AFPUnitConverter.java @@ -29,14 +29,14 @@ import java.awt.geom.AffineTransform; public class AFPUnitConverter { /** the AFP state */ - private final AFPState state; + private final AFPPaintingState state; /** * Unit converter * - * @param state the AFP state + * @param state the AFP painting state */ - public AFPUnitConverter(AFPState state) { + public AFPUnitConverter(AFPPaintingState state) { this.state = state; } diff --git a/src/java/org/apache/fop/afp/AbstractAFPPainter.java b/src/java/org/apache/fop/afp/AbstractAFPPainter.java index ba6d49fc6..72c6c56e1 100644 --- a/src/java/org/apache/fop/afp/AbstractAFPPainter.java +++ b/src/java/org/apache/fop/afp/AbstractAFPPainter.java @@ -29,7 +29,7 @@ public abstract class AbstractAFPPainter { protected static Log log = LogFactory.getLog("org.apache.xmlgraphics.afp"); protected final DataStream dataStream; - protected final AFPState state; + protected final AFPPaintingState state; /** * Main constructor @@ -37,7 +37,7 @@ public abstract class AbstractAFPPainter { * @param state the afp state * @param dataStream the afp datastream */ - public AbstractAFPPainter(AFPState state, DataStream dataStream) { + public AbstractAFPPainter(AFPPaintingState state, DataStream dataStream) { this.state = state; this.dataStream = dataStream; } diff --git a/src/java/org/apache/fop/afp/Factory.java b/src/java/org/apache/fop/afp/Factory.java index 840d7b4e8..ef7426330 100644 --- a/src/java/org/apache/fop/afp/Factory.java +++ b/src/java/org/apache/fop/afp/Factory.java @@ -392,11 +392,11 @@ public class Factory { /** * Creates a new {@link DataStream} * - * @param state the afp state + * @param state the AFP painting state * @param outputStream an outputstream to write to * @return a new {@link DataStream} */ - public DataStream createDataStream(AFPState state, OutputStream outputStream) { + public DataStream createDataStream(AFPPaintingState state, OutputStream outputStream) { DataStream dataStream = new DataStream(this, state, outputStream); return dataStream; } diff --git a/src/java/org/apache/fop/afp/Graphics2DImagePainterGOCA.java b/src/java/org/apache/fop/afp/Graphics2DImagePainterGOCA.java new file mode 100644 index 000000000..1a2883e72 --- /dev/null +++ b/src/java/org/apache/fop/afp/Graphics2DImagePainterGOCA.java @@ -0,0 +1,71 @@ +/* + * 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.Dimension; +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; + +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.gvt.GraphicsNode; +import org.apache.fop.image.loader.batik.Graphics2DImagePainterImpl; +import org.apache.xmlgraphics.java2d.Graphics2DPainterPreparator; + +/** + * Graphics2DImagePainter implementation for GOCA + */ +public class Graphics2DImagePainterGOCA extends Graphics2DImagePainterImpl { + + /** + * Main Constructor + * + * @param root the graphics node root + * @param ctx the bridge context + * @param imageSize the image size + */ + public Graphics2DImagePainterGOCA(GraphicsNode root, BridgeContext ctx, Dimension imageSize) { + super(root, ctx, imageSize); + } + + /** {@inheritDoc} */ + protected Graphics2DPainterPreparator getPreparator() { + return new Graphics2DPainterPreparator() { + + /** {@inheritdoc} */ + public void prepare(Graphics2D g2d, Rectangle2D area) { + double tx = area.getX(); + double ty = area.getHeight() - area.getY(); + if (tx != 0 || ty != 0) { + g2d.translate(tx, ty); + } + + float iw = (float) ctx.getDocumentSize().getWidth(); + float ih = (float) ctx.getDocumentSize().getHeight(); + float w = (float) area.getWidth(); + float h = (float) area.getHeight(); + float sx = w / iw; + float sy = -(h / ih); + if (sx != 1.0 || sy != 1.0) { + g2d.scale(sx, sy); + } + } + }; + } +} \ No newline at end of file diff --git a/src/java/org/apache/fop/afp/ioca/ImageContent.java b/src/java/org/apache/fop/afp/ioca/ImageContent.java index 27147d511..fc8ce0944 100644 --- a/src/java/org/apache/fop/afp/ioca/ImageContent.java +++ b/src/java/org/apache/fop/afp/ioca/ImageContent.java @@ -25,6 +25,7 @@ import java.io.OutputStream; import org.apache.fop.afp.modca.AbstractStructuredAFPObject; /** + * An IOCA Image Content */ public class ImageContent extends AbstractStructuredAFPObject { diff --git a/src/java/org/apache/fop/afp/modca/DataStream.java b/src/java/org/apache/fop/afp/modca/DataStream.java index c1c5e12a7..00d2b6f16 100644 --- a/src/java/org/apache/fop/afp/modca/DataStream.java +++ b/src/java/org/apache/fop/afp/modca/DataStream.java @@ -29,8 +29,8 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.afp.AFPLineDataInfo; +import org.apache.fop.afp.AFPPaintingState; import org.apache.fop.afp.AFPResourceLevel; -import org.apache.fop.afp.AFPState; import org.apache.fop.afp.AFPTextDataInfo; import org.apache.fop.afp.Factory; import org.apache.fop.afp.fonts.AFPFont; @@ -83,17 +83,17 @@ public class DataStream { private OutputStream outputStream; - /** the afp state */ - private final AFPState state; + /** the afp painting state */ + private final AFPPaintingState state; /** * Default constructor for the AFPDocumentStream. * * @param factory the resource factory - * @param state the afp state + * @param state the AFP painting state * @param outputStream the outputstream to write to */ - public DataStream(Factory factory, AFPState state, OutputStream outputStream) { + public DataStream(Factory factory, AFPPaintingState state, OutputStream outputStream) { this.state = state; this.factory = factory; this.outputStream = outputStream; diff --git a/src/java/org/apache/fop/image/loader/batik/BatikGraphics2DImagePainter.java b/src/java/org/apache/fop/image/loader/batik/BatikGraphics2DImagePainter.java deleted file mode 100644 index 983033027..000000000 --- a/src/java/org/apache/fop/image/loader/batik/BatikGraphics2DImagePainter.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.apache.fop.image.loader.batik; - -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.geom.Rectangle2D; - -import org.apache.batik.bridge.BridgeContext; -import org.apache.batik.gvt.GraphicsNode; -import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; -import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; - -/** - * A generic graphics 2D image painter implementation - */ -public class BatikGraphics2DImagePainter implements Graphics2DImagePainter { - - protected final ImageXMLDOM svg; - protected final BridgeContext ctx; - protected final GraphicsNode root; - - /** - * Constructor - * - * @param svg the svg image dom - * @param ctx the bridge context - * @param root the graphics node root - */ - public BatikGraphics2DImagePainter(ImageXMLDOM svg, BridgeContext ctx, GraphicsNode root) { - this.svg = svg; - this.ctx = ctx; - this.root = root; - } - - /** - * Initialises the graphics 2d - * - * @param g2d the graphics 2d - * @param area the rectangle drawing area - */ - protected void init(Graphics2D g2d, Rectangle2D area) { - // If no viewbox is defined in the svg file, a viewbox of 100x100 is - // assumed, as defined in SVGUserAgent.getViewportSize() - double tx = area.getX(); - double ty = area.getY(); - if (tx != 0 || ty != 0) { - g2d.translate(tx, ty); - } - - float iw = (float) ctx.getDocumentSize().getWidth(); - float ih = (float) ctx.getDocumentSize().getHeight(); - float w = (float) area.getWidth(); - float h = (float) area.getHeight(); - float sx = w / iw; - float sy = h / ih; - if (sx != 1.0 || sy != 1.0) { - g2d.scale(sx, sy); - } - } - - /** {@inheritDoc} */ - public void paint(Graphics2D g2d, Rectangle2D area) { - init(g2d, area); - root.paint(g2d); - } - - /** {@inheritDoc} */ - public Dimension getImageSize() { - return new Dimension(svg.getSize().getWidthMpt(), svg.getSize().getHeightMpt()); - } - - /** - * Returns the svg image dom - * @return the svg image dom - */ - public ImageXMLDOM getImageXMLDOM() { - return svg; - } - - /** - * Returns the bridge context - * @return the bridge context - */ - public BridgeContext getBridgeContext() { - return ctx; - } - - /** - * Returns the graphics root node - * @return the graphics root node - */ - public GraphicsNode getRoot() { - return root; - } - -} \ No newline at end of file diff --git a/src/java/org/apache/fop/image/loader/batik/Graphics2DImagePainterImpl.java b/src/java/org/apache/fop/image/loader/batik/Graphics2DImagePainterImpl.java new file mode 100644 index 000000000..87907eddf --- /dev/null +++ b/src/java/org/apache/fop/image/loader/batik/Graphics2DImagePainterImpl.java @@ -0,0 +1,64 @@ +package org.apache.fop.image.loader.batik; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; + +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.gvt.GraphicsNode; +import org.apache.fop.render.AbstractGraphics2DImagePainter; +import org.apache.xmlgraphics.java2d.Graphics2DPainterPreparator; + +/** + * A generic graphics 2D image painter implementation + */ +public class Graphics2DImagePainterImpl extends AbstractGraphics2DImagePainter { + + protected final BridgeContext ctx; + protected final Dimension imageSize; + + /** + * Main constructor + * + * @param root the graphics node root + * @param ctx the bridge context + * @param imageSize the image size + */ + public Graphics2DImagePainterImpl(GraphicsNode root, BridgeContext ctx, Dimension imageSize) { + super(root); + this.imageSize = imageSize; + this.ctx = ctx; + } + + /** {@inheritDoc} */ + public Dimension getImageSize() { + return imageSize; + } + + /** {@inheritDoc} */ + protected Graphics2DPainterPreparator getPreparator() { + return new Graphics2DPainterPreparator() { + + public void prepare(Graphics2D g2d, Rectangle2D area) { + // If no viewbox is defined in the svg file, a viewbox of 100x100 is + // assumed, as defined in SVGUserAgent.getViewportSize() + double tx = area.getX(); + double ty = area.getY(); + if (tx != 0 || ty != 0) { + g2d.translate(tx, ty); + } + + float iw = (float) ctx.getDocumentSize().getWidth(); + float ih = (float) ctx.getDocumentSize().getHeight(); + float w = (float) area.getWidth(); + float h = (float) area.getHeight(); + float sx = w / iw; + float sy = h / ih; + if (sx != 1.0 || sy != 1.0) { + g2d.scale(sx, sy); + } + } + }; + } + +} \ No newline at end of file diff --git a/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java b/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java index 40dc600be..81c12a628 100644 --- a/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java +++ b/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java @@ -19,6 +19,7 @@ package org.apache.fop.image.loader.batik; +import java.awt.Dimension; import java.awt.geom.AffineTransform; import java.util.Map; @@ -33,6 +34,7 @@ import org.apache.fop.svg.SimpleSVGUserAgent; import org.apache.xmlgraphics.image.loader.Image; import org.apache.xmlgraphics.image.loader.ImageException; import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.ImageInfo; import org.apache.xmlgraphics.image.loader.ImageProcessingHints; import org.apache.xmlgraphics.image.loader.XMLNamespaceEnabledImageFlavor; import org.apache.xmlgraphics.image.loader.impl.AbstractImageConverter; @@ -82,8 +84,14 @@ public class ImageConverterSVG2G2D extends AbstractImageConverter { } //Create the painter - Graphics2DImagePainter painter = createPainter(svg, ctx, root); - ImageGraphics2D g2dImage = new ImageGraphics2D(src.getInfo(), painter); + int width = svg.getSize().getWidthMpt(); + int height = svg.getSize().getHeightMpt(); + Dimension imageSize = new Dimension(width, height); + Graphics2DImagePainter painter = createPainter(ctx, root, imageSize); + + //Create g2d image + ImageInfo imageInfo = src.getInfo(); + ImageGraphics2D g2dImage = new ImageGraphics2D(imageInfo, painter); return g2dImage; } @@ -109,14 +117,14 @@ public class ImageConverterSVG2G2D extends AbstractImageConverter { /** * Creates a Graphics 2D image painter * - * @param svg the svg image dom * @param ctx the bridge context * @param root the graphics node root + * @param imageSize the image size * @return the newly created graphics 2d image painter */ protected Graphics2DImagePainter createPainter( - final ImageXMLDOM svg, final BridgeContext ctx, final GraphicsNode root) { - return new BatikGraphics2DImagePainter(svg, ctx, root); + BridgeContext ctx, GraphicsNode root, Dimension imageSize) { + return new Graphics2DImagePainterImpl(root, ctx, imageSize); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/pdf/PDFPaintingState.java b/src/java/org/apache/fop/pdf/PDFPaintingState.java new file mode 100644 index 000000000..7dd876c25 --- /dev/null +++ b/src/java/org/apache/fop/pdf/PDFPaintingState.java @@ -0,0 +1,229 @@ +/* + * 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.pdf; + +import java.awt.Paint; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.geom.GeneralPath; +import java.util.Iterator; + +import org.apache.fop.util.AbstractPaintingState; + +/** + * This keeps information about the current painting state when writing to pdf. + * It allows for creating new graphics states with the q operator. + * This class is only used to store the information about the state + * the caller needs to handle the actual pdf operators. + * + * When setting the state for pdf there are three possible ways of + * handling the situation. + * The values can be set to override previous or default values. + * A new state can be added and then the values set. + * The current state can be popped and values will return to a + * previous state then the necessary values can be overridden. + * The current transform behaves differently to other values as the + * matrix is combined with the current resolved value. + * It is impossible to optimise the result without analysing the all + * the possible combinations after completing. + */ +public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState { + + private static final long serialVersionUID = 5384726143906371279L; + + /** + * PDF State for storing graphics state. + */ + public PDFPaintingState() { + } + + /** + * Set the current paint. + * This checks if the paint will change and then sets the current paint. + * + * @param p the new paint + * @return true if the new paint changes the current paint + */ + public boolean setPaint(Paint p) { + Paint paint = ((PDFData)getData()).paint; + if (paint == null) { + if (p != null) { + ((PDFData)getData()).paint = p; + return true; + } + } else if (!paint.equals(p)) { + ((PDFData)getData()).paint = p; + return true; + } + return false; + } + + /** + * Check if the clip will change the current state. + * A clip is assumed to be used in a situation where it will add + * to any clip in the current or parent states. + * A clip cannot be cleared, this can only be achieved by going to + * a parent level with the correct clip. + * If the clip is different then it may start a new state so that + * it can return to the previous clip. + * + * @param cl the clip shape to check + * @return true if the clip will change the current clip. + */ + public boolean checkClip(Shape cl) { + Shape clip = ((PDFData)getData()).clip; + if (clip == null) { + if (cl != null) { + return true; + } + } else if (!new Area(clip).equals(new Area(cl))) { + return true; + } + //TODO check for clips that are larger than the current + return false; + } + + /** + * Set the current clip. + * This either sets a new clip or sets the clip to the intersect of + * the old clip and the new clip. + * + * @param cl the new clip in the current state + */ + public void setClip(Shape cl) { + Shape clip = ((PDFData)getData()).clip; + if (clip != null) { + Area newClip = new Area(clip); + newClip.intersect(new Area(cl)); + ((PDFData)getData()).clip = new GeneralPath(newClip); + } else { + ((PDFData)getData()).clip = cl; + } + } + + /** + * Get the current stack level. + * + * @return the current stack level + */ + public int getStackLevel() { + return getStateStack().size(); + } + + /** + * Get the graphics state. + * This gets the combination of all graphic states for + * the current context. + * This is the graphic state set with the gs operator not + * the other graphic state changes. + * + * @return the calculated ExtGState in the current context + */ + public PDFGState getGState() { + PDFGState defaultState = PDFGState.DEFAULT; + + PDFGState state; + PDFGState newState = new PDFGState(); + newState.addValues(defaultState); + for (Iterator it = getStateStack().iterator(); it.hasNext();) { + PDFData data = (PDFData)it.next(); + state = data.gstate; + if (state != null) { + newState.addValues(state); + } + } + if (((PDFData)getData()).gstate != null) { + newState.addValues(((PDFData)getData()).gstate); + } + return newState; + } + + /** {@inheritDoc} */ + protected AbstractData instantiateData() { + return new PDFData(); + } + + /** {@inheritDoc} */ + protected AbstractPaintingState instantiate() { + return new PDFPaintingState(); + } + + /** + * Push the current state onto the stack. + * This call should be used when the q operator is used + * so that the state is known when popped. + */ + public void push() { + AbstractData data = getData(); + AbstractData copy = (AbstractData)data.clone(); + data.clearTransform(); + getStateStack().add(copy); + } + + private class PDFData extends org.apache.fop.util.AbstractPaintingState.AbstractData { + + private static final long serialVersionUID = 3527950647293177764L; + + private Paint paint = null; + private Paint backPaint = null; + private int lineCap = 0; + private int lineJoin = 0; + private float miterLimit = 0; + private boolean text = false; + private int dashOffset = 0; + private Shape clip = null; + private PDFGState gstate = null; + + /** {@inheritDoc} */ + public Object clone() { + PDFData obj = (PDFData)super.clone(); + obj.paint = this.paint; + obj.backPaint = this.paint; + obj.lineCap = this.lineCap; + obj.lineJoin = this.lineJoin; + obj.miterLimit = this.miterLimit; + obj.text = this.text; + obj.dashOffset = this.dashOffset; + obj.clip = this.clip; + obj.gstate = this.gstate; + return obj; + } + + /** {@inheritDoc} */ + public String toString() { + return super.toString() + + ", paint=" + paint + + ", backPaint=" + backPaint + + ", lineCap=" + lineCap + + ", miterLimit=" + miterLimit + + ", text=" + text + + ", dashOffset=" + dashOffset + + ", clip=" + clip + + ", gstate=" + gstate; + } + + /** {@inheritDoc} */ + protected AbstractData instantiate() { + return new PDFData(); + } + } + +} + diff --git a/src/java/org/apache/fop/pdf/PDFState.java b/src/java/org/apache/fop/pdf/PDFState.java deleted file mode 100644 index 3804c189a..000000000 --- a/src/java/org/apache/fop/pdf/PDFState.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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.pdf; - -import java.awt.Paint; -import java.awt.Shape; -import java.awt.geom.Area; -import java.awt.geom.GeneralPath; -import java.util.Iterator; - -import org.apache.fop.AbstractData; -import org.apache.fop.AbstractState; - -/** - * This keeps information about the current state when writing to pdf. - * It allows for creating new graphics states with the q operator. - * This class is only used to store the information about the state - * the caller needs to handle the actual pdf operators. - * - * When setting the state for pdf there are three possible ways of - * handling the situation. - * The values can be set to override previous or default values. - * A new state can be added and then the values set. - * The current state can be popped and values will return to a - * previous state then the necessary values can be overridden. - * The current transform behaves differently to other values as the - * matrix is combined with the current resolved value. - * It is impossible to optimise the result without analysing the all - * the possible combinations after completing. - */ -public class PDFState extends org.apache.fop.AbstractState { - - private static final long serialVersionUID = 5384726143906371279L; - - /** - * PDF State for storing graphics state. - */ - public PDFState() { - } - - /** - * Set the current paint. - * This checks if the paint will change and then sets the current paint. - * - * @param p the new paint - * @return true if the new paint changes the current paint - */ - public boolean setPaint(Paint p) { - Paint paint = ((PDFData)getData()).paint; - if (paint == null) { - if (p != null) { - ((PDFData)getData()).paint = p; - return true; - } - } else if (!paint.equals(p)) { - ((PDFData)getData()).paint = p; - return true; - } - return false; - } - - /** - * Check if the clip will change the current state. - * A clip is assumed to be used in a situation where it will add - * to any clip in the current or parent states. - * A clip cannot be cleared, this can only be achieved by going to - * a parent level with the correct clip. - * If the clip is different then it may start a new state so that - * it can return to the previous clip. - * - * @param cl the clip shape to check - * @return true if the clip will change the current clip. - */ - public boolean checkClip(Shape cl) { - Shape clip = ((PDFData)getData()).clip; - if (clip == null) { - if (cl != null) { - return true; - } - } else if (!new Area(clip).equals(new Area(cl))) { - return true; - } - //TODO check for clips that are larger than the current - return false; - } - - /** - * Set the current clip. - * This either sets a new clip or sets the clip to the intersect of - * the old clip and the new clip. - * - * @param cl the new clip in the current state - */ - public void setClip(Shape cl) { - Shape clip = ((PDFData)getData()).clip; - if (clip != null) { - Area newClip = new Area(clip); - newClip.intersect(new Area(cl)); - ((PDFData)getData()).clip = new GeneralPath(newClip); - } else { - ((PDFData)getData()).clip = cl; - } - } - - /** - * Get the current stack level. - * - * @return the current stack level - */ - public int getStackLevel() { - return getStateStack().size(); - } - - /** - * Get the graphics state. - * This gets the combination of all graphic states for - * the current context. - * This is the graphic state set with the gs operator not - * the other graphic state changes. - * - * @return the calculated ExtGState in the current context - */ - public PDFGState getGState() { - PDFGState defaultState = PDFGState.DEFAULT; - - PDFGState state; - PDFGState newState = new PDFGState(); - newState.addValues(defaultState); - for (Iterator it = getStateStack().iterator(); it.hasNext();) { - PDFData data = (PDFData)it.next(); - state = data.gstate; - if (state != null) { - newState.addValues(state); - } - } - if (((PDFData)getData()).gstate != null) { - newState.addValues(((PDFData)getData()).gstate); - } - return newState; - } - - /** {@inheritDoc} */ - protected AbstractData instantiateData() { - return new PDFData(); - } - - /** {@inheritDoc} */ - protected AbstractState instantiateState() { - return new PDFState(); - } - - /** - * Push the current state onto the stack. - * This call should be used when the q operator is used - * so that the state is known when popped. - */ - public void push() { - AbstractData data = getData(); - AbstractData copy = (AbstractData)data.clone(); - data.clearTransform(); - getStateStack().add(copy); - } - - private class PDFData extends org.apache.fop.AbstractData { - - private static final long serialVersionUID = 3527950647293177764L; - - private Paint paint = null; - private Paint backPaint = null; - private int lineCap = 0; - private int lineJoin = 0; - private float miterLimit = 0; - private boolean text = false; - private int dashOffset = 0; - private Shape clip = null; - private PDFGState gstate = null; - - /** {@inheritDoc} */ - public Object clone() { - PDFData obj = (PDFData)super.clone(); - obj.paint = this.paint; - obj.backPaint = this.paint; - obj.lineCap = this.lineCap; - obj.lineJoin = this.lineJoin; - obj.miterLimit = this.miterLimit; - obj.text = this.text; - obj.dashOffset = this.dashOffset; - obj.clip = this.clip; - obj.gstate = this.gstate; - return obj; - } - - /** {@inheritDoc} */ - public String toString() { - return super.toString() - + ", paint=" + paint - + ", backPaint=" + backPaint - + ", lineCap=" + lineCap - + ", miterLimit=" + miterLimit - + ", text=" + text - + ", dashOffset=" + dashOffset - + ", clip=" + clip - + ", gstate=" + gstate; - } - - /** {@inheritDoc} */ - protected AbstractData instantiate() { - return new PDFData(); - } - } - -} - diff --git a/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java b/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java index 0d6bf9be9..18cc81400 100644 --- a/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java +++ b/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java @@ -21,9 +21,7 @@ package org.apache.fop.render; // Java import java.awt.Dimension; -import java.awt.Graphics2D; import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; import java.io.IOException; import org.apache.batik.bridge.BridgeContext; @@ -31,7 +29,9 @@ import org.apache.batik.bridge.GVTBuilder; import org.apache.batik.dom.AbstractDocument; import org.apache.batik.dom.svg.SVGDOMImplementation; import org.apache.batik.gvt.GraphicsNode; +import org.apache.fop.events.EventBroadcaster; import org.apache.fop.fo.extensions.ExtensionElementMapping; +import org.apache.fop.image.loader.batik.Graphics2DImagePainterImpl; import org.apache.fop.render.RendererContext.RendererContextWrapper; import org.apache.fop.svg.SVGEventProducer; import org.apache.fop.svg.SVGUserAgent; @@ -51,6 +51,9 @@ public abstract class AbstractGenericSVGHandler implements XMLHandler, RendererC protected static final QName CONVERSION_MODE = new QName( ExtensionElementMapping.URI, null, "conversion-mode"); + /** "bitmap" value for the "conversion-mode" extension attribute. */ + protected static final String BITMAP = "bitmap"; + /** {@inheritDoc} */ public void handleXML(RendererContext context, Document doc, String ns) throws Exception { @@ -61,65 +64,80 @@ public abstract class AbstractGenericSVGHandler implements XMLHandler, RendererC } /** - * Render the SVG document. + * Creates a graphics 2D image painter implementation * - * @param context the renderer context - * @param doc the SVG document - * @throws IOException In case of an I/O error while painting the image + * @param root the batik graphics node root + * @param ctx the batik bridge context + * @param imageSize the image size + * @return a new graphics 2D image painter implementation */ - protected void renderSVGDocument(final RendererContext context, - final Document doc) throws IOException { - updateRendererContext(context); + protected Graphics2DImagePainter createPainter( + GraphicsNode root, BridgeContext ctx, Dimension imageSize) { + return new Graphics2DImagePainterImpl(root, ctx, imageSize); + } - //Prepare - SVGUserAgent ua = new SVGUserAgent( - context.getUserAgent(), - new AffineTransform()); + /** + * Builds the GVT root + * + * @param rendererContext the renderer context + * @param ctx the batik bridge context + * @param doc the document + * @return a built GVT root tree + */ + protected GraphicsNode buildGraphicsNode( + RendererContext rendererContext, BridgeContext ctx, Document doc) { GVTBuilder builder = new GVTBuilder(); - final BridgeContext ctx = new BridgeContext(ua); - - //Build the GVT tree final GraphicsNode root; try { root = builder.build(ctx, doc); } catch (Exception e) { - SVGEventProducer eventProducer = SVGEventProducer.Provider.get( - context.getUserAgent().getEventBroadcaster()); + EventBroadcaster eventBroadcaster + = rendererContext.getUserAgent().getEventBroadcaster(); + SVGEventProducer eventProducer = SVGEventProducer.Provider.get(eventBroadcaster); final String uri = getDocumentURI(doc); eventProducer.svgNotBuilt(this, e, uri); - return; + return null; } + return root; + } - final RendererContextWrapper wrappedContext = RendererContext.wrapRendererContext(context); + /** + * Render the SVG document. + * + * @param rendererContext the renderer context + * @param doc the SVG document + * @throws IOException In case of an I/O error while painting the image + */ + protected void renderSVGDocument(final RendererContext rendererContext, + final Document doc) throws IOException { + updateRendererContext(rendererContext); - //Create the painter - Graphics2DImagePainter painter = new Graphics2DImagePainter() { + //Prepare + SVGUserAgent svgUserAgent = new SVGUserAgent( + rendererContext.getUserAgent(), new AffineTransform()); + final BridgeContext bridgeContext = new BridgeContext(svgUserAgent); - public void paint(Graphics2D g2d, Rectangle2D area) { - // If no viewbox is defined in the svg file, a viewbox of 100x100 is - // assumed, as defined in SVGUserAgent.getViewportSize() - float iw = (float) ctx.getDocumentSize().getWidth(); - float ih = (float) ctx.getDocumentSize().getHeight(); - float w = (float) area.getWidth(); - float h = (float) area.getHeight(); - g2d.scale(w / iw, h / ih); + //Build the GVT tree + final GraphicsNode root = buildGraphicsNode(rendererContext, bridgeContext, doc); - root.paint(g2d); - } + final RendererContextWrapper wrappedContext = RendererContext.wrapRendererContext( + rendererContext); - public Dimension getImageSize() { - return new Dimension(wrappedContext.getWidth(), wrappedContext.getHeight()); - } + //Get Image Size + final int width = wrappedContext.getWidth(); + final int height = wrappedContext.getHeight(); + Dimension imageSize = new Dimension(width, height); - }; + //Create the painter + final Graphics2DImagePainter painter = createPainter(root, bridgeContext, imageSize); //Let the painter paint the SVG on the Graphics2D instance - Graphics2DAdapter adapter = context.getRenderer().getGraphics2DAdapter(); - adapter.paintImage(painter, context, - wrappedContext.getCurrentXPosition(), - wrappedContext.getCurrentYPosition(), - wrappedContext.getWidth(), - wrappedContext.getHeight()); + Graphics2DAdapter g2dAdapter = rendererContext.getRenderer().getGraphics2DAdapter(); + + //Paint the image + final int x = wrappedContext.getCurrentXPosition(); + final int y = wrappedContext.getCurrentYPosition(); + g2dAdapter.paintImage(painter, rendererContext, x, y, width, height); } /** diff --git a/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java b/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java index e37d02b2b..5861fb042 100644 --- a/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java +++ b/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java @@ -135,6 +135,7 @@ public abstract class AbstractGraphics2DAdapter implements Graphics2DAdapter { g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); } + /** {@inheritDoc} */ public void paintImage(Graphics2DImagePainter painter, RendererContext context, diff --git a/src/java/org/apache/fop/render/afp/AFPAbstractImageFactory.java b/src/java/org/apache/fop/render/afp/AFPAbstractImageFactory.java index 0c32204e2..3b00804fc 100644 --- a/src/java/org/apache/fop/render/afp/AFPAbstractImageFactory.java +++ b/src/java/org/apache/fop/render/afp/AFPAbstractImageFactory.java @@ -24,8 +24,8 @@ import java.io.IOException; import org.apache.fop.afp.AFPDataObjectInfo; import org.apache.fop.afp.AFPForeignAttributeReader; import org.apache.fop.afp.AFPObjectAreaInfo; +import org.apache.fop.afp.AFPPaintingState; import org.apache.fop.afp.AFPResourceInfo; -import org.apache.fop.afp.AFPState; import org.apache.fop.afp.AFPUnitConverter; @@ -37,7 +37,7 @@ public abstract class AFPAbstractImageFactory { private static final int Y = 1; /** the AFP state */ - protected final AFPState state; + protected final AFPPaintingState state; /** foreign attribute reader */ private final AFPForeignAttributeReader foreignAttributeReader @@ -46,9 +46,9 @@ public abstract class AFPAbstractImageFactory { /** * Main constructor * - * @param state the AFP state + * @param state the AFP painting state */ - public AFPAbstractImageFactory(AFPState state) { + public AFPAbstractImageFactory(AFPPaintingState state) { this.state = state; } diff --git a/src/java/org/apache/fop/render/afp/AFPBatikGraphicsObjectPainter.java b/src/java/org/apache/fop/render/afp/AFPBatikGraphicsObjectPainter.java deleted file mode 100644 index 0aa77d61b..000000000 --- a/src/java/org/apache/fop/render/afp/AFPBatikGraphicsObjectPainter.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.render.afp; - -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.geom.Rectangle2D; - -import org.apache.batik.gvt.GraphicsNode; -import org.apache.fop.afp.AFPAbstractGraphicsObjectPainter; -import org.apache.fop.afp.AFPGraphics2D; - -/** - * Paints SVG as a GOCA Graphics Object using Batik - */ -public class AFPBatikGraphicsObjectPainter extends AFPAbstractGraphicsObjectPainter { - - /** the batik root node of the svg document */ - private GraphicsNode root; - - /** - * Main constructor - * - * @param graphics an AFP graphics 2D implementation - */ - public AFPBatikGraphicsObjectPainter(AFPGraphics2D graphics) { - super(graphics); - } - - /** - * Sets the graphics node - * - * @param rootNode the graphics root node - */ - public void setGraphicsNode(GraphicsNode rootNode) { - this.root = rootNode; - } - - /** {@inheritDoc} */ - public void paint(Graphics2D g2d, Rectangle2D area) { - log.debug("Painting SVG using GOCA"); - - // tell batik to paint the graphics object - root.paint(g2d); - - // dispose of the graphics 2d implementation - g2d.dispose(); - } - - /** {@inheritDoc} */ - public Dimension getImageSize() { - return null; - } - -} diff --git a/src/java/org/apache/fop/render/afp/AFPDataObjectInfoFactory.java b/src/java/org/apache/fop/render/afp/AFPDataObjectInfoFactory.java index dcf074262..ba2392835 100644 --- a/src/java/org/apache/fop/render/afp/AFPDataObjectInfoFactory.java +++ b/src/java/org/apache/fop/render/afp/AFPDataObjectInfoFactory.java @@ -26,8 +26,8 @@ import java.io.IOException; import org.apache.fop.afp.AFPDataObjectInfo; import org.apache.fop.afp.AFPForeignAttributeReader; import org.apache.fop.afp.AFPObjectAreaInfo; +import org.apache.fop.afp.AFPPaintingState; import org.apache.fop.afp.AFPResourceInfo; -import org.apache.fop.afp.AFPState; import org.apache.fop.afp.AFPUnitConverter; @@ -38,8 +38,8 @@ public abstract class AFPDataObjectInfoFactory { private static final int X = 0; private static final int Y = 1; - /** the AFP state */ - protected final AFPState state; + /** the AFP painting state */ + protected final AFPPaintingState state; /** foreign attribute reader */ private final AFPForeignAttributeReader foreignAttributeReader @@ -50,7 +50,7 @@ public abstract class AFPDataObjectInfoFactory { * * @param state the AFP state */ - public AFPDataObjectInfoFactory(AFPState state) { + public AFPDataObjectInfoFactory(AFPPaintingState state) { this.state = state; } diff --git a/src/java/org/apache/fop/render/afp/AFPDataObjectInfoProvider.java b/src/java/org/apache/fop/render/afp/AFPDataObjectInfoProvider.java index 4211fe360..aac17b701 100644 --- a/src/java/org/apache/fop/render/afp/AFPDataObjectInfoProvider.java +++ b/src/java/org/apache/fop/render/afp/AFPDataObjectInfoProvider.java @@ -22,7 +22,7 @@ package org.apache.fop.render.afp; import java.util.Iterator; import java.util.Map; -import org.apache.fop.afp.AFPState; +import org.apache.fop.afp.AFPPaintingState; import org.apache.xmlgraphics.image.loader.Image; import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; @@ -33,16 +33,18 @@ import org.apache.xmlgraphics.image.loader.impl.ImageRendered; * AFP data object info factory provider */ public class AFPDataObjectInfoProvider { + private final Map/**/ factoryMap = new java.util.HashMap/**/(); - private final AFPState state; + + private final AFPPaintingState state; /** * Main constructor * - * @param state the AFP state + * @param state the AFP painting state */ - public AFPDataObjectInfoProvider(AFPState state) { + public AFPDataObjectInfoProvider(AFPPaintingState state) { this.state = state; init(); } diff --git a/src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java b/src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java index 453e16429..4f92826cf 100644 --- a/src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java +++ b/src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java @@ -27,8 +27,9 @@ import java.io.IOException; import org.apache.fop.afp.AFPGraphics2D; import org.apache.fop.afp.AFPGraphicsObjectInfo; +import org.apache.fop.afp.AFPPaintingState; +import org.apache.fop.afp.AFPResourceInfo; import org.apache.fop.afp.AFPResourceManager; -import org.apache.fop.afp.AFPState; import org.apache.fop.render.AbstractGraphics2DAdapter; import org.apache.fop.render.RendererContext; import org.apache.fop.render.RendererContext.RendererContextWrapper; @@ -69,28 +70,32 @@ public class AFPGraphics2DAdapter extends AbstractGraphics2DAdapter { RendererContext context, int x, int y, int width, int height) throws IOException { - // get the 'width' and 'height' attributes of the SVG document - Dimension dim = painter.getImageSize(); + AFPInfo afpInfo = AFPSVGHandler.getAFPInfo(context); + // set resource manager + AFPResourceManager resourceManager = afpInfo.getResourceManager(); + g2d.setResourceManager(resourceManager); - AFPInfo afpInfo = AFPSVGHandler.getAFPInfo(context); - g2d.setResourceManager(afpInfo.getResourceManager()); - g2d.setResourceInfo(afpInfo.getResourceInfo()); - g2d.setState(afpInfo.getState()); - g2d.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext()); + // set resource information + AFPResourceInfo resourceInfo = afpInfo.getResourceInfo(); + g2d.setResourceInfo(resourceInfo); + + // set painting state + AFPPaintingState paintingState = afpInfo.getPaintingState(); + g2d.setPaintingState(paintingState); -// // scale/convert to afp units -// AFPUnitConverter unitConv = state.getUnitConverter(); -// float scale = unitConv.mpt2units(1); + // set graphic context + g2d.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext()); float fwidth = width / 1000f; float fheight = height / 1000f; - float imw = (float)dim.getWidth() / 1000f; - float imh = (float)dim.getHeight() / 1000f; + + // get the 'width' and 'height' attributes of the SVG document + Dimension imageSize = painter.getImageSize(); + float imw = (float)imageSize.getWidth() / 1000f; + float imh = (float)imageSize.getHeight() / 1000f; float sx = fwidth / imw; float sy = fheight / imh; -// float fx = x / 1000f; -// float fy = y / 1000f; AffineTransform at = new AffineTransform(sx, 0, 0, sy, x, y); renderer.saveGraphicsState(); @@ -99,26 +104,21 @@ public class AFPGraphics2DAdapter extends AbstractGraphics2DAdapter { //Fallback solution: Paint to a BufferedImage int resolution = Math.round(context.getUserAgent().getTargetResolution()); RendererContextWrapper ctx = RendererContext.wrapRendererContext(context); - BufferedImage bi = paintToBufferedImage(painter, ctx, resolution, false, false); + BufferedImage bufferedImage = paintToBufferedImage(painter, ctx, resolution, false, false); - AFPState state = afpInfo.getState(); + AFPPaintingState state = afpInfo.getPaintingState(); AffineTransform trans = state.getData().getTransform(); float scale = AFPRenderer.NORMAL_AFP_RESOLUTION / context.getUserAgent().getTargetResolution(); if (scale != 1) { at.scale(scale, scale); - if (!at.isIdentity()) { - trans.concatenate(at); - } } + if (!at.isIdentity()) { + trans.concatenate(at); + } - // concatenate to transformation matrix -// state.concatenate(at); - - // draw image using current transformation matrix -// at = state.getData().getTransform(); - g2d.drawImage(bi, trans, null); + g2d.drawImage(bufferedImage, trans, null); } else { AFPGraphicsObjectInfo graphicsObjectInfo = new AFPGraphicsObjectInfo(); graphicsObjectInfo.setPainter(painter); @@ -126,8 +126,6 @@ public class AFPGraphics2DAdapter extends AbstractGraphics2DAdapter { Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh); graphicsObjectInfo.setArea(area); - AFPResourceManager resourceManager = (AFPResourceManager)context.getProperty( - AFPRendererContextConstants.AFP_RESOURCE_MANAGER); resourceManager.createObject(graphicsObjectInfo); } diff --git a/src/java/org/apache/fop/render/afp/AFPImageGraphics2DFactory.java b/src/java/org/apache/fop/render/afp/AFPImageGraphics2DFactory.java index da9a37b76..88c0b5c26 100644 --- a/src/java/org/apache/fop/render/afp/AFPImageGraphics2DFactory.java +++ b/src/java/org/apache/fop/render/afp/AFPImageGraphics2DFactory.java @@ -19,10 +19,8 @@ package org.apache.fop.render.afp; -import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; import java.io.IOException; import org.apache.batik.bridge.BridgeContext; @@ -30,16 +28,16 @@ import org.apache.fop.afp.AFPDataObjectInfo; import org.apache.fop.afp.AFPGraphics2D; import org.apache.fop.afp.AFPGraphicsObjectInfo; import org.apache.fop.afp.AFPObjectAreaInfo; +import org.apache.fop.afp.AFPPaintingState; import org.apache.fop.afp.AFPResourceInfo; import org.apache.fop.afp.AFPResourceLevel; -import org.apache.fop.afp.AFPState; import org.apache.fop.afp.AFPTextElementBridge; import org.apache.fop.afp.AFPTextHandler; import org.apache.fop.afp.AFPTextPainter; -import org.apache.fop.image.loader.batik.BatikGraphics2DImagePainter; import org.apache.fop.render.RendererContext; import org.apache.fop.svg.SVGUserAgent; import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; +import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; import org.apache.xmlgraphics.util.MimeConstants; @@ -51,9 +49,9 @@ public class AFPImageGraphics2DFactory extends AFPDataObjectInfoFactory { /** * Main constructor * - * @param state the afp state + * @param state the AFP painting state */ - public AFPImageGraphics2DFactory(AFPState state) { + public AFPImageGraphics2DFactory(AFPPaintingState state) { super(state); } @@ -62,8 +60,6 @@ public class AFPImageGraphics2DFactory extends AFPDataObjectInfoFactory { return new AFPGraphicsObjectInfo(); } - private static final AFPResourceLevel inlineResourceLevel = new AFPResourceLevel(AFPResourceLevel.INLINE); - /** {@inheritDoc} */ public AFPDataObjectInfo create(AFPRendererImageInfo rendererImageInfo) throws IOException { AFPGraphicsObjectInfo graphicsObjectInfo @@ -73,7 +69,7 @@ public class AFPImageGraphics2DFactory extends AFPDataObjectInfoFactory { // level not explicitly set/changed so default to inline for GOCA graphic objects // (due to a bug in the IBM AFP Workbench Viewer (2.04.01.07) - hard copy works just fine) if (!resourceInfo.levelChanged()) { - resourceInfo.setLevel(inlineResourceLevel); + resourceInfo.setLevel(new AFPResourceLevel(AFPResourceLevel.INLINE)); } // set mime type (unsupported by MOD:CA registry) @@ -89,7 +85,7 @@ public class AFPImageGraphics2DFactory extends AFPDataObjectInfoFactory { AFPInfo afpInfo = AFPSVGHandler.getAFPInfo(rendererContext); g2d.setResourceManager(afpInfo.getResourceManager()); g2d.setResourceInfo(afpInfo.getResourceInfo()); - g2d.setState(afpInfo.getState()); + g2d.setPaintingState(afpInfo.getPaintingState()); g2d.setFontInfo(afpInfo.getFontInfo()); // set to default graphic context @@ -100,7 +96,7 @@ public class AFPImageGraphics2DFactory extends AFPDataObjectInfoFactory { g2d.translate(at.getTranslateX(), at.getTranslateY()); // set afp state - g2d.setState(state); + g2d.setPaintingState(state); // controls whether text painted by Batik is generated using text or path operations SVGUserAgent svgUserAgent @@ -117,49 +113,23 @@ public class AFPImageGraphics2DFactory extends AFPDataObjectInfoFactory { // set painter ImageGraphics2D imageG2D = (ImageGraphics2D)rendererImageInfo.getImage(); - BatikGraphics2DImagePainter painter - = (BatikGraphics2DImagePainter)imageG2D.getGraphics2DImagePainter(); - painter = new AFPGraphics2DImagePainter(painter); - imageG2D.setGraphics2DImagePainter(painter); + Graphics2DImagePainter painter = imageG2D.getGraphics2DImagePainter(); graphicsObjectInfo.setPainter(painter); // set object area AFPObjectAreaInfo objectAreaInfo = graphicsObjectInfo.getObjectAreaInfo(); - Rectangle area = new Rectangle(objectAreaInfo.getWidth(), objectAreaInfo.getHeight()); + int width = objectAreaInfo.getWidth(); + int height = objectAreaInfo.getHeight(); + Rectangle area = new Rectangle(width, height); graphicsObjectInfo.setArea(area); - return graphicsObjectInfo; - } - - private class AFPGraphics2DImagePainter extends BatikGraphics2DImagePainter { - /** - * Copy constructor - * - * @param painter a graphics 2D image painter - */ - public AFPGraphics2DImagePainter(BatikGraphics2DImagePainter painter) { - super(painter.getImageXMLDOM(), painter.getBridgeContext(), painter.getRoot()); - } - - /** {@inheritDoc} */ - protected void init(Graphics2D g2d, Rectangle2D area) { - double tx = area.getX(); - double ty = area.getHeight() - area.getY(); - if (tx != 0 || ty != 0) { - g2d.translate(tx, ty); - } - - float iw = (float) ctx.getDocumentSize().getWidth(); - float ih = (float) ctx.getDocumentSize().getHeight(); - float w = (float) area.getWidth(); - float h = (float) area.getHeight(); - float sx = w / iw; - float sy = -(h / ih); - if (sx != 1.0 || sy != 1.0) { - g2d.scale(sx, sy); - } - } + // invert y-axis for GOCA + final int sx = 1; + final int sy = -1; + g2d.translate(0, height); + g2d.scale(sx, sy); + return graphicsObjectInfo; } } diff --git a/src/java/org/apache/fop/render/afp/AFPImageRawStreamFactory.java b/src/java/org/apache/fop/render/afp/AFPImageRawStreamFactory.java index 19504f6c9..376bee7b9 100644 --- a/src/java/org/apache/fop/render/afp/AFPImageRawStreamFactory.java +++ b/src/java/org/apache/fop/render/afp/AFPImageRawStreamFactory.java @@ -24,7 +24,7 @@ import java.io.InputStream; import org.apache.fop.afp.AFPDataObjectInfo; import org.apache.fop.afp.AFPObjectAreaInfo; -import org.apache.fop.afp.AFPState; +import org.apache.fop.afp.AFPPaintingState; import org.apache.xmlgraphics.image.loader.ImageInfo; import org.apache.xmlgraphics.image.loader.impl.ImageRawStream; @@ -36,9 +36,9 @@ public class AFPImageRawStreamFactory extends AFPDataObjectInfoFactory { /** * Main constructor * - * @param state the AFP state + * @param state the AFP painting state */ - public AFPImageRawStreamFactory(AFPState state) { + public AFPImageRawStreamFactory(AFPPaintingState state) { super(state); } diff --git a/src/java/org/apache/fop/render/afp/AFPImageRenderedFactory.java b/src/java/org/apache/fop/render/afp/AFPImageRenderedFactory.java index 9c59e8b83..59d6af9a8 100644 --- a/src/java/org/apache/fop/render/afp/AFPImageRenderedFactory.java +++ b/src/java/org/apache/fop/render/afp/AFPImageRenderedFactory.java @@ -26,7 +26,7 @@ import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.fop.afp.AFPDataObjectInfo; import org.apache.fop.afp.AFPImageObjectInfo; import org.apache.fop.afp.AFPObjectAreaInfo; -import org.apache.fop.afp.AFPState; +import org.apache.fop.afp.AFPPaintingState; import org.apache.xmlgraphics.image.loader.impl.ImageRendered; import org.apache.xmlgraphics.ps.ImageEncodingHelper; import org.apache.xmlgraphics.util.MimeConstants; @@ -39,9 +39,9 @@ public class AFPImageRenderedFactory extends AFPDataObjectInfoFactory { /** * Main constructor * - * @param state the AFP state + * @param state the AFP painting state */ - public AFPImageRenderedFactory(AFPState state) { + public AFPImageRenderedFactory(AFPPaintingState state) { super(state); } diff --git a/src/java/org/apache/fop/render/afp/AFPInfo.java b/src/java/org/apache/fop/render/afp/AFPInfo.java index 5fd59c2aa..1059014ab 100644 --- a/src/java/org/apache/fop/render/afp/AFPInfo.java +++ b/src/java/org/apache/fop/render/afp/AFPInfo.java @@ -20,9 +20,9 @@ package org.apache.fop.render.afp; import org.apache.avalon.framework.configuration.Configuration; +import org.apache.fop.afp.AFPPaintingState; import org.apache.fop.afp.AFPResourceInfo; import org.apache.fop.afp.AFPResourceManager; -import org.apache.fop.afp.AFPState; import org.apache.fop.fonts.FontInfo; /** @@ -48,7 +48,7 @@ public final class AFPInfo { private FontInfo fontInfo; /** See AFP_STATE */ - private AFPState state; + private AFPPaintingState state; /** See AFP_RESOURCE_MANAGER */ private AFPResourceManager resourceManager; @@ -127,7 +127,7 @@ public final class AFPInfo { * * @return the current AFP state */ - public AFPState getState() { + public AFPPaintingState getPaintingState() { return this.state; } @@ -146,7 +146,7 @@ public final class AFPInfo { * @return true if supports color */ public boolean isColorSupported() { - return getState().isColorImages(); + return getPaintingState().isColorImages(); } /** @@ -173,7 +173,7 @@ public final class AFPInfo { * @return the resolution */ protected int getResolution() { - return getState().getResolution(); + return getPaintingState().getResolution(); } /** @@ -181,7 +181,7 @@ public final class AFPInfo { * @return the number of bits per pixel to use */ protected int getBitsPerPixel() { - return getState().getBitsPerPixel(); + return getPaintingState().getBitsPerPixel(); } /** @@ -216,7 +216,7 @@ public final class AFPInfo { * * @param state the AFP state */ - public void setState(AFPState state) { + public void setPaintingState(AFPPaintingState state) { this.state = state; } diff --git a/src/java/org/apache/fop/render/afp/AFPRawCCITTFaxFactory.java b/src/java/org/apache/fop/render/afp/AFPRawCCITTFaxFactory.java index 17aff9fc0..2e6eca6ae 100644 --- a/src/java/org/apache/fop/render/afp/AFPRawCCITTFaxFactory.java +++ b/src/java/org/apache/fop/render/afp/AFPRawCCITTFaxFactory.java @@ -24,7 +24,7 @@ import java.io.IOException; import org.apache.fop.afp.AFPDataObjectInfo; import org.apache.fop.afp.AFPImageObjectInfo; import org.apache.fop.afp.AFPObjectAreaInfo; -import org.apache.fop.afp.AFPState; +import org.apache.fop.afp.AFPPaintingState; import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; /** @@ -35,9 +35,9 @@ public class AFPRawCCITTFaxFactory extends AFPDataObjectInfoFactory { /** * Main constructor * - * @param state the afp state + * @param state the AFP painting state */ - public AFPRawCCITTFaxFactory(AFPState state) { + public AFPRawCCITTFaxFactory(AFPPaintingState state) { super(state); } diff --git a/src/java/org/apache/fop/render/afp/AFPRenderer.java b/src/java/org/apache/fop/render/afp/AFPRenderer.java index 03945dfee..87c098a89 100644 --- a/src/java/org/apache/fop/render/afp/AFPRenderer.java +++ b/src/java/org/apache/fop/render/afp/AFPRenderer.java @@ -33,14 +33,13 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import org.apache.fop.AbstractState; import org.apache.fop.afp.AFPBorderPainter; import org.apache.fop.afp.AFPConstants; import org.apache.fop.afp.AFPDataObjectInfo; import org.apache.fop.afp.AFPPageFonts; +import org.apache.fop.afp.AFPPaintingState; import org.apache.fop.afp.AFPRectanglePainter; import org.apache.fop.afp.AFPResourceManager; -import org.apache.fop.afp.AFPState; import org.apache.fop.afp.AFPTextDataInfo; import org.apache.fop.afp.AFPUnitConverter; import org.apache.fop.afp.BorderPaintInfo; @@ -72,6 +71,7 @@ import org.apache.fop.render.Graphics2DAdapter; import org.apache.fop.render.RendererContext; import org.apache.fop.render.afp.extensions.AFPElementMapping; import org.apache.fop.render.afp.extensions.AFPPageSetup; +import org.apache.fop.util.AbstractPaintingState; import org.apache.xmlgraphics.image.loader.ImageException; import org.apache.xmlgraphics.image.loader.ImageFlavor; import org.apache.xmlgraphics.image.loader.ImageInfo; @@ -146,8 +146,8 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { /** resource manager */ private AFPResourceManager resourceManager; - /** drawing state */ - private final AFPState state; + /** painting state */ + private final AFPPaintingState paintingState; /** unit converter */ private final AFPUnitConverter unitConv; @@ -175,9 +175,9 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { public AFPRenderer() { super(); this.resourceManager = new AFPResourceManager(); - this.state = new AFPState(); - this.dataObjectInfoProvider = new AFPDataObjectInfoProvider(state); - this.unitConv = state.getUnitConverter(); + this.paintingState = new AFPPaintingState(); + this.dataObjectInfoProvider = new AFPDataObjectInfoProvider(paintingState); + this.unitConv = paintingState.getUnitConverter(); } /** {@inheritDoc} */ @@ -197,13 +197,13 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { /** {@inheritDoc} */ public void startRenderer(OutputStream outputStream) throws IOException { - state.setColor(Color.WHITE); + paintingState.setColor(Color.WHITE); - resourceManager.createDataStream(state, outputStream); + resourceManager.createDataStream(paintingState, outputStream); this.dataStream = resourceManager.getDataStream(); - this.borderPainter = new AFPBorderPainter(state, dataStream); - this.rectanglePainter = new AFPRectanglePainter(state, dataStream); + this.borderPainter = new AFPBorderPainter(paintingState, dataStream); + this.rectanglePainter = new AFPRectanglePainter(paintingState, dataStream); dataStream.startDocument(); } @@ -231,10 +231,10 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { /** {@inheritDoc} */ public void preparePage(PageViewport page) { - int pageRotation = state.getPageRotation(); - int pageWidth = state.getPageWidth(); - int pageHeight = state.getPageHeight(); - int resolution = state.getResolution(); + int pageRotation = paintingState.getPageRotation(); + int pageWidth = paintingState.getPageWidth(); + int pageHeight = paintingState.getPageHeight(); + int resolution = paintingState.getResolution(); dataStream.startPage(pageWidth, pageHeight, pageRotation, resolution, resolution); @@ -278,7 +278,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { /** {@inheritDoc} */ protected void concatenateTransformationMatrix(AffineTransform at) { if (!at.isIdentity()) { - state.concatenate(at); + paintingState.concatenate(at); } } @@ -296,12 +296,12 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { /** {@inheritDoc} */ public void renderPage(PageViewport pageViewport) throws IOException, FOPException { - state.clear(); + paintingState.clear(); Rectangle2D bounds = pageViewport.getViewArea(); AffineTransform baseTransform = getBaseTransform(); - state.concatenate(baseTransform); + paintingState.concatenate(baseTransform); if (pages.containsKey(pageViewport)) { dataStream.restorePage( @@ -309,15 +309,15 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { } else { int pageWidth = Math.round(unitConv.mpt2units((float)bounds.getWidth())); - state.setPageWidth(pageWidth); + paintingState.setPageWidth(pageWidth); int pageHeight = Math.round(unitConv.mpt2units((float)bounds.getHeight())); - state.setPageHeight(pageHeight); + paintingState.setPageHeight(pageHeight); - int pageRotation = state.getPageRotation(); + int pageRotation = paintingState.getPageRotation(); - int resolution = state.getResolution(); + int resolution = paintingState.getResolution(); dataStream.startPage(pageWidth, pageHeight, pageRotation, resolution, resolution); @@ -327,7 +327,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { super.renderPage(pageViewport); - AFPPageFonts pageFonts = state.getPageFonts(); + AFPPageFonts pageFonts = paintingState.getPageFonts(); if (pageFonts != null && !pageFonts.isEmpty()) { dataStream.addFontsToCurrentPage(pageFonts); } @@ -389,24 +389,22 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { this.fontInfo); context.setProperty(AFPRendererContextConstants.AFP_RESOURCE_MANAGER, this.resourceManager); - context.setProperty(AFPRendererContextConstants.AFP_STATE, state); + context.setProperty(AFPRendererContextConstants.AFP_PAINTING_STATE, paintingState); return context; } private static final ImageFlavor[] NATIVE_FLAVORS = new ImageFlavor[] { /*ImageFlavor.RAW_PNG, */ // PNG not natively supported in AFP - ImageFlavor.RAW_JPEG, ImageFlavor.RAW_CCITTFAX, ImageFlavor.RAW_EPS, - ImageFlavor.GRAPHICS2D, ImageFlavor.BUFFERED_IMAGE, ImageFlavor.RENDERED_IMAGE, - ImageFlavor.XML_DOM }; + ImageFlavor.XML_DOM, ImageFlavor.RAW_JPEG, ImageFlavor.RAW_CCITTFAX, ImageFlavor.RAW_EPS, + ImageFlavor.GRAPHICS2D, ImageFlavor.BUFFERED_IMAGE, ImageFlavor.RENDERED_IMAGE }; private static final ImageFlavor[] FLAVORS = new ImageFlavor[] { - ImageFlavor.GRAPHICS2D, ImageFlavor.BUFFERED_IMAGE, ImageFlavor.RENDERED_IMAGE, - ImageFlavor.XML_DOM }; + ImageFlavor.XML_DOM, ImageFlavor.GRAPHICS2D, ImageFlavor.BUFFERED_IMAGE, ImageFlavor.RENDERED_IMAGE }; /** {@inheritDoc} */ public void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) { uri = URISpecification.getURL(uri); - state.setImageUri(uri); + paintingState.setImageUri(uri); Rectangle posInt = new Rectangle((int) pos.getX(), (int) pos.getY(), (int) pos.getWidth(), (int) pos.getHeight()); String name = (String)pageSegmentMap.get(uri); @@ -427,7 +425,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { // Only now fully load/prepare the image Map hints = ImageUtil.getDefaultHints(sessionContext); - ImageFlavor[] flavors = state.isNativeImages() ? NATIVE_FLAVORS : FLAVORS; + ImageFlavor[] flavors = paintingState.isNativeImages() ? NATIVE_FLAVORS : FLAVORS; org.apache.xmlgraphics.image.loader.Image img = manager.getImage( info, flavors, hints, sessionContext); @@ -501,30 +499,30 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { /** {@inheritDoc} */ public void updateColor(Color col, boolean fill) { if (fill) { - state.setColor(col); + paintingState.setColor(col); } } /** {@inheritDoc} */ public void restoreStateStackAfterBreakOut(List breakOutList) { log.debug("Block.FIXED --> restoring context after break-out"); - state.pushAll(breakOutList); + paintingState.pushAll(breakOutList); } /** {@inheritDoc} */ protected List breakOutOfStateStack() { log.debug("Block.FIXED --> break out"); - return state.popAll(); + return paintingState.popAll(); } /** {@inheritDoc} */ public void saveGraphicsState() { - state.push(); + paintingState.push(); } /** {@inheritDoc} */ public void restoreGraphicsState() { - state.pop(); + paintingState.pop(); } /** Indicates the beginning of a text object. */ @@ -549,7 +547,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { renderInlineAreaBackAndBorders(text); int fontSize = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue(); - state.setFontSize(fontSize); + paintingState.setFontSize(fontSize); String name = getInternalFontNameForArea(text); AFPFont font = (AFPFont)fontInfo.getFonts().get(name); @@ -561,10 +559,10 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { AFPFontAttributes fontAttributes = new AFPFontAttributes(name, font, fontSize); - AFPPageFonts pageFonts = state.getPageFonts(); + AFPPageFonts pageFonts = paintingState.getPageFonts(); if (!pageFonts.containsKey(fontAttributes.getFontKey())) { // Font not found on current page, so add the new one - fontAttributes.setFontReference(state.incrementPageFontCount()); + fontAttributes.setFontReference(paintingState.incrementPageFontCount()); pageFonts.put(fontAttributes.getFontKey(), fontAttributes); } else { // Use the previously stored font attributes @@ -727,7 +725,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { * The rotation in degrees. */ public void setPortraitRotation(int rotation) { - state.setPortraitRotation(rotation); + paintingState.setPortraitRotation(rotation); } /** @@ -738,7 +736,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { * The rotation in degrees. */ public void setLandscapeRotation(int rotation) { - state.setLandscapeRotation(rotation); + paintingState.setLandscapeRotation(rotation); } /** @@ -748,7 +746,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { * number of bits per pixel */ public void setBitsPerPixel(int bitsPerPixel) { - state.setBitsPerPixel(bitsPerPixel); + paintingState.setBitsPerPixel(bitsPerPixel); } /** @@ -758,7 +756,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { * color image output */ public void setColorImages(boolean colorImages) { - state.setColorImages(colorImages); + paintingState.setColorImages(colorImages); } /** @@ -768,7 +766,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { * native image support */ public void setNativeImages(boolean nativeImages) { - state.setNativeImages(nativeImages); + paintingState.setNativeImages(nativeImages); } /** @@ -778,7 +776,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { * the output resolution (dpi) */ public void setResolution(int resolution) { - state.setResolution(resolution); + paintingState.setResolution(resolution); } /** @@ -787,7 +785,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { * @return the resolution in dpi */ public int getResolution() { - return state.getResolution(); + return paintingState.getResolution(); } /** @@ -795,8 +793,8 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { * * @return the current AFP state */ - public AbstractState getState() { - return this.state; + public AbstractPaintingState getState() { + return this.paintingState; } /** diff --git a/src/java/org/apache/fop/render/afp/AFPRendererContextConstants.java b/src/java/org/apache/fop/render/afp/AFPRendererContextConstants.java index 72be26483..3302b7f3c 100644 --- a/src/java/org/apache/fop/render/afp/AFPRendererContextConstants.java +++ b/src/java/org/apache/fop/render/afp/AFPRendererContextConstants.java @@ -38,6 +38,6 @@ public interface AFPRendererContextConstants extends RendererContextConstants { /** The afp resource manager */ String AFP_RESOURCE_MANAGER = "afpResourceManager"; - /** The afp state */ - String AFP_STATE = "afpPageState"; + /** The afp painting state */ + String AFP_PAINTING_STATE = "afpPaintingState"; } diff --git a/src/java/org/apache/fop/render/afp/AFPSVGHandler.java b/src/java/org/apache/fop/render/afp/AFPSVGHandler.java index de2786215..3bdab289c 100644 --- a/src/java/org/apache/fop/render/afp/AFPSVGHandler.java +++ b/src/java/org/apache/fop/render/afp/AFPSVGHandler.java @@ -20,6 +20,7 @@ package org.apache.fop.render.afp; // FOP +import java.awt.Dimension; import java.awt.geom.AffineTransform; import java.awt.geom.Dimension2D; import java.io.IOException; @@ -36,14 +37,16 @@ import org.apache.fop.afp.AFPForeignAttributeReader; import org.apache.fop.afp.AFPGraphics2D; import org.apache.fop.afp.AFPGraphicsObjectInfo; import org.apache.fop.afp.AFPObjectAreaInfo; +import org.apache.fop.afp.AFPPaintingState; import org.apache.fop.afp.AFPResourceInfo; +import org.apache.fop.afp.AFPResourceLevel; import org.apache.fop.afp.AFPResourceManager; -import org.apache.fop.afp.AFPState; import org.apache.fop.afp.AFPTextElementBridge; import org.apache.fop.afp.AFPTextHandler; import org.apache.fop.afp.AFPTextPainter; import org.apache.fop.afp.AFPUnitConverter; -import org.apache.fop.fo.extensions.ExtensionElementMapping; +import org.apache.fop.afp.Graphics2DImagePainterGOCA; +import org.apache.fop.fonts.FontInfo; import org.apache.fop.render.AbstractGenericSVGHandler; import org.apache.fop.render.Renderer; import org.apache.fop.render.RendererContext; @@ -51,7 +54,7 @@ import org.apache.fop.render.RendererContextConstants; import org.apache.fop.render.RendererContext.RendererContextWrapper; import org.apache.fop.svg.SVGEventProducer; import org.apache.fop.svg.SVGUserAgent; -import org.apache.xmlgraphics.util.QName; +import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; import org.w3c.dom.Document; /** @@ -61,9 +64,7 @@ import org.w3c.dom.Document; */ public class AFPSVGHandler extends AbstractGenericSVGHandler { - /** foreign attribute reader */ - private final AFPForeignAttributeReader foreignAttributeReader - = new AFPForeignAttributeReader(); + private boolean paintAsBitmap = false; /** {@inheritDoc} */ public void handleXML(RendererContext context, @@ -88,21 +89,24 @@ public class AFPSVGHandler extends AbstractGenericSVGHandler { afpi.setHandlerConfiguration((Configuration)context.getProperty(HANDLER_CONFIGURATION)); afpi.setFontInfo((org.apache.fop.fonts.FontInfo)context.getProperty( AFPRendererContextConstants.AFP_FONT_INFO)); - afpi.setState((AFPState)context.getProperty( - AFPRendererContextConstants.AFP_STATE)); + afpi.setPaintingState((AFPPaintingState)context.getProperty( + AFPRendererContextConstants.AFP_PAINTING_STATE)); afpi.setResourceManager(((AFPResourceManager)context.getProperty( AFPRendererContextConstants.AFP_RESOURCE_MANAGER))); Map foreignAttributes = (Map)context.getProperty(RendererContextConstants.FOREIGN_ATTRIBUTES); if (foreignAttributes != null) { + String conversionMode = (String)foreignAttributes.get(CONVERSION_MODE); + boolean paintAsBitmap = BITMAP.equalsIgnoreCase(conversionMode); + afpi.setPaintAsBitmap(paintAsBitmap); + AFPForeignAttributeReader foreignAttributeReader = new AFPForeignAttributeReader(); AFPResourceInfo resourceInfo = foreignAttributeReader.getResourceInfo(foreignAttributes); - afpi.setResourceInfo(resourceInfo); - - QName qName = new QName(ExtensionElementMapping.URI, null, "conversion-mode"); - if ("bitmap".equalsIgnoreCase((String)foreignAttributes.get(qName))) { - afpi.setPaintAsBitmap(true); + // default to inline level if painted as GOCA + if (!resourceInfo.levelChanged() && !paintAsBitmap) { + resourceInfo.setLevel(new AFPResourceLevel(AFPResourceLevel.INLINE)); } + afpi.setResourceInfo(resourceInfo); } return afpi; } @@ -122,8 +126,10 @@ public class AFPSVGHandler extends AbstractGenericSVGHandler { AFPInfo afpInfo = getAFPInfo(context); + this.paintAsBitmap = afpInfo.paintAsBitmap(); + // fallback paint as bitmap - if (afpInfo.paintAsBitmap()) { + if (paintAsBitmap) { try { super.renderSVGDocument(context, doc); } catch (IOException ioe) { @@ -135,8 +141,8 @@ public class AFPSVGHandler extends AbstractGenericSVGHandler { } String uri = ((AbstractDocument)doc).getDocumentURI(); - AFPState state = afpInfo.getState(); - state.setImageUri(uri); + AFPPaintingState paintingState = afpInfo.getPaintingState(); + paintingState.setImageUri(uri); // set the data object parameters AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo(); @@ -146,7 +152,7 @@ public class AFPSVGHandler extends AbstractGenericSVGHandler { int curry = rctx.getCurrentYPosition(); float[] srcPts = {currx, curry}; - AFPUnitConverter unitConv = state.getUnitConverter(); + AFPUnitConverter unitConv = paintingState.getUnitConverter(); int[] coords = unitConv.mpts2units(srcPts); objectAreaInfo.setX(coords[X]); objectAreaInfo.setY(coords[Y]); @@ -161,7 +167,7 @@ public class AFPSVGHandler extends AbstractGenericSVGHandler { int height = Math.round(unitConv.mpt2units(afpInfo.getHeight())); objectAreaInfo.setHeight(height); - int rotation = state.getRotation(); + int rotation = paintingState.getRotation(); objectAreaInfo.setRotation(rotation); AFPGraphicsObjectInfo graphicsObjectInfo = new AFPGraphicsObjectInfo(); @@ -171,14 +177,22 @@ public class AFPSVGHandler extends AbstractGenericSVGHandler { final boolean textAsShapes = false; AFPGraphics2D g2d = new AFPGraphics2D(textAsShapes); - g2d.setResourceManager(afpInfo.getResourceManager()); - g2d.setResourceInfo(afpInfo.getResourceInfo()); - g2d.setState(afpInfo.getState()); + g2d.setPaintingState(paintingState); + + AFPResourceManager resourceManager = afpInfo.getResourceManager(); + g2d.setResourceManager(resourceManager); + + AFPResourceInfo resourceInfo = afpInfo.getResourceInfo(); + g2d.setResourceInfo(resourceInfo); + graphicsObjectInfo.setResourceInfo(resourceInfo); + g2d.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext()); - g2d.setFontInfo(afpInfo.getFontInfo()); + + FontInfo fontInfo = afpInfo.getFontInfo(); + g2d.setFontInfo(fontInfo); // Configure GraphicsObjectPainter with the Graphics2D implementation - AFPBatikGraphicsObjectPainter painter = new AFPBatikGraphicsObjectPainter(g2d); + GraphicsObjectPainterAFP painter = new GraphicsObjectPainterAFP(g2d); (graphicsObjectInfo).setPainter(painter); // Controls whether text painted by Batik is generated using text or path operations @@ -194,12 +208,6 @@ public class AFPSVGHandler extends AbstractGenericSVGHandler { ctx.putBridge(tBridge); } - Map/**/ foreignAttributes - = (Map/**/)context.getProperty( - RendererContextConstants.FOREIGN_ATTRIBUTES); - AFPResourceInfo resourceInfo = foreignAttributeReader.getResourceInfo(foreignAttributes); - graphicsObjectInfo.setResourceInfo(resourceInfo); - // Build the SVG DOM and provide the painter with it GraphicsNode root; GVTBuilder builder = new GVTBuilder(); @@ -221,13 +229,12 @@ public class AFPSVGHandler extends AbstractGenericSVGHandler { double hx = (afpInfo.getHeight() / h); double scaleX = unitConv.pt2units((float)wx); double scaleY = unitConv.pt2units((float)hx); - double xOffset = unitConv.mpt2units(afpInfo.getX()); double yOffset = unitConv.mpt2units(afpInfo.getHeight()); // Transformation matrix that establishes the local coordinate system // for the SVG graphic in relation to the current coordinate system // (note: y axis is inverted) - AffineTransform trans = new AffineTransform(scaleX, 0, 0, -scaleY, xOffset, yOffset); + AffineTransform trans = new AffineTransform(scaleX, 0, 0, -scaleY, 0, yOffset); g2d.setTransform(trans); // Set the afp graphics 2d implementation @@ -236,8 +243,6 @@ public class AFPSVGHandler extends AbstractGenericSVGHandler { // Set the object area info graphicsObjectInfo.setObjectAreaInfo(objectAreaInfo); - AFPResourceManager resourceManager = afpInfo.getResourceManager(); - // Create the graphics object resourceManager.createObject(graphicsObjectInfo); } @@ -253,4 +258,24 @@ public class AFPSVGHandler extends AbstractGenericSVGHandler { context.setProperty(AFPRendererContextConstants.AFP_GRAYSCALE, Boolean.FALSE); } + /** {@inheritDoc} */ + protected Graphics2DImagePainter createPainter(BridgeContext ctx, GraphicsNode root, Dimension imageSize) { + Graphics2DImagePainter painter = null; + if (paintAsBitmap()) { + painter = super.createPainter(root, ctx, imageSize); + } else { + painter = new Graphics2DImagePainterGOCA(root, ctx, imageSize); + } + return painter; + } + + /** + * Returns true if the SVG is to be painted as a bitmap + * + * @return true if the SVG is to be painted as a bitmap + */ + private boolean paintAsBitmap() { + return paintAsBitmap; + } + } diff --git a/src/java/org/apache/fop/render/afp/GraphicsObjectPainterAFP.java b/src/java/org/apache/fop/render/afp/GraphicsObjectPainterAFP.java new file mode 100644 index 000000000..7eb2c1001 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/GraphicsObjectPainterAFP.java @@ -0,0 +1,89 @@ +/* + * 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.render.afp; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; + +import org.apache.batik.gvt.GraphicsNode; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.afp.AFPGraphics2D; +import org.apache.fop.afp.modca.GraphicsObject; +import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; + +/** + * Paints SVG as a GOCA Graphics Object using Batik + */ +public class GraphicsObjectPainterAFP implements Graphics2DImagePainter { + /** Static logging instance */ + protected static Log log = LogFactory.getLog(GraphicsObjectPainterAFP.class); + + private final AFPGraphics2D graphics2D; + + /** the batik root node of the svg document */ + private GraphicsNode root; + + /** + * Main constructor + * + * @param graphics an AFP graphics 2D implementation + */ + public GraphicsObjectPainterAFP(AFPGraphics2D graphics) { + final boolean textAsShapes = false; + this.graphics2D = new AFPGraphics2D(textAsShapes); + } + + /** + * Sets the graphics node + * + * @param rootNode the graphics root node + */ + public void setGraphicsNode(GraphicsNode rootNode) { + this.root = rootNode; + } + + /** {@inheritDoc} */ + public void paint(Graphics2D g2d, Rectangle2D area) { + log.debug("Painting SVG using GOCA"); + + // tell batik to paint the graphics object + root.paint(g2d); + + // dispose of the graphics 2d implementation + g2d.dispose(); + } + + /** {@inheritDoc} */ + public Dimension getImageSize() { + return null; + } + + /** + * Sets the GOCA Graphics Object + * + * @param graphicsObject the GOCA Graphics Object + */ + public void setGraphicsObject(GraphicsObject graphicsObject) { + this.graphics2D.setGraphicsObject(graphicsObject); + } + +} diff --git a/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java b/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java index 6ed45ca98..ba5c86059 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java +++ b/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java @@ -23,22 +23,18 @@ import java.awt.geom.AffineTransform; import java.io.IOException; import java.util.Map; -import org.w3c.dom.Document; - import org.apache.batik.bridge.BridgeContext; import org.apache.batik.bridge.GVTBuilder; import org.apache.batik.gvt.GraphicsNode; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - -import org.apache.fop.fo.extensions.ExtensionElementMapping; import org.apache.fop.render.AbstractGenericSVGHandler; import org.apache.fop.render.Renderer; import org.apache.fop.render.RendererContext; import org.apache.fop.render.RendererContextConstants; import org.apache.fop.svg.SVGEventProducer; import org.apache.fop.svg.SVGUserAgent; -import org.apache.xmlgraphics.util.QName; +import org.w3c.dom.Document; /** * Java2D XML handler for SVG (uses Apache Batik). @@ -72,9 +68,8 @@ public class Java2DSVGHandler extends AbstractGenericSVGHandler pdfi.currentXPosition = ((Integer)context.getProperty(XPOS)).intValue(); pdfi.currentYPosition = ((Integer)context.getProperty(YPOS)).intValue(); Map foreign = (Map)context.getProperty(RendererContextConstants.FOREIGN_ATTRIBUTES); - QName qName = new QName(ExtensionElementMapping.URI, null, "conversion-mode"); if (foreign != null - && "bitmap".equalsIgnoreCase((String)foreign.get(qName))) { + && BITMAP.equalsIgnoreCase((String)foreign.get(CONVERSION_MODE))) { pdfi.paintAsBitmap = true; } return pdfi; diff --git a/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java b/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java index 2aa11227a..01d863e6a 100644 --- a/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java +++ b/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java @@ -95,8 +95,8 @@ public class PDFGraphics2DAdapter extends AbstractGraphics2DAdapter { AffineTransform transform = new AffineTransform(); transform.translate(fx, fy); - pdfInfo.pdfState.concatenate(transform); - graphics.setPDFState(pdfInfo.pdfState); + pdfInfo.pdfPaintingState.concatenate(transform); + graphics.setPaintingState(pdfInfo.pdfPaintingState); graphics.setOutputStream(pdfInfo.outputStream); if (pdfInfo.paintAsBitmap) { diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index 9f60d3c86..0eba2fe91 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -40,7 +40,6 @@ import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import org.apache.commons.io.IOUtils; -import org.apache.fop.AbstractData; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; @@ -95,9 +94,9 @@ import org.apache.fop.pdf.PDFOutline; import org.apache.fop.pdf.PDFOutputIntent; import org.apache.fop.pdf.PDFPage; import org.apache.fop.pdf.PDFPageLabels; +import org.apache.fop.pdf.PDFPaintingState; import org.apache.fop.pdf.PDFResourceContext; import org.apache.fop.pdf.PDFResources; -import org.apache.fop.pdf.PDFState; import org.apache.fop.pdf.PDFStream; import org.apache.fop.pdf.PDFTextUtil; import org.apache.fop.pdf.PDFXMode; @@ -105,9 +104,11 @@ import org.apache.fop.pdf.PDFXObject; import org.apache.fop.render.AbstractPathOrientedRenderer; import org.apache.fop.render.Graphics2DAdapter; import org.apache.fop.render.RendererContext; +import org.apache.fop.util.AbstractPaintingState; import org.apache.fop.util.CharUtilities; import org.apache.fop.util.ColorProfileUtil; import org.apache.fop.util.ColorUtil; +import org.apache.fop.util.AbstractPaintingState.AbstractData; import org.apache.xmlgraphics.image.loader.ImageException; import org.apache.xmlgraphics.image.loader.ImageInfo; import org.apache.xmlgraphics.image.loader.ImageManager; @@ -249,8 +250,8 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { /** Optional URI to an output profile to be used. */ protected String outputProfileURI; - /** drawing state */ - protected PDFState currentState = null; + /** Painting state */ + protected PDFPaintingState paintingState = null; /** Text generation utility holding the current font status */ protected PDFTextUtil textutil; @@ -518,7 +519,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { currentStream = null; currentContext = null; currentPage = null; - currentState = null; + paintingState = null; this.textutil = null; idPositions.clear(); @@ -639,7 +640,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { /** {@inheritDoc} */ protected void saveGraphicsState() { endTextObject(); - currentState.push(); + paintingState.push(); currentStream.add("q\n"); } @@ -647,7 +648,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { endTextObject(); currentStream.add("Q\n"); if (popState) { - currentState.pop(); + paintingState.pop(); } } @@ -782,11 +783,11 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { } }; - currentState = new PDFState(); + paintingState = new PDFPaintingState(); // Transform the PDF's default coordinate system (0,0 at lower left) to the PDFRenderer's AffineTransform basicPageTransform = new AffineTransform(1, 0, 0, -1, 0, pageHeight / 1000f); - currentState.concatenate(basicPageTransform); + paintingState.concatenate(basicPageTransform); currentStream.add(CTMHelper.toPDFString(basicPageTransform, false) + " cm\n"); super.renderPage(page); @@ -806,7 +807,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { protected void startVParea(CTM ctm, Rectangle2D clippingRect) { saveGraphicsState(); // Set the given CTM in the graphics state - currentState.concatenate( + paintingState.concatenate( new AffineTransform(CTMHelper.toPDFArray(ctm))); if (clippingRect != null) { @@ -827,7 +828,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { /** {@inheritDoc} */ protected void concatenateTransformationMatrix(AffineTransform at) { if (!at.isIdentity()) { - currentState.concatenate(at); + paintingState.concatenate(at); currentStream.add(CTMHelper.toPDFString(at, false) + " cm\n"); } } @@ -1017,7 +1018,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { * @param width line width in points */ private void updateLineWidth(float width) { - if (currentState.setLineWidth(width)) { + if (paintingState.setLineWidth(width)) { //Only write if value has changed WRT the current line width currentStream.add(format(width) + " w\n"); } @@ -1095,10 +1096,10 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { protected List breakOutOfStateStack() { // return currentState.popAll(); List breakOutList = new java.util.ArrayList(); - AbstractData data; + AbstractPaintingState.AbstractData data; while (true) { - data = currentState.getData(); - if (currentState.pop() == null) { + data = paintingState.getData(); + if (paintingState.pop() == null) { break; } if (breakOutList.size() == 0) { @@ -1260,7 +1261,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { */ protected void saveAbsolutePosition(String id, int relativeIPP, int relativeBPP) { saveAbsolutePosition(id, currentPageRef, - relativeIPP, relativeBPP, currentState.getTransform()); + relativeIPP, relativeBPP, paintingState.getTransform()); } /** @@ -1284,8 +1285,8 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { bpp += currentBPPosition; } AffineTransform tf = positioning == Block.FIXED - ? currentState.getBaseTransform() - : currentState.getTransform(); + ? paintingState.getBaseTransform() + : paintingState.getTransform(); saveAbsolutePosition(id, currentPageRef, ipp, bpp, tf); } } @@ -1348,7 +1349,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { int bpp = currentBPPosition + ip.getOffset(); ipRect = new Rectangle2D.Float(ipp / 1000f, bpp / 1000f, ip.getIPD() / 1000f, ip.getBPD() / 1000f); - AffineTransform transform = currentState.getTransform(); + AffineTransform transform = paintingState.getTransform(); ipRect = transform.createTransformedShape(ipRect).getBounds2D(); factory = pdfDoc.getFactory(); @@ -1582,9 +1583,9 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { } boolean update = false; if (fill) { - update = currentState.setBackColor(col); + update = paintingState.setBackColor(col); } else { - update = currentState.setColor(col); + update = paintingState.setColor(col); } if (update) { @@ -1725,7 +1726,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { x, y, width, height, foreignAttributes); context.setProperty(PDFRendererContextConstants.PDF_DOCUMENT, pdfDoc); context.setProperty(PDFRendererContextConstants.OUTPUT_STREAM, ostream); - context.setProperty(PDFRendererContextConstants.PDF_STATE, currentState); + context.setProperty(PDFRendererContextConstants.PDF_PAINTING_STATE, paintingState); context.setProperty(PDFRendererContextConstants.PDF_PAGE, currentPage); context.setProperty(PDFRendererContextConstants.PDF_CONTEXT, currentContext == null ? currentPage : currentContext); @@ -1745,7 +1746,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { public void renderLeader(Leader area) { renderInlineAreaBackAndBorders(area); - currentState.push(); + paintingState.push(); saveGraphicsState(); int style = area.getRuleStyle(); float startx = (currentIPPosition + area.getBorderAndPaddingWidthStart()) / 1000f; @@ -1803,7 +1804,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { } restoreGraphicsState(); - currentState.pop(); + paintingState.pop(); beginTextObject(); super.renderLeader(area); } diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererContextConstants.java b/src/java/org/apache/fop/render/pdf/PDFRendererContextConstants.java index de51aabc7..33888d442 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRendererContextConstants.java +++ b/src/java/org/apache/fop/render/pdf/PDFRendererContextConstants.java @@ -29,8 +29,8 @@ public interface PDFRendererContextConstants extends RendererContextConstants { /** The PDF document that this image is being drawn into. */ String PDF_DOCUMENT = "pdfDoc"; - /** The current pdf state. */ - String PDF_STATE = "pdfState"; + /** The current PDF painting state. */ + String PDF_PAINTING_STATE = "pdfPaintingState"; /** The current PDF page for page renference and as a resource context. */ String PDF_PAGE = "pdfPage"; diff --git a/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java b/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java index e31628160..e83579728 100644 --- a/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java @@ -25,8 +25,6 @@ import java.io.IOException; import java.io.OutputStream; import java.util.Map; -import org.w3c.dom.Document; - import org.apache.avalon.framework.configuration.Configuration; import org.apache.batik.bridge.BridgeContext; import org.apache.batik.bridge.GVTBuilder; @@ -35,16 +33,12 @@ import org.apache.batik.gvt.GraphicsNode; import org.apache.batik.util.SVGConstants; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - -import org.apache.xmlgraphics.util.QName; - import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.fo.extensions.ExtensionElementMapping; import org.apache.fop.fonts.FontInfo; import org.apache.fop.pdf.PDFDocument; import org.apache.fop.pdf.PDFPage; +import org.apache.fop.pdf.PDFPaintingState; import org.apache.fop.pdf.PDFResourceContext; -import org.apache.fop.pdf.PDFState; import org.apache.fop.pdf.PDFStream; import org.apache.fop.render.AbstractGenericSVGHandler; import org.apache.fop.render.Renderer; @@ -55,6 +49,7 @@ import org.apache.fop.svg.PDFBridgeContext; import org.apache.fop.svg.PDFGraphics2D; import org.apache.fop.svg.SVGEventProducer; import org.apache.fop.svg.SVGUserAgent; +import org.w3c.dom.Document; /** * PDF XML handler for SVG (uses Apache Batik). @@ -78,7 +73,7 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler PDFInfo pdfi = new PDFInfo(); pdfi.pdfDoc = (PDFDocument)context.getProperty(PDF_DOCUMENT); pdfi.outputStream = (OutputStream)context.getProperty(OUTPUT_STREAM); - pdfi.pdfState = (PDFState)context.getProperty(PDF_STATE); + pdfi.pdfPaintingState = (PDFPaintingState)context.getProperty(PDF_PAINTING_STATE); pdfi.pdfPage = (PDFPage)context.getProperty(PDF_PAGE); pdfi.pdfContext = (PDFResourceContext)context.getProperty(PDF_CONTEXT); pdfi.currentStream = (PDFStream)context.getProperty(PDF_STREAM); @@ -91,10 +86,9 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler pdfi.currentYPosition = ((Integer)context.getProperty(YPOS)).intValue(); pdfi.cfg = (Configuration)context.getProperty(HANDLER_CONFIGURATION); Map foreign = (Map)context.getProperty(RendererContextConstants.FOREIGN_ATTRIBUTES); - - QName qName = new QName(ExtensionElementMapping.URI, null, "conversion-mode"); + if (foreign != null - && "bitmap".equalsIgnoreCase((String)foreign.get(qName))) { + && BITMAP.equalsIgnoreCase((String)foreign.get(CONVERSION_MODE))) { pdfi.paintAsBitmap = true; } return pdfi; @@ -109,7 +103,7 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler /** see OUTPUT_STREAM */ public OutputStream outputStream; /** see PDF_STATE */ - public PDFState pdfState; + public PDFPaintingState pdfPaintingState; /** see PDF_PAGE */ public PDFPage pdfPage; /** see PDF_CONTEXT */ @@ -199,8 +193,8 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler float w = (float)ctx.getDocumentSize().getWidth() * 1000f; float h = (float)ctx.getDocumentSize().getHeight() * 1000f; - float sx = pdfInfo.width / (float)w; - float sy = pdfInfo.height / (float)h; + float sx = pdfInfo.width / w; + float sy = pdfInfo.height / h; //Scaling and translation for the bounding box of the image AffineTransform scaling = new AffineTransform( @@ -249,16 +243,16 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler pdfInfo.currentStream.add("%SVG start\n"); //Save state and update coordinate system for the SVG image - pdfInfo.pdfState.push(); - pdfInfo.pdfState.concatenate(imageTransform); + pdfInfo.pdfPaintingState.push(); + pdfInfo.pdfPaintingState.concatenate(imageTransform); //Now that we have the complete transformation matrix for the image, we can update the //transformation matrix for the AElementBridge. PDFAElementBridge aBridge = (PDFAElementBridge)ctx.getBridge( SVGDOMImplementation.SVG_NAMESPACE_URI, SVGConstants.SVG_A_TAG); - aBridge.getCurrentTransform().setTransform(pdfInfo.pdfState.getTransform()); + aBridge.getCurrentTransform().setTransform(pdfInfo.pdfPaintingState.getTransform()); - graphics.setPDFState(pdfInfo.pdfState); + graphics.setPaintingState(pdfInfo.pdfPaintingState); graphics.setOutputStream(pdfInfo.outputStream); try { root.paint(graphics); @@ -268,7 +262,7 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler context.getUserAgent().getEventBroadcaster()); eventProducer.svgRenderingError(this, e, getDocumentURI(doc)); } - pdfInfo.pdfState.pop(); + pdfInfo.pdfPaintingState.pop(); renderer.restoreGraphicsState(); pdfInfo.currentStream.add("%SVG end\n"); } diff --git a/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java index dd13df1c4..cc6e06978 100644 --- a/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java +++ b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java @@ -19,30 +19,30 @@ package org.apache.fop.svg; -import org.apache.fop.Version; -import org.apache.fop.pdf.PDFDocument; -import org.apache.fop.pdf.PDFFilterList; -import org.apache.fop.pdf.PDFPage; -import org.apache.fop.pdf.PDFStream; -import org.apache.fop.pdf.PDFState; -import org.apache.fop.pdf.PDFNumber; -import org.apache.fop.pdf.PDFResources; -import org.apache.fop.pdf.PDFColor; -import org.apache.fop.pdf.PDFAnnotList; -import org.apache.fop.fonts.FontInfo; -import org.apache.fop.fonts.FontSetup; - -import java.awt.Graphics; -import java.awt.Font; import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; import java.awt.Shape; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; -import java.io.OutputStream; import java.io.IOException; +import java.io.OutputStream; import java.io.StringWriter; +import org.apache.fop.Version; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontSetup; +import org.apache.fop.pdf.PDFAnnotList; +import org.apache.fop.pdf.PDFColor; +import org.apache.fop.pdf.PDFDocument; +import org.apache.fop.pdf.PDFFilterList; +import org.apache.fop.pdf.PDFNumber; +import org.apache.fop.pdf.PDFPage; +import org.apache.fop.pdf.PDFPaintingState; +import org.apache.fop.pdf.PDFResources; +import org.apache.fop.pdf.PDFStream; + /** * This class is a wrapper for the PDFGraphics2D that * is used to create a full document around the pdf rendering from @@ -52,7 +52,7 @@ import java.io.StringWriter; */ public class PDFDocumentGraphics2D extends PDFGraphics2D { - private PDFContext pdfContext; + private final PDFContext pdfContext; private int width; private int height; @@ -296,7 +296,7 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D { throw new IllegalStateException("Close page first before starting another"); } //Start page - graphicsState = new PDFState(); + paintingState = new PDFPaintingState(); if (this.initialTransform == null) { //Save initial transformation matrix this.initialTransform = getTransform(); @@ -322,7 +322,7 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D { pageRef = page.referencePDF(); AffineTransform at = new AffineTransform(1.0, 0.0, 0.0, -1.0, - 0.0, (double)height); + 0.0, height); currentStream.write("1 0 0 -1 0 " + height + " cm\n"); if (svgWidth != 0) { double scaleX = width / svgWidth; @@ -340,7 +340,7 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D { scale(1 / s, 1 / s); } // Remember the transform we installed. - graphicsState.concatenate(at); + paintingState.concatenate(at); pdfContext.increasePageCount(); } diff --git a/src/java/org/apache/fop/svg/PDFGraphics2D.java b/src/java/org/apache/fop/svg/PDFGraphics2D.java index cd0a4133b..179ebb90a 100644 --- a/src/java/org/apache/fop/svg/PDFGraphics2D.java +++ b/src/java/org/apache/fop/svg/PDFGraphics2D.java @@ -59,15 +59,6 @@ import org.apache.batik.ext.awt.RadialGradientPaint; import org.apache.batik.ext.awt.RenderingHintsKeyExt; import org.apache.batik.gvt.GraphicsNode; import org.apache.batik.gvt.PatternPaint; - -import org.apache.xmlgraphics.image.loader.ImageInfo; -import org.apache.xmlgraphics.image.loader.ImageSize; -import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; -import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG; -import org.apache.xmlgraphics.image.loader.impl.ImageRendered; -import org.apache.xmlgraphics.java2d.AbstractGraphics2D; -import org.apache.xmlgraphics.java2d.GraphicContext; - import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontSetup; @@ -83,16 +74,23 @@ import org.apache.fop.pdf.PDFImage; import org.apache.fop.pdf.PDFImageXObject; import org.apache.fop.pdf.PDFLink; import org.apache.fop.pdf.PDFNumber; +import org.apache.fop.pdf.PDFPaintingState; import org.apache.fop.pdf.PDFPattern; import org.apache.fop.pdf.PDFResourceContext; import org.apache.fop.pdf.PDFResources; -import org.apache.fop.pdf.PDFState; import org.apache.fop.pdf.PDFText; import org.apache.fop.pdf.PDFXObject; import org.apache.fop.render.pdf.ImageRawCCITTFaxAdapter; import org.apache.fop.render.pdf.ImageRawJPEGAdapter; import org.apache.fop.render.pdf.ImageRenderedAdapter; import org.apache.fop.util.ColorExt; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageSize; +import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; +import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG; +import org.apache.xmlgraphics.image.loader.impl.ImageRendered; +import org.apache.xmlgraphics.java2d.AbstractGraphics2D; +import org.apache.xmlgraphics.java2d.GraphicContext; /** * PDF Graphics 2D. @@ -129,9 +127,9 @@ public class PDFGraphics2D extends AbstractGraphics2D { protected String pageRef; /** - * the current state of the pdf graphics + * The PDF painting state */ - protected PDFState graphicsState; + protected PDFPaintingState paintingState; /** * The PDF graphics state level that this svg is being drawn into. @@ -200,7 +198,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { currentFontSize = size; fontInfo = fi; pageRef = pref; - graphicsState = new PDFState(); + paintingState = new PDFPaintingState(); } /** @@ -226,7 +224,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { this.currentFontSize = g.currentFontSize; this.fontInfo = g.fontInfo; this.pageRef = g.pageRef; - this.graphicsState = g.graphicsState; + this.paintingState = g.paintingState; this.currentStream = g.currentStream; this.nativeCount = g.nativeCount; this.outputStream = g.outputStream; @@ -266,9 +264,9 @@ public class PDFGraphics2D extends AbstractGraphics2D { * * @param state the PDF state */ - public void setPDFState(PDFState state) { - graphicsState = state; - baseLevel = graphicsState.getStackLevel(); + public void setPaintingState(PDFPaintingState state) { + paintingState = state; + baseLevel = paintingState.getStackLevel(); } /** @@ -369,7 +367,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { * @return the transformation matrix that established the basic user space for this document */ protected AffineTransform getBaseTransform() { - AffineTransform at = new AffineTransform(graphicsState.getTransform()); + AffineTransform at = new AffineTransform(paintingState.getTransform()); return at; } @@ -518,10 +516,13 @@ public class PDFGraphics2D extends AbstractGraphics2D { g.setBackground(new Color(1, 1, 1, 0)); g.setPaint(new Color(1, 1, 1, 0)); g.fillRect(0, 0, width, height); - g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight())); + + int imageWidth = buf.getWidth(); + int imageHeight = buf.getHeight(); + g.clip(new Rectangle(0, 0, imageWidth, imageHeight)); g.setComposite(gc.getComposite()); - if (!g.drawImage(img, 0, 0, buf.getWidth(), buf.getHeight(), observer)) { + if (!g.drawImage(img, 0, 0, imageWidth, imageHeight, observer)) { return false; } g.dispose(); @@ -602,13 +603,13 @@ public class PDFGraphics2D extends AbstractGraphics2D { trans.getMatrix(tranvals); Shape imclip = getClip(); - boolean newClip = graphicsState.checkClip(imclip); - boolean newTransform = graphicsState.checkTransform(trans) + boolean newClip = paintingState.checkClip(imclip); + boolean newTransform = paintingState.checkTransform(trans) && !trans.isIdentity(); if (newClip || newTransform) { currentStream.write("q\n"); - graphicsState.push(); + paintingState.push(); if (newTransform) { concatMatrix(tranvals); } @@ -625,7 +626,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { applyColor(c, true); Paint paint = getPaint(); - if (graphicsState.setPaint(paint)) { + if (paintingState.setPaint(paint)) { if (!applyPaint(paint, false)) { // Stroke the shape and use it to 'clip' // the paint contents. @@ -634,7 +635,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { if (newClip || newTransform) { currentStream.write("Q\n"); - graphicsState.pop(); + paintingState.pop(); } return; } @@ -646,7 +647,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { doDrawing(false, true, false); if (newClip || newTransform) { currentStream.write("Q\n"); - graphicsState.pop(); + paintingState.pop(); } } @@ -1380,7 +1381,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { if (!useMultiByte) { if (ch > 127) { currentStream.write("\\"); - currentStream.write(Integer.toOctalString((int)ch)); + currentStream.write(Integer.toOctalString(ch)); } else { switch (ch) { case '(': @@ -1397,8 +1398,8 @@ public class PDFGraphics2D extends AbstractGraphics2D { } if (kerningAvailable && (i + 1) < l) { - addKerning(currentStream, (new Integer((int)ch)), - (new Integer((int)fontState.mapChar(s.charAt(i + 1)))), + addKerning(currentStream, (new Integer(ch)), + (new Integer(fontState.mapChar(s.charAt(i + 1)))), kerning, startText, endText); } @@ -1426,7 +1427,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { vals.put(PDFGState.GSTATE_ALPHA_STROKE, new Float(strokeAlpha / 255f)); } PDFGState gstate = pdfDoc.getFactory().makeGState( - vals, graphicsState.getGState()); + vals, paintingState.getGState()); resourceContext.addGState(gstate); currentStream.write("/" + gstate.getName() + " gs\n"); } @@ -1438,7 +1439,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { */ protected void updateCurrentFont(Font font) { String name = font.getFontName(); - float size = (float)font.getFontSize() / 1000f; + float size = font.getFontSize() / 1000f; //Only update if necessary if ((!name.equals(this.currentFontName)) @@ -1617,13 +1618,13 @@ public class PDFGraphics2D extends AbstractGraphics2D { trans.getMatrix(tranvals); Shape imclip = getClip(); - boolean newClip = graphicsState.checkClip(imclip); - boolean newTransform = graphicsState.checkTransform(trans) + boolean newClip = paintingState.checkClip(imclip); + boolean newTransform = paintingState.checkTransform(trans) && !trans.isIdentity(); if (newClip || newTransform) { currentStream.write("q\n"); - graphicsState.push(); + paintingState.push(); if (newTransform) { concatMatrix(tranvals); } @@ -1640,14 +1641,14 @@ public class PDFGraphics2D extends AbstractGraphics2D { applyColor(c, false); Paint paint = getPaint(); - if (graphicsState.setPaint(paint)) { + if (paintingState.setPaint(paint)) { if (!applyPaint(paint, true)) { // Use the shape to 'clip' the paint contents. applyUnknownPaint(paint, s); if (newClip || newTransform) { currentStream.write("Q\n"); - graphicsState.pop(); + paintingState.pop(); } return; } @@ -1660,7 +1661,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { iter.getWindingRule() == PathIterator.WIND_EVEN_ODD); if (newClip || newTransform) { currentStream.write("Q\n"); - graphicsState.pop(); + paintingState.pop(); } } diff --git a/src/java/org/apache/fop/util/AbstractPaintingState.java b/src/java/org/apache/fop/util/AbstractPaintingState.java new file mode 100644 index 000000000..e712ce74f --- /dev/null +++ b/src/java/org/apache/fop/util/AbstractPaintingState.java @@ -0,0 +1,530 @@ +/* + * 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.util; + +import java.awt.Color; +import java.awt.geom.AffineTransform; +import java.io.Serializable; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Stack; + + +/** + * A base class which holds information about the current rendering state. + */ +public abstract class AbstractPaintingState implements Cloneable, Serializable { + + private static final long serialVersionUID = 5998356138437094188L; + + /** current state data */ + private AbstractData data = null; + + /** the state stack */ + private StateStack/**/ stateStack = new StateStack/**/(); + + /** + * Instantiates a new state data object + * + * @return a new state data object + */ + protected abstract AbstractData instantiateData(); + + /** + * Instantiates a new state object + * + * @return a new state object + */ + protected abstract AbstractPaintingState instantiate(); + + /** + * Returns the currently valid state + * + * @return the currently valid state + */ + public AbstractData getData() { + if (data == null) { + data = instantiateData(); + } + return data; + } + + /** + * Set the current color. + * Check if the new color is a change and then set the current color. + * + * @param col the color to set + * @return true if the color has changed + */ + public boolean setColor(Color col) { + if (!col.equals(getData().color)) { + getData().color = col; + return true; + } + return false; + } + + /** + * Get the color. + * + * @return the color + */ + public Color getColor() { + if (getData().color == null) { + getData().color = Color.black; + } + return getData().color; + } + + /** + * Get the background color. + * + * @return the background color + */ + public Color getBackColor() { + if (getData().backColor == null) { + getData().backColor = Color.white; + } + return getData().backColor; + } + + /** + * Set the current background color. + * Check if the new background color is a change and then set the current background color. + * + * @param col the background color to set + * @return true if the color has changed + */ + public boolean setBackColor(Color col) { + if (!col.equals(getData().backColor)) { + getData().backColor = col; + return true; + } + return false; + } + + /** + * Set the current font name + * + * @param internalFontName the internal font name + * @return true if the font name has changed + */ + public boolean setFontName(String internalFontName) { + if (!internalFontName.equals(getData().fontName)) { + getData().fontName = internalFontName; + return true; + } + return false; + } + + /** + * Gets the current font name + * + * @return the current font name + */ + public String getFontName() { + return getData().fontName; + } + + /** + * Gets the current font size + * + * @return the current font size + */ + public int getFontSize() { + return getData().fontSize; + } + + /** + * Set the current font size. + * Check if the font size is a change and then set the current font size. + * + * @param size the font size to set + * @return true if the font size has changed + */ + public boolean setFontSize(int size) { + if (size != getData().fontSize) { + getData().fontSize = size; + return true; + } + return false; + } + + /** + * Set the current line width. + * + * @param width the line width in points + * @return true if the line width has changed + */ + public boolean setLineWidth(float width) { + if (getData().lineWidth != width) { + getData().lineWidth = width; + return true; + } + return false; + } + + /** + * Returns the current line width + * + * @return the current line width + */ + public float getLineWidth() { + return getData().lineWidth; + } + + /** + * Sets the dash array (line type) for the current basic stroke + * + * @param dash the line dash array + * @return true if the dash array has changed + */ + public boolean setDashArray(float[] dash) { + if (!Arrays.equals(dash, getData().dashArray)) { + getData().dashArray = dash; + return true; + } + return false; + } + + /** + * Get the current transform. + * This gets the combination of all transforms in the + * current state. + * + * @return the calculate combined transform for the current state + */ + public AffineTransform getTransform() { + AffineTransform at = new AffineTransform(); + for (Iterator iter = stateStack.iterator(); iter.hasNext();) { + AbstractData data = (AbstractData)iter.next(); + AffineTransform stackTrans = data.getTransform(); + at.concatenate(stackTrans); + } + AffineTransform currentTrans = getData().getTransform(); + at.concatenate(currentTrans); + return at; + } + + /** + * Check the current transform. + * The transform for the current state is the combination of all + * transforms in the current state. The parameter is compared + * against this current transform. + * + * @param tf the transform the check against + * @return true if the new transform is different then the current transform + */ + public boolean checkTransform(AffineTransform tf) { + return !tf.equals(getData().getTransform()); + } + + /** + * Get a copy of the base transform for the page. Used to translate + * IPP/BPP values into X,Y positions when positioning is "fixed". + * + * @return the base transform, or null if the state stack is empty + */ + public AffineTransform getBaseTransform() { + if (stateStack.isEmpty()) { + return null; + } else { + AbstractData baseData = (AbstractData)stateStack.get(0); + return (AffineTransform) baseData.getTransform().clone(); + } + } + + /** + * Concatenates the given AffineTransform to the current one. + * + * @param at the transform to concatenate to the current level transform + */ + public void concatenate(AffineTransform at) { + getData().concatenate(at); + } + + /** + * Resets the current AffineTransform to the Base AffineTransform. + */ + public void resetTransform() { + getData().setTransform(getBaseTransform()); + } + + /** + * Clears the current AffineTransform to the Identity AffineTransform + */ + public void clearTransform() { + getData().clearTransform(); + } + + + /** + * Push the current painting state onto the stack. + * This call should be used when the Q operator is used + * so that the state is known when popped. + */ + public void push() { + AbstractData copy = (AbstractData)getData().clone(); + stateStack.push(copy); + } + + /** + * Pop the painting state from the stack and set current values to popped state. + * This should be called when a Q operator is used so + * the state is restored to the correct values. + * + * @return the restored state, null if the stack is empty + */ + public AbstractData pop() { + if (!stateStack.isEmpty()) { + setData((AbstractData)stateStack.pop()); + return this.data; + } else { + return null; + } + } + + /** + * Pushes all painting state data in the given list to the stack + * + * @param dataList a state data list + */ + public void pushAll(List/**/ dataList) { + Iterator it = dataList.iterator(); + while (it.hasNext()) { + // save current data on stack + push(); + setData((AbstractData)it.next()); + } + } + + /** + * Pops all painting state data from the stack + * + * @return a list of state data popped from the stack + */ + public List/**/ popAll() { + List/**/ dataList = new java.util.ArrayList/**/(); + AbstractData data; + while (true) { + data = getData(); + if (pop() == null) { + break; + } + // insert because of stack-popping + dataList.add(0, data); + } + return dataList; + } + + /** + * Sets the current state data + * + * @param currentData state data + */ + protected void setData(AbstractData data) { + this.data = data; + } + + /** + * Clears the state stack + */ + public void clear() { + stateStack.clear(); + setData(null); + } + + /** + * Return the state stack + * + * @return the state stack + */ + protected Stack/**/ getStateStack() { + return this.stateStack; + } + + /** {@inheritDoc} */ + public Object clone() { + AbstractPaintingState state = instantiate(); + state.stateStack = new StateStack(this.stateStack); + state.data = (AbstractData)this.data.clone(); + return state; + } + + /** {@inheritDoc} */ + public String toString() { + return ", stateStack=" + stateStack + + ", currentData=" + data; + } + + + /** + * A stack implementation which holds state objects + */ + public class StateStack extends java.util.Stack { + + private static final long serialVersionUID = 4897178211223823041L; + + /** + * Default constructor + */ + public StateStack() { + super(); + } + + /** + * Copy constructor + * + * @param c initial contents of stack + */ + public StateStack(Collection c) { + elementCount = c.size(); + // 10% for growth + elementData = new Object[ + (int)Math.min((elementCount * 110L) / 100, Integer.MAX_VALUE)]; + c.toArray(elementData); + } + } + + + /** + * A base painting state data holding object + */ + public abstract class AbstractData implements Cloneable, Serializable { + + private static final long serialVersionUID = 5208418041189828624L; + + /** The current color */ + protected Color color = null; + + /** The current background color */ + protected Color backColor = null; + + /** The current font name */ + protected String fontName = null; + + /** The current font size */ + protected int fontSize = 0; + + /** The current line width */ + protected float lineWidth = 0; + + /** The dash array for the current basic stroke (line type) */ + protected float[] dashArray = null; + + /** The current transform */ + protected AffineTransform transform = null; + + /** + * Returns a newly create data object + * + * @return a new data object + */ + protected abstract AbstractData instantiate(); + + /** + * Concatenate the given AffineTransform with the current thus creating + * a new viewport. Note that all concatenation operations are logged + * so they can be replayed if necessary (ex. for block-containers with + * "fixed" positioning. + * + * @param at Transformation to perform + */ + public void concatenate(AffineTransform at) { + getTransform().concatenate(at); + } + + /** + * Get the current AffineTransform. + * + * @return the current transform + */ + public AffineTransform getTransform() { + if (transform == null) { + transform = new AffineTransform(); + } + return transform; + } + + /** + * Sets the current AffineTransform. + */ + public void setTransform(AffineTransform baseTransform) { + this.transform = baseTransform; + } + + /** + * Resets the current AffineTransform. + */ + public void clearTransform() { + transform = new AffineTransform(); + } + + /** + * Returns the derived rotation from the current transform + * + * @return the derived rotation from the current transform + */ + public int getDerivedRotation() { + AffineTransform at = getTransform(); + double sx = at.getScaleX(); + double sy = at.getScaleY(); + double shx = at.getShearX(); + double shy = at.getShearY(); + int rotation = 0; + if (sx == 0 && sy == 0 && shx > 0 && shy < 0) { + rotation = 270; + } else if (sx < 0 && sy < 0 && shx == 0 && shy == 0) { + rotation = 180; + } else if (sx == 0 && sy == 0 && shx < 0 && shy > 0) { + rotation = 90; + } else { + rotation = 0; + } + return rotation; + } + + /** {@inheritDoc} */ + public Object clone() { + AbstractData data = instantiate(); + data.color = this.color; + data.backColor = this.backColor; + data.fontName = this.fontName; + data.fontSize = this.fontSize; + data.lineWidth = this.lineWidth; + data.dashArray = this.dashArray; + data.transform = new AffineTransform(this.transform); + return data; + } + + /** {@inheritDoc} */ + public String toString() { + return "color=" + color + + ", backColor=" + backColor + + ", fontName=" + fontName + + ", fontSize=" + fontSize + + ", lineWidth=" + lineWidth + + ", dashArray=" + dashArray + + ", transform=" + transform; + } + } +}