import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.fop.afp.goca.GraphicsSetLineType;
-import org.apache.fop.afp.modca.GraphicsObject;
-import org.apache.fop.afp.svg.AFPGraphicsConfiguration;
-import org.apache.fop.fonts.FontInfo;
-import org.apache.fop.svg.NativeImageHandler;
+
import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageSize;
import org.apache.xmlgraphics.image.loader.impl.ImageRendered;
import org.apache.xmlgraphics.java2d.TextHandler;
import org.apache.xmlgraphics.ps.ImageEncodingHelper;
import org.apache.xmlgraphics.util.MimeConstants;
+import org.apache.xmlgraphics.util.UnitConv;
+
+import org.apache.fop.afp.goca.GraphicsSetLineType;
+import org.apache.fop.afp.modca.GraphicsObject;
+import org.apache.fop.afp.svg.AFPGraphicsConfiguration;
+import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.svg.NativeImageHandler;
/**
* This is a concrete implementation of <tt>AbstractGraphics2D</tt> (and
this.gc = gc;
}
+ private int getResolution() {
+ return this.paintingState.getResolution();
+ }
+
+ /**
+ * Converts a length value to an absolute value.
+ * Please note that this only uses the "ScaleY" factor, so this will result
+ * in a bad value should "ScaleX" and "ScaleY" be different.
+ * @param length the length
+ * @return the absolute length
+ */
+ public double convertToAbsoluteLength(double length) {
+ AffineTransform current = getTransform();
+ double mult = getResolution() / (double)UnitConv.IN2PT;
+ double factor = -current.getScaleY() / mult;
+ return length * factor;
+ }
+
+ /** IBM's AFP Workbench paints lines that are wider than expected. We correct manually. */
+ private static final double GUESSED_WIDTH_CORRECTION = 1.7;
+
+ private static final double SPEC_NORMAL_LINE_WIDTH = UnitConv.in2pt(0.01); //"approx" 0.01 inch
+ private static final double NORMAL_LINE_WIDTH
+ = SPEC_NORMAL_LINE_WIDTH * GUESSED_WIDTH_CORRECTION;
+
+
/**
* Apply the stroke to the AFP graphics object.
* This takes the java stroke and outputs the appropriate settings
// set line width
float lineWidth = basicStroke.getLineWidth();
- graphicsObj.setLineWidth(Math.round(lineWidth / 2));
+ if (false) {
+ //Old approach. Retained until verified problems with 1440 resolution
+ graphicsObj.setLineWidth(Math.round(lineWidth / 2));
+ } else {
+ double absoluteLineWidth = lineWidth * Math.abs(getTransform().getScaleY());
+ double multiplier = absoluteLineWidth / NORMAL_LINE_WIDTH;
+ graphicsObj.setLineWidth((int)Math.round(multiplier));
+ //TODO Use GSFLW instead of GSLW for higher accuracy?
+ }
+
+ //No line join, miter limit and end cap support in GOCA. :-(
// set line type/style (note: this is an approximation at best!)
float[] dashArray = basicStroke.getDashArray();
return this.paintingState;
}
- /**
- * Sets the FontInfo
- *
- * @param the FontInfo
- */
- public void setFontInfo(FontInfo fontInfo) {
- this.fontInfo = fontInfo;
- }
-
/**
* Returns the FontInfo
*
/** {@inheritDoc} */
public void addNativeImage(org.apache.xmlgraphics.image.loader.Image image,
float x, float y, float width, float height) {
- log.debug("NYI: addNativeImage() "+ "image=" + image
+ log.debug("NYI: addNativeImage() " + "image=" + image
+ ",x=" + x + ",y=" + y + ",width=" + width + ",height=" + height);
}
}
/**
- * Sets whether the following shape is to be filled
+ * Sets whether the following shape is to be filled.
*
* @param fill true if the following shape is to be filled
*/
public void setFill(boolean fill) {
- setPatternSymbol(fill ?
- GraphicsSetPatternSymbol.SOLID_FILL :
- GraphicsSetPatternSymbol.NO_FILL);
+ setPatternSymbol(fill
+ ? GraphicsSetPatternSymbol.SOLID_FILL
+ : GraphicsSetPatternSymbol.NO_FILL);
}
/**
- * Sets the fill pattern of the next shape
+ * Sets the fill pattern of the next shape.
*
- * @param the fill pattern of the next shape
+ * @param patternSymbol the fill pattern of the next shape
*/
public void setPatternSymbol(byte patternSymbol) {
if (patternSymbol != graphicsState.patternSymbol) {
*/
public void newSegment() {
getData().newSegment();
+ graphicsState.lineWidth = 0; //Looks like a new segment invalidates the graphics state
}
/** {@inheritDoc} */
}
/** the internal graphics state */
- private class GraphicsState {
+ private static class GraphicsState {
/** the current color */
private Color color;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.apache.fop.afp.AFPGraphics2D;
import org.apache.fop.afp.AFPPaintingState;
import org.apache.fop.afp.fonts.AFPFont;
* @return a font reference
*/
private int registerPageFont(AFPPageFonts pageFonts, String internalFontName, int fontSize) {
- FontInfo fontInfo = getFontInfo();
AFPFont afpFont = (AFPFont)fontInfo.getFonts().get(internalFontName);
// register if necessary
AFPFontAttributes afpFontAttributes = pageFonts.registerFont(
* {@inheritDoc}
*/
public void drawString(Graphics2D g, String str, float x, float y) throws IOException {
- log.debug("drawString() str=" + str + ", x=" + x + ", y=" + y);
- AFPGraphics2D g2d = (AFPGraphics2D)g;
- GraphicsObject graphicsObj = g2d.getGraphicsObject();
- Color color = g2d.getColor();
-
- // set the color
- AFPPaintingState paintingState = g2d.getPaintingState();
- if (paintingState.setColor(color)) {
- graphicsObj.setColor(color);
+ if (log.isDebugEnabled()) {
+ log.debug("drawString() str=" + str + ", x=" + x + ", y=" + y);
}
-
- // set the character set
- int fontReference = 0;
- AFPPageFonts pageFonts = paintingState.getPageFonts();
- if (overrideFont != null) {
- String internalFontName = overrideFont.getFontName();
- int fontSize = overrideFont.getFontSize();
+ if (g instanceof AFPGraphics2D) {
+ AFPGraphics2D g2d = (AFPGraphics2D)g;
+ GraphicsObject graphicsObj = g2d.getGraphicsObject();
+ Color color = g2d.getColor();
+
+ // set the color
+ AFPPaintingState paintingState = g2d.getPaintingState();
+ if (paintingState.setColor(color)) {
+ graphicsObj.setColor(color);
+ }
+
+ // set the character set
+ int fontReference = 0;
+ int fontSize;
+ String internalFontName;
+ AFPPageFonts pageFonts = paintingState.getPageFonts();
+ if (overrideFont != null) {
+ internalFontName = overrideFont.getFontName();
+ fontSize = overrideFont.getFontSize();
+ } else {
+ java.awt.Font awtFont = g2d.getFont();
+ Font fopFont = fontInfo.getFontInstanceForAWTFont(awtFont);
+ internalFontName = fopFont.getFontName();
+ fontSize = fopFont.getFontSize();
+ }
+ fontSize = (int)Math.round(
+ g2d.convertToAbsoluteLength(fontSize));
fontReference = registerPageFont(pageFonts, internalFontName, fontSize);
+ graphicsObj.setCharacterSet(fontReference);
+
+ // add the character string
+ graphicsObj.addString(str, Math.round(x), Math.round(y));
} else {
- java.awt.Font awtFont = g2d.getFont();
-// AffineTransform fontTransform = awtFont.getTransform();
- FontInfo fontInfo = getFontInfo();
- Font fopFont = fontInfo.getFontInstanceForAWTFont(awtFont);
- String internalFontName = fopFont.getFontName();
- int fontSize = fopFont.getFontSize();
- fontReference = registerPageFont(pageFonts, internalFontName, fontSize);
+ //Inside Batik's SVG filter operations, you won't get an AFPGraphics2D
+ g.drawString(str, x, y);
}
- graphicsObj.setCharacterSet(fontReference);
-
- // add the character string
- graphicsObj.addString(str, Math.round(x), Math.round(y));
}
/**
package org.apache.fop.afp.svg;
+import java.awt.Graphics2D;
+
+import org.apache.fop.afp.AFPGraphics2D;
import org.apache.fop.svg.AbstractFOPTextPainter;
import org.apache.fop.svg.FOPTextHandler;
super(nativeTextHandler);
}
+ /** {@inheritDoc} */
+ protected boolean isSupportedGraphics2D(Graphics2D g2d) {
+ return g2d instanceof AFPGraphics2D;
+ }
+
}