diff options
Diffstat (limited to 'src/java/org')
61 files changed, 5325 insertions, 1235 deletions
diff --git a/src/java/org/apache/fop/render/afp/AFPGraphics2D.java b/src/java/org/apache/fop/render/afp/AFPGraphics2D.java new file mode 100644 index 000000000..bdd33f3de --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPGraphics2D.java @@ -0,0 +1,501 @@ +/* + * 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.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ImageObserver; +import java.awt.image.RenderedImage; +import java.awt.image.renderable.RenderableImage; +import java.io.IOException; + +import org.apache.batik.ext.awt.geom.ExtendedGeneralPath; +import org.apache.commons.io.output.ByteArrayOutputStream; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.render.afp.modca.AFPDataStream; +import org.apache.fop.render.afp.modca.GraphicsObject; +import org.apache.fop.render.afp.modca.ImageObject; +import org.apache.fop.render.afp.modca.goca.GraphicsSetLineType; +import org.apache.xmlgraphics.java2d.AbstractGraphics2D; +import org.apache.xmlgraphics.java2d.GraphicContext; +import org.apache.xmlgraphics.java2d.StrokingTextHandler; +import org.apache.xmlgraphics.java2d.TextHandler; + +/** + * This is a concrete implementation of <tt>AbstractGraphics2D</tt> (and + * therefore of <tt>Graphics2D</tt>) which is able to generate GOCA byte + * codes. + * + * @see org.apache.xmlgraphics.java2d.AbstractGraphics2D + */ +public class AFPGraphics2D extends AbstractGraphics2D { + + private static final Log log = LogFactory.getLog(AFPGraphics2D.class); + + private GraphicsObject graphicsObj = null; + + /** Fallback text handler */ + protected TextHandler fallbackTextHandler = new StrokingTextHandler(this); + + /** Custom text handler */ + protected TextHandler customTextHandler = null; + + /** AFP info */ + private AFPInfo afpInfo = null; + + /** Current AFP state */ + private AFPState afpState = null; + + /** + * @param textAsShapes + * if true, all text is turned into shapes in the convertion. No + * text is output. + * + */ + public AFPGraphics2D(boolean textAsShapes) { + super(textAsShapes); + } + + /** + * Creates a new AbstractGraphics2D from an existing instance. + * + * @param g + * the AbstractGraphics2D whose properties should be copied + */ + public AFPGraphics2D(AFPGraphics2D g) { + super(g); + } + + /** + * Sets the AFPInfo + * + * @param info + * the AFP Info to use + */ + public void setAFPInfo(AFPInfo info) { + this.afpInfo = info; + this.afpState = info.getState(); + } + + /** + * Gets the AFPInfo + * + * @return the AFPInfo + */ + public AFPInfo getAFPInfo() { + return this.afpInfo; + } + + /** + * Sets the GraphicContext + * + * @param gc + * GraphicContext to use + */ + public void setGraphicContext(GraphicContext gc) { + this.gc = gc; + } + + /** + * Apply the stroke to the AFP graphics object. + * This takes the java stroke and outputs the appropriate settings + * to the AFP graphics object so that the stroke attributes are handled. + * + * @param stroke the java stroke + */ + protected void applyStroke(Stroke stroke) { + if (stroke instanceof BasicStroke) { + BasicStroke basicStroke = (BasicStroke) stroke; + float lineWidth = basicStroke.getLineWidth(); + if (afpState.setLineWidth(lineWidth)) { + getGraphicsObject().setLineWidth(Math.round(lineWidth * 2)); + } + // note: this is an approximation at best! + float[] dashArray = basicStroke.getDashArray(); + if (afpState.setDashArray(dashArray)) { + byte type = GraphicsSetLineType.DEFAULT; // normally SOLID + if (dashArray != null) { + type = GraphicsSetLineType.DOTTED; // default to DOTTED + // float offset = basicStroke.getDashPhase(); + if (dashArray.length == 2) { + if (dashArray[0] < dashArray[1]) { + type = GraphicsSetLineType.SHORT_DASHED; + } else if (dashArray[0] > dashArray[1]) { + type = GraphicsSetLineType.LONG_DASHED; + } + } else if (dashArray.length == 4) { + if (dashArray[0] > dashArray[1] + && dashArray[2] < dashArray[3]) { + type = GraphicsSetLineType.DASH_DOT; + } else if (dashArray[0] < dashArray[1] + && dashArray[2] < dashArray[3]) { + type = GraphicsSetLineType.DOUBLE_DOTTED; + } + } else if (dashArray.length == 6) { + if (dashArray[0] > dashArray[1] + && dashArray[2] < dashArray[3] + && dashArray[4] < dashArray[5]) { + type = GraphicsSetLineType.DASH_DOUBLE_DOTTED; + } + } + } + getGraphicsObject().setLineType(type); + } + } else { + log.warn("Unsupported Stroke: " + stroke.getClass().getName()); + } + } + + /** + * Handle the Batik drawing event + * + * @param shape + * the shape to draw + * @param fill + * true if the shape is to be drawn filled + */ + private void doDrawing(Shape shape, boolean fill) { + getGraphicsObject(); + if (!fill) { + graphicsObj.newSegment(); + } + Color col = getColor(); + if (afpState.setColor(col)) { + graphicsObj.setColor(col); + } + + applyStroke(getStroke()); + + if (fill) { + graphicsObj.beginArea(); + } + AffineTransform trans = super.getTransform(); + PathIterator iter = shape.getPathIterator(trans); + double[] vals = new double[6]; + int[] coords = null; + if (shape instanceof GeneralPath || shape instanceof ExtendedGeneralPath) { + // graphics segment opening coordinates (x,y) + int[] openingCoords = new int[2]; + // current position coordinates (x,y) + int[] currCoords = new int[2]; + NEXT_ITER: while (!iter.isDone()) { + // round the coordinate values and combine with current position + // coordinates + int type = iter.currentSegment(vals); + if (type == PathIterator.SEG_MOVETO) { + log.debug("SEG_MOVETO"); + openingCoords[0] = currCoords[0] = (int)Math.round(vals[0]); + openingCoords[1] = currCoords[1] = (int)Math.round(vals[1]); + } else { + int numCoords; + if (type == PathIterator.SEG_LINETO) { + log.debug("SEG_LINETO"); + numCoords = 2; + } else if (type == PathIterator.SEG_QUADTO) { + log.debug("SEG_QUADTO"); + numCoords = 4; + } else if (type == PathIterator.SEG_CUBICTO) { + log.debug("SEG_CUBICTO"); + numCoords = 6; + } else { + // close of the graphics segment + if (type == PathIterator.SEG_CLOSE) { + log.debug("SEG_CLOSE"); + coords = new int[] { + coords[coords.length - 2], + coords[coords.length - 1], + openingCoords[0], + openingCoords[1] + }; + graphicsObj.addLine(coords); + } else { + log.debug("Unrecognised path iterator type: " + + type); + } + iter.next(); + continue NEXT_ITER; + } + // combine current position coordinates with new graphics + // segment coordinates + coords = new int[numCoords + 2]; + coords[0] = currCoords[0]; + coords[1] = currCoords[1]; + for (int i = 0; i < numCoords; i++) { + coords[i + 2] = (int) Math.round(vals[i]); + } + if (type == PathIterator.SEG_LINETO) { + graphicsObj.addLine(coords); + } else if (type == PathIterator.SEG_QUADTO + || type == PathIterator.SEG_CUBICTO) { + graphicsObj.addFillet(coords); + } + // update current position coordinates + currCoords[0] = coords[coords.length - 2]; + currCoords[1] = coords[coords.length - 1]; + } + iter.next(); + } + } else if (shape instanceof Line2D) { + iter.currentSegment(vals); + coords = new int[4]; + coords[0] = (int) Math.round(vals[0]); + coords[1] = (int) Math.round(vals[1]); + iter.next(); + iter.currentSegment(vals); + coords[2] = (int) Math.round(vals[0]); + coords[3] = (int) Math.round(vals[1]); + graphicsObj.addLine(coords); + } else if (shape instanceof Rectangle2D) { + iter.currentSegment(vals); + coords = new int[4]; + coords[2] = (int) Math.round(vals[0]); + coords[3] = (int) Math.round(vals[1]); + iter.next(); + iter.next(); + iter.currentSegment(vals); + coords[0] = (int) Math.round(vals[0]); + coords[1] = (int) Math.round(vals[1]); + graphicsObj.addBox(coords); + } else if (shape instanceof Ellipse2D) { + Ellipse2D elip = (Ellipse2D) shape; + final double factor = afpInfo.resolution / 100f; + graphicsObj.setArcParams( + (int)Math.round(elip.getWidth() * factor), + (int)Math.round(elip.getHeight() * factor), + 0, + 0 + ); + trans.transform( + new double[] {elip.getCenterX(), elip.getCenterY()}, 0, + vals, 0, 1); + final int mh = 1; + final int mhr = 0; + graphicsObj.addFullArc( + (int)Math.round(vals[0]), + (int)Math.round(vals[1]), + mh, + mhr + ); + } else { + log.error("Unrecognised shape: " + shape); + } + if (fill) { + graphicsObj.endArea(); + } + } + + /** + * {@inheritDoc} + */ + public void draw(Shape shape) { + log.debug("draw() shape=" + shape); + doDrawing(shape, false); + } + + /** + * {@inheritDoc} + */ + public void fill(Shape shape) { + log.debug("fill() shape=" + shape); + doDrawing(shape, true); + } + + /** + * Central handler for IOExceptions for this class. + * + * @param ioe + * IOException to handle + */ + public void handleIOException(IOException ioe) { + // TODO Surely, there's a better way to do this. + ioe.printStackTrace(); + } + + /** + * {@inheritDoc} + */ + public void drawRenderableImage(RenderableImage img, AffineTransform xform) { + log.debug("drawRenderableImage() NYI: img=" + img + ", xform=" + xform); + } + + /** + * {@inheritDoc} + */ + public void drawRenderedImage(RenderedImage img, AffineTransform xform) { + log.debug("drawRenderedImage() NYI: img=" + img + ", xform=" + xform); + } + + /** + * {@inheritDoc} + */ + public void drawString(String s, float x, float y) { + try { + if (customTextHandler != null && !textAsShapes) { + customTextHandler.drawString(s, x, y); + } else { + fallbackTextHandler.drawString(s, x, y); + } + } catch (IOException ioe) { + handleIOException(ioe); + } + } + + /** + * {@inheritDoc} + */ + public GraphicsConfiguration getDeviceConfiguration() { + return new AFPGraphicsConfiguration(); + } + + /** + * {@inheritDoc} + */ + public void copyArea(int x, int y, int width, int height, int dx, int dy) { + log.debug("copyArea() NYI: "); + } + + /** + * {@inheritDoc} + */ + public Graphics create() { + return new AFPGraphics2D(this); + } + + /** + * {@inheritDoc} + */ + public void dispose() { + log.debug("dispose() NYI: "); + } + + /** + * {@inheritDoc} + */ + public boolean drawImage(Image img, int x, int y, ImageObserver observer) { + return drawImage(img, x, y, img.getWidth(observer), img.getHeight(observer), observer); + } + + /** + * {@inheritDoc} + */ + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) { + log.debug("drawImage() img=" + img + ", x=" + x + ", y=" + y + + ", width=" + width + ", height=" + height + ", obs=" + observer); + + int afpres = afpInfo.resolution; + int afpBitsPerPixel = afpInfo.bitsPerPixel; + int afpx = x; + int afpy = y; + int afpw = width; + int afph = height; + boolean colorImages = !afpInfo.grayscale; + int imageResolution = afpres; + if (img instanceof BufferedImage) { + BufferedImage bi = (BufferedImage)img; + ByteArrayOutputStream baout = new ByteArrayOutputStream(); + try { + // Serialize image + AFPRenderer.writeImage(bi, baout); + byte[] buf = baout.toByteArray(); + + // Generate image + AFPDataStream afpDataStream = afpInfo.afpDataStream; + ImageObject io = afpDataStream.getImageObject(afpx, afpy, afpw, + afph, afpres, afpres); + io.setImageParameters(imageResolution, imageResolution, + afpw, afph); + if (colorImages) { + io.setImageIDESize((byte)24); + io.setImageData(buf); + } else { + AFPRenderer.convertToGrayScaleImage(io, buf, afpw, afph, afpBitsPerPixel); + } + } catch (IOException ioe) { + log.error("Error while serializing bitmap: " + ioe.getMessage(), + ioe); + return false; + } + return true; + } else { + log.debug("drawImage() NYI: img=" + img + ", x=" + x + ", y=" + y + + ", observer=" + observer); + } + return false; + } + + /** + * {@inheritDoc} + */ + public FontMetrics getFontMetrics(Font f) { + log.debug("getFontMetrics() NYI: f=" + f); + return null; + } + + /** + * {@inheritDoc} + */ + public void setXORMode(Color col) { + log.debug("setXORMode() NYI: col=" + col); + } + + /** + * Sets a custom TextHandler implementation that is responsible for painting + * text. The default TextHandler paints all text as shapes. A custom + * implementation can implement text painting using text painting operators. + * + * @param handler + * the custom TextHandler implementation + */ + public void setCustomTextHandler(TextHandler handler) { + this.customTextHandler = handler; + } + + /** + * @return the GOCA graphics object + */ + protected GraphicsObject getGraphicsObject() { + if (this.graphicsObj == null) { + int x = (int)Math.round((afpInfo.currentXPosition * 25.4f) / 1000); + int y = (int)Math.round((afpInfo.currentYPosition * 25.4f) / 1000); + int res = afpInfo.resolution; + int width = (int)Math.round((afpInfo.width * res) / 72000f); + int height = (int)Math.round((afpInfo.height * res) / 72000f); + this.graphicsObj = afpInfo.getAFPDataStream().getGraphicsObject( + x, y, width, height, res, res); + } + return this.graphicsObj; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/AFPGraphicsConfiguration.java b/src/java/org/apache/fop/render/afp/AFPGraphicsConfiguration.java new file mode 100644 index 000000000..086308975 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPGraphicsConfiguration.java @@ -0,0 +1,155 @@ +/* + * 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.GraphicsDevice; +import java.awt.Rectangle; +import java.awt.Transparency; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.svg.GraphicsConfiguration; + +/** + * Our implementation of the class that returns information about + * roughly what we can handle and want to see (alpha for example). + */ +public class AFPGraphicsConfiguration extends GraphicsConfiguration { + // We use this to get a good colormodel.. + private static final BufferedImage BI_WITH_ALPHA + = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); + // We use this to get a good colormodel.. + private static final BufferedImage BI_WITHOUT_ALPHA + = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); + + /** + * Construct a buffered image with an alpha channel, unless + * transparencty is OPAQUE (no alpha at all). + * + * @param width the width of the image + * @param height the height of the image + * @param transparency the alpha value of the image + * @return the new buffered image + */ + public BufferedImage createCompatibleImage(int width, int height, + int transparency) { + if (transparency == Transparency.OPAQUE) { + return new BufferedImage(width, height, + BufferedImage.TYPE_INT_RGB); + } else { + return new BufferedImage(width, height, + BufferedImage.TYPE_INT_ARGB); + } + } + + /** + * Construct a buffered image with an alpha channel. + * + * @param width the width of the image + * @param height the height of the image + * @return the new buffered image + */ + public BufferedImage createCompatibleImage(int width, int height) { + return new BufferedImage(width, height, + BufferedImage.TYPE_INT_ARGB); + } + + /** + * TODO: This should return the page bounds in Pts, + * I couldn't figure out how to get this for the current + * page from the PDFDocument (this still works for now, + * but it should be fixed...). + * + * @return the bounds of the PDF document page + */ + public Rectangle getBounds() { + return null; + } + + /** + * Return a good default color model for this 'device'. + * @return the colour model for the configuration + */ + public ColorModel getColorModel() { + return BI_WITH_ALPHA.getColorModel(); + } + + /** + * Return a good color model given <tt>transparency</tt> + * + * @param transparency the alpha value for the colour model + * @return the colour model for the configuration + */ + public ColorModel getColorModel(int transparency) { + if (transparency == Transparency.OPAQUE) { + return BI_WITHOUT_ALPHA.getColorModel(); + } else { + return BI_WITH_ALPHA.getColorModel(); + } + } + + private static final Log log = LogFactory.getLog(AFPGraphicsConfiguration.class); + + private AffineTransform defaultTransform = null; + private AffineTransform normalizingTransform = null; + private GraphicsDevice graphicsDevice = null; + + /** + * The default transform (1:1). + * + * @return the default transform for the configuration + */ + public AffineTransform getDefaultTransform() { + log.debug("getDefaultTransform()"); + if (defaultTransform == null) { + defaultTransform = new AffineTransform(); + } + return defaultTransform; + } + + /** + * The normalizing transform (1:1) (since we currently + * render images at 72dpi, which we might want to change + * in the future). + * + * @return the normalizing transform for the configuration + */ + public AffineTransform getNormalizingTransform() { + log.debug("getNormalizingTransform()"); + if (normalizingTransform == null) { + normalizingTransform = new AffineTransform(2, 0, 0, 2, 0, 0); + } + return normalizingTransform; + } + + /** + * {@inheritDoc} + */ + public GraphicsDevice getDevice() { + log.debug("getDevice()"); + if (graphicsDevice == null) { + graphicsDevice = new AFPGraphicsDevice(this); + } + return graphicsDevice; + } +} diff --git a/src/java/org/apache/fop/render/afp/AFPGraphicsDevice.java b/src/java/org/apache/fop/render/afp/AFPGraphicsDevice.java new file mode 100644 index 000000000..dd31af9f1 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPGraphicsDevice.java @@ -0,0 +1,80 @@ +/* + * 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.GraphicsConfiguration; +import java.awt.GraphicsDevice; + +/** + * This implements the GraphicsDevice interface as appropriate for + * an AFPGraphics2D. + */ +public class AFPGraphicsDevice extends GraphicsDevice { + + /** + * The Graphics Config that created us... + */ + protected GraphicsConfiguration gc; + + /** + * Create a new AF{ graphics device. + * + * @param gc The graphics configuration we should reference + */ + public AFPGraphicsDevice(AFPGraphicsConfiguration gc) { + this.gc = gc; + } + + /** + * Return an array of our one GraphicsConfig + * + * @return an array containing the one graphics configuration + */ + public GraphicsConfiguration[] getConfigurations() { + return new GraphicsConfiguration[] {gc}; + } + + /** + * Return out sole GraphicsConfig. + * + * @return the graphics configuration that created this object + */ + public GraphicsConfiguration getDefaultConfiguration() { + return this.gc; + } + + /** + * Generate an IdString.. + * + * @return the ID string for this device, uses toString + */ + public String getIDstring() { + return toString(); + } + + /** + * Let the caller know that we are "a printer" + * + * @return the type which is always printer + */ + public int getType() { + return GraphicsDevice.TYPE_PRINTER; + } +} diff --git a/src/java/org/apache/fop/render/afp/AFPInfo.java b/src/java/org/apache/fop/render/afp/AFPInfo.java new file mode 100644 index 000000000..cd291da56 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPInfo.java @@ -0,0 +1,120 @@ +/* + * 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 org.apache.avalon.framework.configuration.Configuration; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.render.afp.modca.AFPDataStream; + +/** + * AFP information structure for drawing the XML document. + */ +public final class AFPInfo { + /** see WIDTH */ + protected int width; + /** see HEIGHT */ + protected int height; + /** see XPOS */ + protected int currentXPosition; + /** see YPOS */ + protected int currentYPosition; + /** see HANDLER_CONFIGURATION */ + protected Configuration cfg; + + /** see AFP_FONT_INFO */ + protected FontInfo fontInfo; + /** See AFP_DATASTREAM */ + protected AFPDataStream afpDataStream; + /** See AFP_STATE */ + protected AFPState afpState; + /** see AFP_GRAYSCALE */ + protected boolean grayscale; + /** see AFP_RESOLUTION */ + protected int resolution; + /** see AFP_BITS_PER_PIXEL */ + protected int bitsPerPixel; + + /** + * Returns the width. + * @return the width + */ + public int getWidth() { + return width; + } + + /** + * Sets the width. + * @param width The pageWidth to set + */ + public void setWidth(int width) { + this.width = width; + } + + /** + * Returns the height. + * @return the height + */ + public int getHeight() { + return height; + } + + /** + * Sets the height. + * @param height The height to set + */ + public void setHeight(int height) { + this.height = height; + } + + /** + * @return Configuration the handler configuration + */ + public Configuration getHandlerConfiguration() { + return this.cfg; + } + + /** + * @return FontInfo the font info + */ + public FontInfo getFontInfo() { + return this.fontInfo; + } + + /** + * @return Map the current page fonts + */ + public AFPState getState() { + return this.afpState; + } + + /** + * @return AFPDataStream the afp datastream + */ + public AFPDataStream getAFPDataStream() { + return this.afpDataStream; + } + + /** + * @return true if supports color + */ + public boolean isColorSupported() { + return !this.grayscale; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/AFPPageFonts.java b/src/java/org/apache/fop/render/afp/AFPPageFonts.java new file mode 100644 index 000000000..1ca38a58f --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPPageFonts.java @@ -0,0 +1,48 @@ +/* + * 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 org.apache.fop.render.afp.fonts.AFPFont; + +/** + * Holds the current page fonts + */ +public class AFPPageFonts extends java.util.HashMap { + private static final long serialVersionUID = -4991896259427109041L; + + /** + * Registers a font on the current page and returns font attributes + * @param fontName the internal font name + * @param font the AFPFont + * @param fontSize the font point size + * @return newly registered AFPFontAttributes + */ + public AFPFontAttributes registerFont(String fontName, AFPFont font, int fontSize) { + String pageFontKey = fontName + "_" + fontSize; + AFPFontAttributes afpFontAttributes = (AFPFontAttributes)super.get(pageFontKey); + // Add to page font mapping if not already present + if (afpFontAttributes == null) { + afpFontAttributes = new AFPFontAttributes(fontName, font, fontSize); + super.put(pageFontKey, afpFontAttributes); + afpFontAttributes.setFontReference(super.size()); + } + return afpFontAttributes; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/AFPRenderer.java b/src/java/org/apache/fop/render/afp/AFPRenderer.java index 3a228e172..de414fa10 100644 --- a/src/java/org/apache/fop/render/afp/AFPRenderer.java +++ b/src/java/org/apache/fop/render/afp/AFPRenderer.java @@ -124,23 +124,28 @@ import org.w3c.dom.Document; * handle all types of inline area, text, image etc and draws various lines and * rectangles. * </p> - * - * Note: There are specific extensions that have been added to the - * FO. They are specific to their location within the FO and have to be - * processed accordingly (ie. at the start or end of the page). - * + * + * Note: There are specific extensions that have been added to the FO. They are + * specific to their location within the FO and have to be processed accordingly + * (ie. at the start or end of the page). + * */ public class AFPRenderer extends AbstractPathOrientedRenderer { /** - * The default afp renderer output resolution + * 2400 dpi renderer resolution + */ + protected static final int DPI_240_RESOLUTION = 240; + + /** + * 14400 dpi renderer resolution */ - private static final int DEFAULT_DPI_RESOLUTION = 240; + protected static final int DPI_1440_RESOLUTION = 1440; /** * The afp factor for calculating resolutions (e.g. 72000/240 = 300) */ - private static final int DPI_CONVERSION_FACTOR = 72000; + protected static final int DPI_CONVERSION_FACTOR = 72000; /** * The afp data stream object responsible for generating afp data @@ -148,46 +153,11 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { private AFPDataStream afpDataStream = null; /** - * The map of afp root extensions - */ - // UNUSED - // private HashMap rootExtensionMap = null; - /** * The map of page segments */ - private HashMap pageSegmentsMap = null; - - /** - * The fonts on the current page - */ - private HashMap currentPageFonts = null; - - /** - * The current color object - */ - private Color currentColor = null; - - /** - * The page font number counter, used to determine the next font reference - */ - private int pageFontCounter = 0; + private Map pageSegmentsMap = null; /** - * The current font family - */ - // UNUSED - // private String currentFontFamily = ""; - /** - * The current font size - */ - private int currentFontSize = 0; - - /** - * The Options to be set on the AFPRenderer - */ - // UNUSED - // private Map afpOptions = null; - /** * The page width */ private int pageWidth = 0; @@ -198,11 +168,6 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { private int pageHeight = 0; /** - * The current page sequence id - */ - // UNUSED - // private String pageSequenceId = null; - /** * The portrait rotation */ private int portraitRotation = 0; @@ -213,21 +178,6 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { private int landscapeRotation = 270; /** - * The line cache, avoids drawing duplicate lines in tables. - */ - // UNUSED - // private HashSet lineCache = null; - /** - * The current x position for line drawing - */ - // UNUSED - // private float x; - /** - * The current y position for line drawing - */ - // UNUSED - // private float y; - /** * The map of saved incomplete pages */ private Map pages = null; @@ -245,7 +195,10 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { /** * The output resolution */ - private int resolution = DEFAULT_DPI_RESOLUTION; + private int resolution = DPI_240_RESOLUTION; + + /** drawing state */ + protected AFPState currentState = null; /** * Constructor for AFPRenderer. @@ -256,20 +209,22 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { /** * Set up the font info - * - * @param inFontInfo font info to set up + * + * @param inFontInfo + * font info to set up */ public void setupFontInfo(FontInfo inFontInfo) { this.fontInfo = inFontInfo; int num = 1; if (this.fontList != null && this.fontList.size() > 0) { for (Iterator it = this.fontList.iterator(); it.hasNext();) { - AFPFontInfo afi = (AFPFontInfo)it.next(); - AFPFont bf = (AFPFont)afi.getAFPFont(); - for (Iterator it2 = afi.getFontTriplets().iterator(); it2.hasNext();) { - FontTriplet ft = (FontTriplet)it2.next(); - this.fontInfo.addFontProperties("F" + num, ft.getName() - , ft.getStyle(), ft.getWeight()); + AFPFontInfo afi = (AFPFontInfo) it.next(); + AFPFont bf = (AFPFont) afi.getAFPFont(); + for (Iterator it2 = afi.getFontTriplets().iterator(); it2 + .hasNext();) { + FontTriplet ft = (FontTriplet) it2.next(); + this.fontInfo.addFontProperties("F" + num, ft.getName(), ft + .getStyle(), ft.getWeight()); this.fontInfo.addMetrics("F" + num, bf); num++; } @@ -278,33 +233,36 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { log.warn("No AFP fonts configured - using default setup"); } if (this.fontInfo.fontLookup("sans-serif", "normal", 400) == null) { - CharacterSet cs = new FopCharacterSet("T1V10500", "Cp500", "CZH200 ", - 1, new Helvetica()); + CharacterSet cs = new FopCharacterSet("T1V10500", "Cp500", + "CZH200 ", 1, new Helvetica()); AFPFont bf = new OutlineFont("Helvetica", cs); - this.fontInfo.addFontProperties("F" + num, "sans-serif", "normal", 400); + this.fontInfo.addFontProperties("F" + num, "sans-serif", "normal", + 400); this.fontInfo.addMetrics("F" + num, bf); num++; } if (this.fontInfo.fontLookup("serif", "normal", 400) == null) { - CharacterSet cs = new FopCharacterSet("T1V10500", "Cp500", "CZN200 ", - 1, new TimesRoman()); + CharacterSet cs = new FopCharacterSet("T1V10500", "Cp500", + "CZN200 ", 1, new TimesRoman()); AFPFont bf = new OutlineFont("Helvetica", cs); this.fontInfo.addFontProperties("F" + num, "serif", "normal", 400); this.fontInfo.addMetrics("F" + num, bf); num++; } if (this.fontInfo.fontLookup("monospace", "normal", 400) == null) { - CharacterSet cs = new FopCharacterSet("T1V10500", "Cp500", "CZ4200 ", - 1, new Courier()); + CharacterSet cs = new FopCharacterSet("T1V10500", "Cp500", + "CZ4200 ", 1, new Courier()); AFPFont bf = new OutlineFont("Helvetica", cs); - this.fontInfo.addFontProperties("F" + num, "monospace", "normal", 400); + this.fontInfo.addFontProperties("F" + num, "monospace", "normal", + 400); this.fontInfo.addMetrics("F" + num, bf); num++; } if (this.fontInfo.fontLookup("any", "normal", 400) == null) { - FontTriplet ft = this.fontInfo.fontLookup("sans-serif", "normal", 400); - this.fontInfo.addFontProperties( - this.fontInfo.getInternalFontKey(ft), "any", "normal", 400); + FontTriplet ft = this.fontInfo.fontLookup("sans-serif", "normal", + 400); + this.fontInfo.addFontProperties(this.fontInfo + .getInternalFontKey(ft), "any", "normal", 400); } } @@ -319,57 +277,49 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { * {@inheritDoc} */ public void startRenderer(OutputStream outputStream) throws IOException { - currentPageFonts = new HashMap(); - currentColor = new Color(255, 255, 255); - afpDataStream = new AFPDataStream(); - afpDataStream.setPortraitRotation(portraitRotation); - afpDataStream.setLandscapeRotation(landscapeRotation); - afpDataStream.startDocument(outputStream); + this.currentState = new AFPState(); + this.afpDataStream = new AFPDataStream(); + this.afpDataStream.setPortraitRotation(portraitRotation); + this.afpDataStream.setLandscapeRotation(landscapeRotation); + this.afpDataStream.startDocument(outputStream); } /** * {@inheritDoc} */ public void stopRenderer() throws IOException { - afpDataStream.endDocument(); + this.afpDataStream.endDocument(); } /** * {@inheritDoc} */ public boolean supportsOutOfOrder() { - //return false; + // return false; return true; } /** - * Prepare a page for rendering. This is called if the renderer supports - * out of order rendering. The renderer should prepare the page so that a - * page further on in the set of pages can be rendered. The body of the - * page should not be rendered. The page will be rendered at a later time - * by the call to render page. - * + * Prepare a page for rendering. This is called if the renderer supports out + * of order rendering. The renderer should prepare the page so that a page + * further on in the set of pages can be rendered. The body of the page + * should not be rendered. The page will be rendered at a later time by the + * call to render page. + * * {@inheritDoc} */ public void preparePage(PageViewport page) { - // initializeRootExtensions(page); - // this.currentFontFamily = ""; - this.currentFontSize = 0; - this.pageFontCounter = 0; - this.currentPageFonts.clear(); - // this.lineCache = new HashSet(); + this.currentState.reset(); Rectangle2D bounds = page.getViewArea(); this.pageWidth = mpts2units(bounds.getWidth()); this.pageHeight = mpts2units(bounds.getHeight()); - // renderPageGroupExtensions(page); - final int pageRotation = 0; this.afpDataStream.startPage(pageWidth, pageHeight, pageRotation, - getResolution(), getResolution()); + this.resolution, this.resolution); renderPageObjectExtensions(page); @@ -407,12 +357,15 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { } /** - * Renders a region viewport. <p> - * - * The region may clip the area and it establishes a position from where - * the region is placed.</p> - * - * @param port The region viewport to be rendered + * Renders a region viewport. + * <p> + * + * The region may clip the area and it establishes a position from where the + * region is placed. + * </p> + * + * @param port + * The region viewport to be rendered */ public void renderRegionViewport(RegionViewport port) { if (port != null) { @@ -427,11 +380,9 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { handleRegionTraits(port); /* - _afpDataStream.startOverlay(mpts2units(view.getX()) - , mpts2units(view.getY()) - , mpts2units(view.getWidth()) - , mpts2units(view.getHeight()) - , rotation); + * _afpDataStream.startOverlay(mpts2units(view.getX()) , + * mpts2units(view.getY()) , mpts2units(view.getWidth()) , + * mpts2units(view.getHeight()) , rotation); */ pushViewPortPos(new ViewPortPos(view, regionReference.getCTM())); @@ -442,7 +393,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { renderRegion(regionReference); } /* - _afpDataStream.endOverlay(); + * _afpDataStream.endOverlay(); */ popViewPortPos(); } @@ -457,18 +408,17 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { // save positions int saveIP = currentIPPosition; int saveBP = currentBPPosition; - //String saveFontName = currentFontName; + // String saveFontName = currentFontName; CTM ctm = bv.getCTM(); int borderPaddingStart = bv.getBorderAndPaddingWidthStart(); int borderPaddingBefore = bv.getBorderAndPaddingWidthBefore(); float x, y; - x = (float)(bv.getXOffset() + containingIPPosition) / 1000f; - y = (float)(bv.getYOffset() + containingBPPosition) / 1000f; - //This is the content-rect - float width = (float)bv.getIPD() / 1000f; - float height = (float)bv.getBPD() / 1000f; - + x = (float) (bv.getXOffset() + containingIPPosition) / 1000f; + y = (float) (bv.getYOffset() + containingBPPosition) / 1000f; + // This is the content-rect + float width = (float) bv.getIPD() / 1000f; + float height = (float) bv.getBPD() / 1000f; if (bv.getPositioning() == Block.ABSOLUTE || bv.getPositioning() == Block.FIXED) { @@ -476,9 +426,10 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { currentIPPosition = bv.getXOffset(); currentBPPosition = bv.getYOffset(); - //For FIXED, we need to break out of the current viewports to the - //one established by the page. We save the state stack for restoration - //after the block-container has been painted. See below. + // For FIXED, we need to break out of the current viewports to the + // one established by the page. We save the state stack for + // restoration + // after the block-container has been painted. See below. List breakOutList = null; if (bv.getPositioning() == Block.FIXED) { breakOutList = breakOutOfStateStack(); @@ -487,19 +438,21 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { CTM tempctm = new CTM(containingIPPosition, containingBPPosition); ctm = tempctm.multiply(ctm); - //Adjust for spaces (from margin or indirectly by start-indent etc. + // Adjust for spaces (from margin or indirectly by start-indent etc. x += bv.getSpaceStart() / 1000f; currentIPPosition += bv.getSpaceStart(); y += bv.getSpaceBefore() / 1000f; currentBPPosition += bv.getSpaceBefore(); - float bpwidth = (borderPaddingStart + bv.getBorderAndPaddingWidthEnd()) / 1000f; - float bpheight = (borderPaddingBefore + bv.getBorderAndPaddingWidthAfter()) / 1000f; + float bpwidth = (borderPaddingStart + bv + .getBorderAndPaddingWidthEnd()) / 1000f; + float bpheight = (borderPaddingBefore + bv + .getBorderAndPaddingWidthAfter()) / 1000f; drawBackAndBorders(bv, x, y, width + bpwidth, height + bpheight); - //Now adjust for border/padding + // Now adjust for border/padding currentIPPosition += borderPaddingStart; currentBPPosition += borderPaddingBefore; @@ -512,7 +465,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { currentIPPosition = 0; currentBPPosition = 0; renderBlocks(bv, children); - //endVParea(); + // endVParea(); popViewPortPos(); if (breakOutList != null) { @@ -525,35 +478,35 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { currentBPPosition += bv.getSpaceBefore(); - //borders and background in the old coordinate system + // borders and background in the old coordinate system handleBlockTraits(bv); - //Advance to start of content area + // Advance to start of content area currentIPPosition += bv.getStartIndent(); CTM tempctm = new CTM(containingIPPosition, currentBPPosition); ctm = tempctm.multiply(ctm); - //Now adjust for border/padding + // Now adjust for border/padding currentBPPosition += borderPaddingBefore; Rectangle2D clippingRect = null; clippingRect = new Rectangle(currentIPPosition, currentBPPosition, bv.getIPD(), bv.getBPD()); - //startVParea(ctm, clippingRect); + // startVParea(ctm, clippingRect); pushViewPortPos(new ViewPortPos(clippingRect, ctm)); currentIPPosition = 0; currentBPPosition = 0; renderBlocks(bv, children); - //endVParea(); + // endVParea(); popViewPortPos(); currentIPPosition = saveIP; currentBPPosition = saveBP; - currentBPPosition += (int)(bv.getAllocBPD()); + currentBPPosition += (int) (bv.getAllocBPD()); } // currentFontName = saveFontName; } @@ -563,13 +516,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { */ public void renderPage(PageViewport pageViewport) { - // initializeRootExtensions(page); - - // this.currentFontFamily = ""; - this.currentFontSize = 0; - this.pageFontCounter = 0; - this.currentPageFonts.clear(); - // this.lineCache = new HashSet(); + currentState.reset(); Rectangle2D bounds = pageViewport.getViewArea(); @@ -578,14 +525,14 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { if (pages != null && pages.containsKey(pageViewport)) { - this.afpDataStream.restorePage((PageObject) pages.remove(pageViewport)); + this.afpDataStream.restorePage((PageObject) pages + .remove(pageViewport)); } else { - // renderPageGroupExtensions(page); final int pageRotation = 0; this.afpDataStream.startPage(pageWidth, pageHeight, pageRotation, - getResolution(), getResolution()); + this.resolution, this.resolution); renderPageObjectExtensions(pageViewport); @@ -595,16 +542,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { renderPageAreas(pageViewport.getPage()); - Iterator i = currentPageFonts.values().iterator(); - while (i.hasNext()) { - AFPFontAttributes afpFontAttributes = (AFPFontAttributes) i.next(); - - afpDataStream.createFont( - (byte)afpFontAttributes.getFontReference(), - afpFontAttributes.getFont(), - afpFontAttributes.getPointSize()); - - } + this.afpDataStream.addFontsToCurrentPage(currentState.getPageFonts()); try { afpDataStream.endPage(); @@ -656,22 +594,12 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { */ public void fillRect(float x, float y, float width, float height) { /* - afpDataStream.createShading( - pts2units(x), - pts2units(y), - pts2units(width), - pts2units(height), - currentColor.getRed(), - currentColor.getGreen(), - currentColor.getBlue()); + * afpDataStream.createShading( pts2units(x), pts2units(y), + * pts2units(width), pts2units(height), currentColor.getRed(), + * currentColor.getGreen(), currentColor.getBlue()); */ - afpDataStream.createLine( - pts2units(x), - pts2units(y), - pts2units(x + width), - pts2units(y), - pts2units(height), - currentColor); + afpDataStream.createLine(pts2units(x), pts2units(y), pts2units(x + + width), pts2units(y), pts2units(height), currentState.getColor()); } /** @@ -686,195 +614,124 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { return; } switch (style) { - case Constants.EN_DOUBLE: - if (horz) { - float h3 = h / 3; - float ym1 = y1; - float ym2 = ym1 + h3 + h3; - afpDataStream.createLine( - pts2units(x1), - pts2units(ym1), - pts2units(x2), - pts2units(ym1), - pts2units(h3), - col - ); - afpDataStream.createLine( - pts2units(x1), - pts2units(ym2), - pts2units(x2), - pts2units(ym2), - pts2units(h3), - col - ); - } else { - float w3 = w / 3; - float xm1 = x1; - float xm2 = xm1 + w3 + w3; - afpDataStream.createLine( - pts2units(xm1), - pts2units(y1), - pts2units(xm1), - pts2units(y2), - pts2units(w3), - col - ); - afpDataStream.createLine( - pts2units(xm2), - pts2units(y1), - pts2units(xm2), - pts2units(y2), - pts2units(w3), - col - ); + case Constants.EN_DOUBLE: + if (horz) { + float h3 = h / 3; + float ym1 = y1; + float ym2 = ym1 + h3 + h3; + afpDataStream.createLine(pts2units(x1), pts2units(ym1), + pts2units(x2), pts2units(ym1), pts2units(h3), col); + afpDataStream.createLine(pts2units(x1), pts2units(ym2), + pts2units(x2), pts2units(ym2), pts2units(h3), col); + } else { + float w3 = w / 3; + float xm1 = x1; + float xm2 = xm1 + w3 + w3; + afpDataStream.createLine(pts2units(xm1), pts2units(y1), + pts2units(xm1), pts2units(y2), pts2units(w3), col); + afpDataStream.createLine(pts2units(xm2), pts2units(y1), + pts2units(xm2), pts2units(y2), pts2units(w3), col); + } + break; + case Constants.EN_DASHED: + if (horz) { + float w2 = 2 * h; + while (x1 + w2 < x2) { + afpDataStream.createLine(pts2units(x1), pts2units(y1), + pts2units(x1 + w2), pts2units(y1), pts2units(h), + col); + x1 += 2 * w2; } - break; - case Constants.EN_DASHED: - if (horz) { - float w2 = 2 * h; - while (x1 + w2 < x2) { - afpDataStream.createLine( - pts2units(x1), - pts2units(y1), - pts2units(x1 + w2), - pts2units(y1), - pts2units(h), - col - ); - x1 += 2 * w2; - } - } else { - float h2 = 2 * w; - while (y1 + h2 < y2) { - afpDataStream.createLine( - pts2units(x1), - pts2units(y1), - pts2units(x1), - pts2units(y1 + h2), - pts2units(w), - col - ); - y1 += 2 * h2; - } + } else { + float h2 = 2 * w; + while (y1 + h2 < y2) { + afpDataStream.createLine(pts2units(x1), pts2units(y1), + pts2units(x1), pts2units(y1 + h2), pts2units(w), + col); + y1 += 2 * h2; } - break; - case Constants.EN_DOTTED: - if (horz) { - while (x1 + h < x2) { - afpDataStream.createLine( - pts2units(x1), - pts2units(y1), - pts2units(x1 + h), - pts2units(y1), - pts2units(h), - col - ); - x1 += 2 * h; - } - } else { - while (y1 + w < y2) { - afpDataStream.createLine( - pts2units(x1), - pts2units(y1), - pts2units(x1), - pts2units(y1 + w), - pts2units(w), - col - ); - y1 += 2 * w; - } + } + break; + case Constants.EN_DOTTED: + if (horz) { + while (x1 + h < x2) { + afpDataStream + .createLine(pts2units(x1), pts2units(y1), + pts2units(x1 + h), pts2units(y1), + pts2units(h), col); + x1 += 2 * h; } - break; - case Constants.EN_GROOVE: - case Constants.EN_RIDGE: - { - float colFactor = (style == EN_GROOVE ? 0.4f : -0.4f); - if (horz) { - Color uppercol = lightenColor(col, -colFactor); - Color lowercol = lightenColor(col, colFactor); - float h3 = h / 3; - float ym1 = y1; - afpDataStream.createLine( - pts2units(x1), - pts2units(ym1), - pts2units(x2), - pts2units(ym1), - pts2units(h3), - uppercol - ); - afpDataStream.createLine( - pts2units(x1), - pts2units(ym1 + h3), - pts2units(x2), - pts2units(ym1 + h3), - pts2units(h3), - col - ); - afpDataStream.createLine( - pts2units(x1), - pts2units(ym1 + h3 + h3), - pts2units(x2), - pts2units(ym1 + h3 + h3), - pts2units(h3), - lowercol - ); - } else { - Color leftcol = lightenColor(col, -colFactor); - Color rightcol = lightenColor(col, colFactor); - float w3 = w / 3; - float xm1 = x1 + (w3 / 2); - afpDataStream.createLine( - pts2units(xm1), - pts2units(y1), - pts2units(xm1), - pts2units(y2), - pts2units(w3), - leftcol - ); - afpDataStream.createLine( - pts2units(xm1 + w3), - pts2units(y1), - pts2units(xm1 + w3), - pts2units(y2), - pts2units(w3), - col - ); - afpDataStream.createLine( - pts2units(xm1 + w3 + w3), - pts2units(y1), - pts2units(xm1 + w3 + w3), - pts2units(y2), - pts2units(w3), - rightcol - ); + } else { + while (y1 + w < y2) { + afpDataStream + .createLine(pts2units(x1), pts2units(y1), + pts2units(x1), pts2units(y1 + w), + pts2units(w), col); + y1 += 2 * w; } - break; } - case Constants.EN_HIDDEN: - break; - case Constants.EN_INSET: - case Constants.EN_OUTSET: - default: - afpDataStream.createLine( - pts2units(x1), - pts2units(y1), - pts2units(horz ? x2 : x1), - pts2units(horz ? y1 : y2), - pts2units(Math.abs(horz ? (y2 - y1) : (x2 - x1))), - col - ); + break; + case Constants.EN_GROOVE: + case Constants.EN_RIDGE: { + float colFactor = (style == EN_GROOVE ? 0.4f : -0.4f); + if (horz) { + Color uppercol = lightenColor(col, -colFactor); + Color lowercol = lightenColor(col, colFactor); + float h3 = h / 3; + float ym1 = y1; + afpDataStream.createLine(pts2units(x1), pts2units(ym1), + pts2units(x2), pts2units(ym1), pts2units(h3), uppercol); + afpDataStream.createLine(pts2units(x1), pts2units(ym1 + h3), + pts2units(x2), pts2units(ym1 + h3), pts2units(h3), col); + afpDataStream.createLine(pts2units(x1), + pts2units(ym1 + h3 + h3), pts2units(x2), pts2units(ym1 + + h3 + h3), pts2units(h3), lowercol); + } else { + Color leftcol = lightenColor(col, -colFactor); + Color rightcol = lightenColor(col, colFactor); + float w3 = w / 3; + float xm1 = x1 + (w3 / 2); + afpDataStream.createLine(pts2units(xm1), pts2units(y1), + pts2units(xm1), pts2units(y2), pts2units(w3), leftcol); + afpDataStream.createLine(pts2units(xm1 + w3), pts2units(y1), + pts2units(xm1 + w3), pts2units(y2), pts2units(w3), col); + afpDataStream.createLine(pts2units(xm1 + w3 + w3), + pts2units(y1), pts2units(xm1 + w3 + w3), pts2units(y2), + pts2units(w3), rightcol); + } + break; + } + case Constants.EN_HIDDEN: + break; + case Constants.EN_INSET: + case Constants.EN_OUTSET: + default: + afpDataStream.createLine(pts2units(x1), pts2units(y1), + pts2units(horz ? x2 : x1), pts2units(horz ? y1 : y2), + pts2units(Math.abs(horz ? (y2 - y1) : (x2 - x1))), col); } } /** * {@inheritDoc} */ - protected RendererContext createRendererContext(int x, int y, int width, int height, - Map foreignAttributes) { + protected RendererContext createRendererContext(int x, int y, int width, + int height, Map foreignAttributes) { RendererContext context; - context = super.createRendererContext(x, y, width, height, foreignAttributes); + context = super.createRendererContext(x, y, width, height, + foreignAttributes); context.setProperty(AFPRendererContextConstants.AFP_GRAYSCALE, new Boolean(!this.colorImages)); + context.setProperty(AFPRendererContextConstants.AFP_FONT_INFO, + this.fontInfo); + context.setProperty(AFPRendererContextConstants.AFP_RESOLUTION, + new Integer(this.resolution)); + context.setProperty(AFPRendererContextConstants.AFP_BITS_PER_PIXEL, + new Integer(this.bitsPerPixel)); + context.setProperty(AFPRendererContextConstants.AFP_DATASTREAM, + this.afpDataStream); + context.setProperty(AFPRendererContextConstants.AFP_STATE, + this.currentState); return context; } @@ -911,71 +768,65 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { renderDocument(doc, ns, pos, foreignAttributes); } else if (MimeConstants.MIME_EPS.equals(mime)) { log.warn("EPS images are not supported by this renderer"); - /* - } else if (MimeConstants.MIME_JPEG.equals(mime)) { - if (!fopimage.load(FopImage.ORIGINAL_DATA)) { - return; - } - fact.releaseImage(url, userAgent); - - int x = mpts2units(pos.getX() + currentIPPosition); - int y = mpts2units(pos.getY() + currentBPPosition); - int w = mpts2units(pos.getWidth()); - int h = mpts2units(pos.getHeight()); - ImageObject io = _afpDataStream.getImageObject(); - io.setImageViewport(x, y, w, h); - io.setImageParameters( - (int)(fopimage.getHorizontalResolution() * 10), - (int)(fopimage.getVerticalResolution() * 10), - fopimage.getWidth(), - fopimage.getHeight() - ); - io.setImageIDESize((byte)fopimage.getBitsPerPixel()); - io.setImageEncoding((byte)0x83); - io.setImageData(fopimage.getRessourceBytes()); - */ + /* + * } else if (MimeConstants.MIME_JPEG.equals(mime)) { if + * (!fopimage.load(FopImage.ORIGINAL_DATA)) { return; } + * fact.releaseImage(url, userAgent); + * + * int x = mpts2units(pos.getX() + currentIPPosition); int y = + * mpts2units(pos.getY() + currentBPPosition); int w = + * mpts2units(pos.getWidth()); int h = + * mpts2units(pos.getHeight()); ImageObject io = + * _afpDataStream.getImageObject(); io.setImageViewport(x, y, w, + * h); io.setImageParameters( + * (int)(fopimage.getHorizontalResolution() * 10), + * (int)(fopimage.getVerticalResolution() * 10), + * fopimage.getWidth(), fopimage.getHeight() ); + * io.setImageIDESize((byte)fopimage.getBitsPerPixel()); + * io.setImageEncoding((byte)0x83); + * io.setImageData(fopimage.getRessourceBytes()); + */ } else if (MimeConstants.MIME_TIFF.equals(mime) - && fopimage instanceof TIFFImage) { + && fopimage instanceof TIFFImage) { TIFFImage tiffImage = (TIFFImage) fopimage; int x = mpts2units(pos.getX() + currentIPPosition); int y = mpts2units(pos.getY() + currentBPPosition); int w = mpts2units(pos.getWidth()); int h = mpts2units(pos.getHeight()); - ImageObject io = afpDataStream.getImageObject(x, y, w, h, - getResolution(), getResolution()); + int res = getResolution(); + ImageObject io = afpDataStream.getImageObject(x, y, w, h, res, + res); io.setImageParameters( - (int)(fopimage.getHorizontalResolution() * 10), - (int)(fopimage.getVerticalResolution() * 10), - fopimage.getWidth(), - fopimage.getHeight() - ); + (int) (fopimage.getHorizontalResolution() * 10), + (int) (fopimage.getVerticalResolution() * 10), fopimage + .getWidth(), fopimage.getHeight()); if (tiffImage.getStripCount() == 1) { int comp = tiffImage.getCompression(); if (comp == 3) { if (!fopimage.load(FopImage.ORIGINAL_DATA)) { return; } - io.setImageEncoding((byte)0x81); + io.setImageEncoding((byte) 0x81); io.setImageData(fopimage.getRessourceBytes()); } else if (comp == 4) { if (!fopimage.load(FopImage.ORIGINAL_DATA)) { return; } - io.setImageEncoding((byte)0x82); + io.setImageEncoding((byte) 0x82); io.setImageData(fopimage.getRessourceBytes()); } else { if (!fopimage.load(FopImage.BITMAP)) { return; } - convertToGrayScaleImage(io, fopimage.getBitmaps(), - fopimage.getWidth(), fopimage.getHeight()); + convertToGrayScaleImage(io, fopimage.getBitmaps(), + fopimage.getWidth(), fopimage.getHeight(), this.bitsPerPixel); } } else { if (!fopimage.load(FopImage.BITMAP)) { return; } - convertToGrayScaleImage(io, fopimage.getBitmaps(), - fopimage.getWidth(), fopimage.getHeight()); + convertToGrayScaleImage(io, fopimage.getBitmaps(), fopimage + .getWidth(), fopimage.getHeight(), this.bitsPerPixel); } } else { if (!fopimage.load(FopImage.BITMAP)) { @@ -987,20 +838,19 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { int y = mpts2units(pos.getY() + currentBPPosition); int w = mpts2units(pos.getWidth()); int h = mpts2units(pos.getHeight()); - ImageObject io = afpDataStream.getImageObject(x, y, w, h, - getResolution(), getResolution()); + int res = getResolution(); + ImageObject io = afpDataStream.getImageObject(x, y, w, h, res, + res); io.setImageParameters( - (int)(fopimage.getHorizontalResolution() * 10), - (int)(fopimage.getVerticalResolution() * 10), - fopimage.getWidth(), - fopimage.getHeight() - ); + (int) (fopimage.getHorizontalResolution() * 10), + (int) (fopimage.getVerticalResolution() * 10), fopimage + .getWidth(), fopimage.getHeight()); if (colorImages) { - io.setImageIDESize((byte)24); + io.setImageIDESize((byte) 24); io.setImageData(fopimage.getBitmaps()); } else { - convertToGrayScaleImage(io, fopimage.getBitmaps(), - fopimage.getWidth(), fopimage.getHeight()); + convertToGrayScaleImage(io, fopimage.getBitmaps(), fopimage + .getWidth(), fopimage.getHeight(), this.bitsPerPixel); } } } @@ -1008,13 +858,18 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { /** * Writes a BufferedImage to an OutputStream as raw sRGB bitmaps. - * @param img the BufferedImage - * @param out the OutputStream - * @throws IOException In case of an I/O error. - */ - public static void writeImage(BufferedImage img, OutputStream out) throws IOException { - int w = img.getWidth(); - int h = img.getHeight(); + * + * @param img + * the BufferedImage + * @param out + * the OutputStream + * @throws IOException + * In case of an I/O error. + */ + public static void writeImage(BufferedImage img, OutputStream out) + throws IOException { + int w = img.getWidth(); + int h = img.getHeight(); int[] tmpMap = img.getRGB(0, 0, w, h, null, 0, w); for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { @@ -1022,21 +877,28 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { int r = (p >> 16) & 0xFF; int g = (p >> 8) & 0xFF; int b = (p) & 0xFF; - out.write((byte)(r & 0xFF)); - out.write((byte)(g & 0xFF)); - out.write((byte)(b & 0xFF)); + out.write((byte) (r & 0xFF)); + out.write((byte) (g & 0xFF)); + out.write((byte) (b & 0xFF)); } } } /** * Draws a BufferedImage to AFP. - * @param bi the BufferedImage - * @param imageResolution the resolution of the BufferedImage - * @param x the x coordinate (in mpt) - * @param y the y coordinate (in mpt) - * @param w the width of the viewport (in mpt) - * @param h the height of the viewport (in mpt) + * + * @param bi + * the BufferedImage + * @param imageResolution + * the resolution of the BufferedImage + * @param x + * the x coordinate (in mpt) + * @param y + * the y coordinate (in mpt) + * @param w + * the width of the viewport (in mpt) + * @param h + * the height of the viewport (in mpt) */ public void drawBufferedImage(BufferedImage bi, int imageResolution, int x, int y, int w, int h) { @@ -1044,46 +906,46 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { int afpy = mpts2units(y); int afpw = mpts2units(w); int afph = mpts2units(h); + int afpres = getResolution(); ByteArrayOutputStream baout = new ByteArrayOutputStream(); try { - //Serialize image + // Serialize image writeImage(bi, baout); byte[] buf = baout.toByteArray(); - //Generate image - ImageObject io = afpDataStream.getImageObject(afpx, afpy, afpw, afph, - getResolution(), getResolution()); - io.setImageParameters( - imageResolution, imageResolution, - bi.getWidth(), - bi.getHeight() - ); + // Generate image + ImageObject io = afpDataStream.getImageObject(afpx, afpy, afpw, + afph, afpres, afpres); + io.setImageParameters(imageResolution, imageResolution, + bi.getWidth(), bi.getHeight()); if (colorImages) { io.setImageIDESize((byte)24); io.setImageData(buf); } else { - //TODO Teach it how to handle grayscale BufferedImages directly - //because this is pretty inefficient - convertToGrayScaleImage(io, buf, bi.getWidth(), bi.getHeight()); + // TODO Teach it how to handle grayscale BufferedImages directly + // because this is pretty inefficient + convertToGrayScaleImage(io, buf, bi.getWidth(), bi.getHeight(), this.bitsPerPixel); } } catch (IOException ioe) { - log.error("Error while serializing bitmap: " + ioe.getMessage(), ioe); + log.error("Error while serializing bitmap: " + ioe.getMessage(), + ioe); } } /** - * Establishes a new foreground or fill color. - * {@inheritDoc} + * Establishes a new foreground or fill color. {@inheritDoc} */ public void updateColor(Color col, boolean fill) { if (fill) { - currentColor = col; + currentState.setColor(col); } } /** * Restores the state stack after a break out. - * @param breakOutList the state stack to restore. + * + * @param breakOutList + * the state stack to restore. */ public void restoreStateStackAfterBreakOut(List breakOutList) { @@ -1091,6 +953,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { /** * Breaks out of the state stack to handle fixed block-containers. + * * @return the saved state stack to recreate later */ public List breakOutOfStateStack() { @@ -1131,76 +994,58 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { public void renderText(TextArea text) { renderInlineAreaBackAndBorders(text); - String name = getInternalFontNameForArea(text); - currentFontSize = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue(); - AFPFont tf = (AFPFont) fontInfo.getFonts().get(name); + String internalFontName = getInternalFontNameForArea(text); + this.currentState.setFontName(internalFontName); + int currentFontSize = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue(); + this.currentState.setFontSize(currentFontSize); + AFPFont font = (AFPFont) fontInfo.getFonts().get(internalFontName); Color col = (Color) text.getTrait(Trait.COLOR); - int vsci = mpts2units(tf.getWidth(' ', currentFontSize) / 1000 - + text.getTextWordSpaceAdjust() - + text.getTextLetterSpaceAdjust()); + int vsci = mpts2units(font.getWidth(' ', currentFontSize) / 1000 + + text.getTextWordSpaceAdjust() + + text.getTextLetterSpaceAdjust()); // word.getOffset() = only height of text itself // currentBlockIPPosition: 0 for beginning of line; nonzero - // where previous line area failed to take up entire allocated space + // where previous line area failed to take up entire allocated space int rx = currentIPPosition + text.getBorderAndPaddingWidthStart(); - int bl = currentBPPosition + text.getOffset() + text.getBaselineOffset(); + int bl = currentBPPosition + text.getOffset() + + text.getBaselineOffset(); // Set letterSpacing - //float ls = fs.getLetterSpacing() / this.currentFontSize; + // float ls = fs.getLetterSpacing() / this.currentFontSize; String worddata = text.getText(); - // Create an AFPFontAttributes object from the current font details - AFPFontAttributes afpFontAttributes = new AFPFontAttributes(name, tf, currentFontSize); - - if (!currentPageFonts.containsKey(afpFontAttributes.getFontKey())) { - // Font not found on current page, so add the new one - pageFontCounter++; - afpFontAttributes.setFontReference(pageFontCounter); - currentPageFonts.put( - afpFontAttributes.getFontKey(), - afpFontAttributes); - - } else { - // Use the previously stored font attributes - afpFontAttributes = (AFPFontAttributes) currentPageFonts.get( - afpFontAttributes.getFontKey()); - } + AFPPageFonts pageFonts = this.currentState.getPageFonts(); + AFPFontAttributes afpFontAttributes = pageFonts.registerFont( + internalFontName, font, currentFontSize); // Try and get the encoding to use for the font String encoding = null; try { - encoding = tf.getCharacterSet(currentFontSize).getEncoding(); + encoding = font.getCharacterSet(currentFontSize).getEncoding(); } catch (Throwable ex) { encoding = AFPConstants.EBCIDIC_ENCODING; - log.warn( - "renderText():: Error getting encoding for font " - + " - using default encoding " - + encoding); + log.warn("renderText():: Error getting encoding for font " + + " - using default encoding " + encoding); } try { - afpDataStream.createText( - afpFontAttributes.getFontReference(), - mpts2units(rx), - mpts2units(bl), - col, - vsci, - mpts2units(text.getTextLetterSpaceAdjust()), - worddata.getBytes(encoding)); + afpDataStream.createText(afpFontAttributes.getFontReference(), + mpts2units(rx), pts2units(bl), col, vsci, mpts2units(text + .getTextLetterSpaceAdjust()), worddata + .getBytes(encoding)); } catch (UnsupportedEncodingException usee) { - log.error( - "renderText:: Font " - + afpFontAttributes.getFontKey() - + " caused UnsupportedEncodingException"); + log.error("renderText:: Font " + afpFontAttributes.getFontKey() + + " caused UnsupportedEncodingException"); } super.renderText(text); - renderTextDecoration(tf, currentFontSize, text, bl, rx); + renderTextDecoration(font, currentFontSize, text, bl, rx); } /** @@ -1238,88 +1083,41 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { } /** - * Render leader area. - * This renders a leader area which is an area with a rule. - * @param area the leader area to render + * Render leader area. This renders a leader area which is an area with a + * rule. + * + * @param area + * the leader area to render */ public void renderLeader(Leader area) { renderInlineAreaBackAndBorders(area); int style = area.getRuleStyle(); - float startx = (currentIPPosition + area.getBorderAndPaddingWidthStart()) / 1000f; + float startx = (currentIPPosition + area + .getBorderAndPaddingWidthStart()) / 1000f; float starty = (currentBPPosition + area.getOffset()) / 1000f; - float endx = (currentIPPosition + area.getBorderAndPaddingWidthStart() - + area.getIPD()) / 1000f; + float endx = (currentIPPosition + area.getBorderAndPaddingWidthStart() + area + .getIPD()) / 1000f; float ruleThickness = area.getRuleThickness() / 1000f; - Color col = (Color)area.getTrait(Trait.COLOR); + Color col = (Color) area.getTrait(Trait.COLOR); switch (style) { - case EN_SOLID: - case EN_DASHED: - case EN_DOUBLE: - case EN_DOTTED: - case EN_GROOVE: - case EN_RIDGE: - drawBorderLine(startx, starty, endx, starty + ruleThickness, - true, true, style, col); - break; - default: - throw new UnsupportedOperationException("rule style not supported"); + case EN_SOLID: + case EN_DASHED: + case EN_DOUBLE: + case EN_DOTTED: + case EN_GROOVE: + case EN_RIDGE: + drawBorderLine(startx, starty, endx, starty + ruleThickness, true, + true, style, col); + break; + default: + throw new UnsupportedOperationException("rule style not supported"); } super.renderLeader(area); } /** - * Sets the AFPRenderer options - * @param options the <code>Map</code> containing the options - */ -// UNUSED -// public void setOptions(Map options) { -// -// this.afpOptions = options; -// -// } - /** - * Determines the orientation from the string representation, this method - * guarantees to return a value of either 0, 90, 180 or 270. - * - * @return the orientation - */ -// UNUSED -// private int getOrientation(String orientationString) { -// -// int orientation = 0; -// if (orientationString != null && orientationString.length() > 0) { -// try { -// orientation = Integer.parseInt(orientationString); -// } catch (NumberFormatException nfe) { -// log.error("Cannot use orientation of " + orientation -// + " defaulting to zero."); -// orientation = 0; -// } -// } else { -// orientation = 0; -// } -// switch (orientation) { -// case 0: -// break; -// case 90: -// break; -// case 180: -// break; -// case 270: -// break; -// default: -// log.error("Cannot use orientation of " + orientation -// + " defaulting to zero."); -// orientation = 0; -// break; -// } -// -// return orientation; -// -// } - /** * Sets the rotation to be used for portrait pages, valid values are 0 * (default), 90, 180, 270. * @@ -1328,14 +1126,13 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { */ public void setPortraitRotation(int rotation) { - if (rotation == 0 - || rotation == 90 - || rotation == 180 - || rotation == 270) { + 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"); + throw new IllegalArgumentException( + "The portrait rotation must be one" + + " of the values 0, 90, 180, 270"); } @@ -1344,20 +1141,19 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { /** * Sets the rotation to be used for landsacpe 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) { + 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"); + throw new IllegalArgumentException( + "The landscape rotation must be one" + + " of the values 0, 90, 180, 270"); } } @@ -1365,7 +1161,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { /** * Get the MIME type of the renderer. * - * @return The MIME type of the renderer + * @return The MIME type of the renderer */ public String getMimeType() { return MimeConstants.MIME_AFP; @@ -1375,7 +1171,8 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { * Method to render the page extension. * <p> * - * @param pageViewport the page object + * @param pageViewport + * the page object */ private void renderPageObjectExtensions(PageViewport pageViewport) { @@ -1386,7 +1183,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { // the s-p-m Iterator i = pageViewport.getExtensionAttachments().iterator(); while (i.hasNext()) { - ExtensionAttachment attachment = (ExtensionAttachment)i.next(); + ExtensionAttachment attachment = (ExtensionAttachment) i.next(); if (AFPPageSetup.CATEGORY.equals(attachment.getCategory())) { AFPPageSetup aps = (AFPPageSetup) attachment; String element = aps.getElementName(); @@ -1425,7 +1222,9 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { /** * Converts FOP mpt measurement to afp measurement units - * @param mpt the millipoints value + * + * @param mpt + * the millipoints value */ private int mpts2units(int mpt) { return mpts2units((double) mpt); @@ -1433,7 +1232,9 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { /** * Converts FOP pt measurement to afp measurement units - * @param mpt the millipoints value + * + * @param mpt + * the millipoints value */ private int pts2units(float mpt) { return mpts2units(mpt * 1000d); @@ -1447,17 +1248,27 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { * @return afp measurement unit value */ private int mpts2units(double mpt) { - return (int)Math.round(mpt / (DPI_CONVERSION_FACTOR / getResolution())); + return (int) Math + .round(mpt / (DPI_CONVERSION_FACTOR / getResolution())); } /** - * Converts a byte array containing 24 bit RGB image data to a grayscale image. - * @param io the target image object - * @param raw the buffer containing the RGB image data - * @param width the width of the image in pixels - * @param height the height of the image in pixels + * Converts a byte array containing 24 bit RGB image data to a grayscale + * image. + * + * @param io + * the target image object + * @param raw + * the buffer containing the RGB image data + * @param width + * the width of the image in pixels + * @param height + * the height of the image in pixels + * @param bitsPerPixel + * the number of bits to use per pixel */ - private void convertToGrayScaleImage(ImageObject io, byte[] raw, int width, int height) { + protected static void convertToGrayScaleImage(ImageObject io, byte[] raw, int width, + int height, int bitsPerPixel) { int pixelsPerByte = 8 / bitsPerPixel; int bytewidth = (width / pixelsPerByte); if ((width % pixelsPerByte) != 0) { @@ -1469,26 +1280,26 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { ib = 0; int i = 3 * y * width; for (int x = 0; x < width; x++, i += 3) { - + // see http://www.jguru.com/faq/view.jsp?EID=221919 - double greyVal = 0.212671d * ((int) raw[i] & 0xff) - + 0.715160d * ((int) raw[i + 1] & 0xff) - + 0.072169d * ((int) raw[i + 2] & 0xff); + double greyVal = 0.212671d * ((int) raw[i] & 0xff) + 0.715160d + * ((int) raw[i + 1] & 0xff) + 0.072169d + * ((int) raw[i + 2] & 0xff); switch (bitsPerPixel) { - case 1: - if (greyVal < 128) { - ib |= (byte) (1 << (7 - (x % 8))); - } - break; - case 4: - greyVal /= 16; - ib |= (byte) ((byte) greyVal << ((1 - (x % 2)) * 4)); - break; - case 8: - ib = (byte) greyVal; - break; - default: - throw new UnsupportedOperationException( + case 1: + if (greyVal < 128) { + ib |= (byte) (1 << (7 - (x % 8))); + } + break; + case 4: + greyVal /= 16; + ib |= (byte) ((byte) greyVal << ((1 - (x % 2)) * 4)); + break; + case 8: + ib = (byte) greyVal; + break; + default: + throw new UnsupportedOperationException( "Unsupported bits per pixel: " + bitsPerPixel); } @@ -1502,7 +1313,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { io.setImageIDESize((byte) bitsPerPixel); io.setImageData(bw); } - + private final class ViewPortPos { private int x = 0; @@ -1611,7 +1422,8 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { private void popViewPortPos() { viewPortPositions.remove(viewPortPositions.size() - 1); if (viewPortPositions.size() > 0) { - ViewPortPos vpp = (ViewPortPos)viewPortPositions.get(viewPortPositions.size() - 1); + ViewPortPos vpp = (ViewPortPos) viewPortPositions + .get(viewPortPositions.size() - 1); afpDataStream.setOffsets(vpp.x, vpp.y, vpp.rot); } } @@ -1625,9 +1437,9 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { public void setBitsPerPixel(int bitsPerPixel) { this.bitsPerPixel = bitsPerPixel; switch (bitsPerPixel) { - case 1: - case 4: - case 8: + case 1: + case 4: + case 8: break; default: log.warn("Invalid bits_per_pixel value, must be 1, 4 or 8."); @@ -1647,20 +1459,36 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { } /** + * Returns the AFPDataStream + * + * @return the AFPDataStream + */ + public AFPDataStream getAFPDataStream() { + return afpDataStream; + } + + /** * 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"); + if (resolution == DPI_240_RESOLUTION + || resolution == DPI_1440_RESOLUTION) { + this.resolution = resolution; + if (log.isDebugEnabled()) { + log.debug("renderer-resolution set to: " + resolution + " dpi"); + } + } else { + log.error("invalid resolution, can only be " + DPI_240_RESOLUTION + + " or " + DPI_1440_RESOLUTION + " dpi"); } - this.resolution = resolution; } - + /** * Returns the output/device resolution. + * * @return the resolution in dpi */ public int getResolution() { diff --git a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java index dee741ab4..c0f6a9c6f 100644 --- a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java +++ b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java @@ -239,7 +239,8 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator { Configuration rendererResolutionCfg = cfg.getChild("renderer-resolution", false); if (rendererResolutionCfg != null) { - afpRenderer.setResolution(rendererResolutionCfg.getValueAsInteger(240)); + afpRenderer.setResolution(rendererResolutionCfg.getValueAsInteger( + AFPRenderer.DPI_240_RESOLUTION)); } } } diff --git a/src/java/org/apache/fop/render/afp/AFPRendererContextConstants.java b/src/java/org/apache/fop/render/afp/AFPRendererContextConstants.java index 88cb73547..a4b449bb0 100644 --- a/src/java/org/apache/fop/render/afp/AFPRendererContextConstants.java +++ b/src/java/org/apache/fop/render/afp/AFPRendererContextConstants.java @@ -1,35 +1,49 @@ -/*
- * 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 org.apache.fop.render.RendererContextConstants;
-
-/**
- * Defines a number of standard constants (keys) for use by the RendererContext class.
- */
-public interface AFPRendererContextConstants extends RendererContextConstants {
-
- /**
- * Key for a Boolean value that enables grayscale processing instead of color
- * processing.
- */
- String AFP_GRAYSCALE = "afpGrayscale";
-
-}
+/* + * 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 org.apache.fop.render.RendererContextConstants; + +/** + * Defines a number of standard constants (keys) for use by the RendererContext class. + */ +public interface AFPRendererContextConstants extends RendererContextConstants { + + /** + * Key for a Boolean value that enables grayscale processing instead of color + * processing. + */ + String AFP_GRAYSCALE = "afpGrayscale"; + + /** The font information for the AFP renderer. */ + String AFP_FONT_INFO = "afpFontInfo"; + + /** The afp resolution. */ + String AFP_RESOLUTION = "afpResolution"; + + /** The afp datastream */ + String AFP_DATASTREAM = "afpDataStream"; + + /** The afp state */ + String AFP_STATE = "afpPageState"; + + /** The afp bits per pixel */ + String AFP_BITS_PER_PIXEL = "afpBitsPerPixel"; +} diff --git a/src/java/org/apache/fop/render/afp/AFPSVGHandler.java b/src/java/org/apache/fop/render/afp/AFPSVGHandler.java index e216244c5..1506acb4b 100644 --- a/src/java/org/apache/fop/render/afp/AFPSVGHandler.java +++ b/src/java/org/apache/fop/render/afp/AFPSVGHandler.java @@ -15,13 +15,27 @@ * limitations under the License. */ -/* $Id$ */ +/* $Id: $ */ package org.apache.fop.render.afp; // FOP +import java.awt.geom.AffineTransform; +import java.io.IOException; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.bridge.GVTBuilder; +import org.apache.batik.dom.svg.SVGDOMImplementation; +import org.apache.batik.gvt.GraphicsNode; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.fop.render.AbstractGenericSVGHandler; import org.apache.fop.render.Renderer; +import org.apache.fop.render.RendererContext; +import org.apache.fop.render.afp.modca.AFPDataStream; +import org.apache.fop.svg.SVGUserAgent; +import org.w3c.dom.Document; /** * AFP XML handler for SVG. Uses Apache Batik for SVG processing. @@ -30,10 +44,126 @@ import org.apache.fop.render.Renderer; */ public class AFPSVGHandler extends AbstractGenericSVGHandler { + /** logging instance */ + private static Log log = LogFactory.getLog(AFPSVGHandler.class); + + /** {@inheritDoc} */ + public void handleXML(RendererContext context, + Document doc, String ns) throws Exception { + AFPInfo afpi = getAFPInfo(context); + + if (SVGDOMImplementation.SVG_NAMESPACE_URI.equals(ns)) { + renderSVGDocument(context, doc, afpi); + } + } + + /** + * Get the afp information from the render context. + * + * @param context the renderer context + * @return the afp information retrieved from the context + */ + public static AFPInfo getAFPInfo(RendererContext context) { + AFPInfo afpi = new AFPInfo(); + afpi.width = ((Integer)context.getProperty(WIDTH)).intValue(); + afpi.height = ((Integer)context.getProperty(HEIGHT)).intValue(); + afpi.currentXPosition = ((Integer)context.getProperty(XPOS)).intValue(); + afpi.currentYPosition = ((Integer)context.getProperty(YPOS)).intValue(); + afpi.cfg = (Configuration)context.getProperty(HANDLER_CONFIGURATION); + afpi.fontInfo = (org.apache.fop.fonts.FontInfo)context.getProperty( + AFPRendererContextConstants.AFP_FONT_INFO); + afpi.resolution = ((Integer)context.getProperty( + AFPRendererContextConstants.AFP_RESOLUTION)).intValue(); + afpi.afpState = (AFPState)context.getProperty( + AFPRendererContextConstants.AFP_STATE); + afpi.afpDataStream = (AFPDataStream)context.getProperty( + AFPRendererContextConstants.AFP_DATASTREAM); + afpi.grayscale = ((Boolean)context.getProperty( + AFPRendererContextConstants.AFP_GRAYSCALE)).booleanValue(); + afpi.bitsPerPixel = ((Integer)context.getProperty( + AFPRendererContextConstants.AFP_BITS_PER_PIXEL)).intValue(); + return afpi; + } + + /** + * Render the SVG document. + * @param context the renderer context + * @param doc the SVG document + * @param afpInfo the AFPInfo renderer parameters + * @throws IOException In case of an I/O error while painting the image + */ + protected void renderSVGDocument(final RendererContext context, + final Document doc, AFPInfo afpInfo) throws IOException { + + final boolean textAsShapes = false; + AFPGraphics2D graphics = new AFPGraphics2D(textAsShapes); + graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext()); + graphics.setAFPInfo(afpInfo); + + GVTBuilder builder = new GVTBuilder(); + + boolean strokeText = false; + Configuration cfg = afpInfo.cfg; + if (cfg != null) { + strokeText = cfg.getChild("stroke-text", true).getValueAsBoolean(strokeText); + } + + final float uaResolution = context.getUserAgent().getSourceResolution(); + SVGUserAgent svgUserAgent = new SVGUserAgent(25.4f / uaResolution, new AffineTransform()); + + BridgeContext ctx = new BridgeContext(svgUserAgent); + AFPTextHandler afpTextHandler = null; + //Controls whether text painted by Batik is generated using text or path operations + if (!strokeText) { + afpTextHandler = new AFPTextHandler(graphics); + graphics.setCustomTextHandler(afpTextHandler); + AFPTextPainter textPainter = new AFPTextPainter(afpTextHandler); + ctx.setTextPainter(textPainter); + AFPTextElementBridge tBridge = new AFPTextElementBridge(textPainter); + ctx.putBridge(tBridge); + } + + GraphicsNode root; + try { + root = builder.build(ctx, doc); + } catch (Exception e) { + log.error("SVG graphic could not be built: " + + e.getMessage(), e); + return; + } + log.debug("Generating SVG at " + + afpInfo.resolution + "dpi."); + + int res = afpInfo.resolution; + + double w = ctx.getDocumentSize().getWidth() * 1000f; + double h = ctx.getDocumentSize().getHeight() * 1000f; + + // convert to afp inches + double sx = ((afpInfo.width / w) * res) / 72f; + double sy = ((afpInfo.height / h) * res) / 72f; + double xOffset = (afpInfo.currentXPosition * res) / 72000f; + double yOffset = ((afpInfo.height - afpInfo.currentYPosition) * res) / 72000f; + + // 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(sx, 0, 0, -sy, xOffset, yOffset); + graphics.setTransform(trans); + try { + root.paint(graphics); + } catch (Exception e) { + log.error("SVG graphic could not be rendered: " + e.getMessage(), e); + } + } + /** {@inheritDoc} */ public boolean supportsRenderer(Renderer renderer) { return (renderer instanceof AFPRenderer); } + /** {@inheritDoc} */ + public String getNamespace() { + return SVGDOMImplementation.SVG_NAMESPACE_URI; + } } diff --git a/src/java/org/apache/fop/render/afp/AFPState.java b/src/java/org/apache/fop/render/afp/AFPState.java new file mode 100644 index 000000000..a86d55cf9 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPState.java @@ -0,0 +1,238 @@ +/* + * 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.Color; +import java.util.Arrays; + +/** + * This keeps information about the current state when writing to pdf. + */ +public class AFPState { + /** + * The current color + */ + private Color color = null; + + /** + * The current background color + */ + private Color backColor = null; + + /** + * The current font name + */ + private String fontName = null; + + /** + * The current font size + */ + private int fontSize = 0; + + /** + * The current line width + */ + private float lineWidth = 0; + + /** + * The dash array for the current basic stroke (line type) + */ + private float[] dashArray = null; + + /** + * The current fill status + */ + private boolean filled = false; + + /** + * The fonts on the current page + */ + private AFPPageFonts pageFonts = null; + + /** + * 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 + */ + protected boolean setColor(Color col) { + if (!col.equals(this.color)) { + this.color = col; + return true; + } + return false; + } + + /** + * 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 != this.filled) { + this.filled = fill; + return true; + } + return false; + } + + /** + * Get the color. + * @return the color + */ + protected Color getColor() { + if (this.color == null) { + this.color = Color.black; + } + return this.color; + } + + /** + * Set the current line width. + * @param width the line width in points + * @return true if the line width has changed + */ + protected boolean setLineWidth(float width) { + if (this.lineWidth != width) { + this.lineWidth = width; + return true; + } + return false; + } + + /** + * 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, this.dashArray)) { + this.dashArray = dash; + return true; + } + return false; + } + + /** + * Gets the current line width + * @return the current line width + */ + protected float getLineWidth() { + return lineWidth; + } + + /** + * Get the background color. + * @return the background color + */ + protected Color getBackColor() { + if (this.backColor == null) { + this.backColor = Color.white; + } + return 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 + */ + protected boolean setBackColor(Color col) { + if (!col.equals(this.backColor)) { + this.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 + */ + protected boolean setFontName(String internalFontName) { + if (!internalFontName.equals(this.fontName)) { + this.fontName = internalFontName; + return true; + } + return false; + } + + /** + * Gets the current font name + * @return the current font name + */ + protected String getFontName() { + return this.fontName; + } + + /** + * Gets the current font size + * @return the current font size + */ + protected int getFontSize() { + return this.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 + */ + protected boolean setFontSize(int size) { + if (size != this.fontSize) { + this.fontSize = size; + return true; + } + return false; + } + + /** + * Gets the current page fonts + * @return the current page fonts + */ + protected AFPPageFonts getPageFonts() { + if (this.pageFonts == null) { + this.pageFonts = new AFPPageFonts(); + } + return this.pageFonts; + } + + /** + * Resets the current state + */ + protected void reset() { + this.color = null; + this.backColor = null; + this.fontName = null; + this.fontSize = 0; + this.lineWidth = 0; + this.dashArray = null; + this.filled = false; + if (this.pageFonts != null) { + this.pageFonts.clear(); + } + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/AFPTextElementBridge.java b/src/java/org/apache/fop/render/afp/AFPTextElementBridge.java new file mode 100644 index 000000000..150cbb236 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPTextElementBridge.java @@ -0,0 +1,110 @@ +/* + * 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: PSTextElementBridge.java 426576 2006-07-28 15:44:37Z jeremias $ */ + +package org.apache.fop.render.afp; + +import org.apache.batik.bridge.SVGTextElementBridge; +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.gvt.GraphicsNode; +import org.apache.batik.gvt.TextNode; +import org.apache.batik.gvt.TextPainter; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * Bridge class for the <text> element. + * This bridge will use the direct text painter if the text + * for the element is simple. + */ +public class AFPTextElementBridge extends SVGTextElementBridge { + + private AFPTextPainter textPainter; + + /** + * Constructs a new bridge for the <text> element. + * @param textPainter the text painter to use + */ + public AFPTextElementBridge(AFPTextPainter textPainter) { + this.textPainter = textPainter; + } + + /** + * Create a text element bridge. + * This set the text painter on the node if the text is simple. + * @param ctx the bridge context + * @param e the svg element + * @return the text graphics node created by the super class + */ + public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) { + GraphicsNode node = super.createGraphicsNode(ctx, e); + if (node != null && isSimple(ctx, e, node)) { + ((TextNode)node).setTextPainter(getTextPainter()); + } + return node; + } + + private TextPainter getTextPainter() { + return this.textPainter; + } + + /** + * Check if text element contains simple text. + * This checks the children of the text element to determine + * if the text is simple. The text is simple if it can be rendered + * with basic text drawing algorithms. This means there are no + * alternate characters, the font is known and there are no effects + * applied to the text. + * + * @param ctx the bridge context + * @param element the svg text element + * @param node the graphics node + * @return true if this text is simple of false if it cannot be + * easily rendered using normal drawString on the PDFGraphics2D + */ + private boolean isSimple(BridgeContext ctx, Element element, GraphicsNode node) { + for (Node n = element.getFirstChild(); + n != null; + n = n.getNextSibling()) { + + switch (n.getNodeType()) { + case Node.ELEMENT_NODE: + + if (n.getLocalName().equals(SVG_TSPAN_TAG) + || n.getLocalName().equals(SVG_ALT_GLYPH_TAG)) { + return false; + } else if (n.getLocalName().equals(SVG_TEXT_PATH_TAG)) { + return false; + } else if (n.getLocalName().equals(SVG_TREF_TAG)) { + return false; + } + break; + case Node.TEXT_NODE: + case Node.CDATA_SECTION_NODE: + default: + } + } + + /*if (CSSUtilities.convertFilter(element, node, ctx) != null) { + return false; + }*/ + + return true; + } +} + diff --git a/src/java/org/apache/fop/render/afp/AFPTextHandler.java b/src/java/org/apache/fop/render/afp/AFPTextHandler.java new file mode 100644 index 000000000..a6e8ffeb8 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPTextHandler.java @@ -0,0 +1,106 @@ +/* + * 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.Color; +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.fonts.Font; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.render.afp.fonts.AFPFont; +import org.apache.fop.render.afp.modca.GraphicsObject; + +import org.apache.xmlgraphics.java2d.TextHandler; + +/** + * Specialized TextHandler implementation that the AFPGraphics2D class delegates to to paint text + * using AFP GOCA text operations. + */ +public class AFPTextHandler implements TextHandler { + + /** logging instance */ + private static Log log = LogFactory.getLog(AFPTextHandler.class); + + private AFPGraphics2D g2d = null; + + /** Overriding FontState */ + protected Font overrideFont = null; + + /** current state */ + private AFPState afpState = null; + + /** + * Main constructor. + * @param g2d the PSGraphics2D instance this instances is used by + */ + public AFPTextHandler(AFPGraphics2D g2d) { + this.g2d = g2d; + this.afpState = g2d.getAFPInfo().getState(); + } + + /** + * Return the font information associated with this object + * @return the FontInfo object + */ + public FontInfo getFontInfo() { + return g2d.getAFPInfo().getFontInfo(); + } + + /** + * Add a text string to the current data object of the AFP datastream. + * The text is painted using text operations. + * {@inheritDoc} + */ + public void drawString(String str, float x, float y) throws IOException { + log.debug("drawString() str=" + str + ", x=" + x + ", y=" + y); + GraphicsObject graphicsObj = g2d.getGraphicsObject(); + Color col = g2d.getColor(); + if (afpState.setColor(col)) { + graphicsObj.setColor(col); + } + if (overrideFont != null) { + FontInfo fontInfo = getFontInfo(); + AFPPageFonts pageFonts = this.afpState.getPageFonts(); + String internalFontName = overrideFont.getFontName(); + int fontSize = overrideFont.getFontSize(); + if (afpState.setFontName(internalFontName) || afpState.setFontSize(fontSize)) { + AFPFont font = (AFPFont)fontInfo.getFonts().get(internalFontName); + AFPFontAttributes afpFontAttributes = pageFonts.registerFont( + internalFontName, + font, + fontSize + ); + int fontReference = afpFontAttributes.getFontReference(); + graphicsObj.setCharacterSet(fontReference); + } + } + graphicsObj.addString(str, (int)Math.round(x), (int)Math.round(y)); + } + + /** + * Sets the overriding font. + * @param overrideFont Overriding Font to set + */ + public void setOverrideFont(Font overrideFont) { + this.overrideFont = overrideFont; + } +} diff --git a/src/java/org/apache/fop/render/afp/AFPTextPainter.java b/src/java/org/apache/fop/render/afp/AFPTextPainter.java new file mode 100644 index 000000000..66183080f --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPTextPainter.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: PSTextPainter.java 542237 2007-05-28 14:31:24Z jeremias $ */ + +package org.apache.fop.render.afp; + +import java.awt.Graphics2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.text.AttributedCharacterIterator; +import java.text.CharacterIterator; +import java.awt.font.TextAttribute; +import java.awt.Shape; +import java.awt.Paint; +import java.awt.Color; +import java.io.IOException; +import java.util.List; +import java.util.Iterator; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.batik.dom.svg.SVGOMTextElement; +import org.apache.batik.gvt.text.Mark; +import org.apache.batik.gvt.TextPainter; +import org.apache.batik.gvt.TextNode; +import org.apache.batik.gvt.text.GVTAttributedCharacterIterator; +import org.apache.batik.gvt.text.TextPaintInfo; +import org.apache.batik.gvt.font.GVTFontFamily; +import org.apache.batik.gvt.renderer.StrokingTextPainter; + +import org.apache.fop.fonts.Font; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontTriplet; + +/** + * Renders the attributed character iterator of a <tt>TextNode</tt>. + * This class draws the text directly into the AFPGraphics2D so that + * the text is not drawn using shapes. + * If the text is simple enough to draw then it sets the font and calls + * drawString. If the text is complex or the cannot be translated + * into a simple drawString the StrokingTextPainter is used instead. + */ +public class AFPTextPainter implements TextPainter { + + /** the logger for this class */ + protected Log log = LogFactory.getLog(AFPTextPainter.class); + + private AFPTextHandler nativeTextHandler; + //private FontInfo fontInfo; + + /** + * Use the stroking text painter to get the bounds and shape. + * Also used as a fallback to draw the string with strokes. + */ + protected static final TextPainter + PROXY_PAINTER = StrokingTextPainter.getInstance(); + + /** + * Create a new PS text painter with the given font information. + * @param nativeTextHandler the NativeTextHandler instance used for text painting + */ + public AFPTextPainter(AFPTextHandler nativeTextHandler) { + this.nativeTextHandler = nativeTextHandler; + } + + /** + * Paints the specified attributed character iterator using the + * specified Graphics2D and context and font context. + * @param node the TextNode to paint + * @param g2d the Graphics2D to use + */ + public void paint(TextNode node, Graphics2D g2d) { + Point2D loc = node.getLocation(); + log.debug("painting text node " + node); + if (hasUnsupportedAttributes(node)) { + log.debug("hasunsuportedattributes"); + PROXY_PAINTER.paint(node, g2d); + } else { + log.debug("allattributessupported"); + paintTextRuns(node.getTextRuns(), g2d, loc); + } + } + + private boolean hasUnsupportedAttributes(TextNode node) { + Iterator iter = node.getTextRuns().iterator(); + while (iter.hasNext()) { + StrokingTextPainter.TextRun + run = (StrokingTextPainter.TextRun)iter.next(); + AttributedCharacterIterator aci = run.getACI(); + boolean hasUnsupported = hasUnsupportedAttributes(aci); + if (hasUnsupported) { + return true; + } + } + return false; + } + + private boolean hasUnsupportedAttributes(AttributedCharacterIterator aci) { + boolean hasunsupported = false; + + String text = getText(aci); + Font font = makeFont(aci); + if (hasUnsupportedGlyphs(text, font)) { + log.trace("-> Unsupported glyphs found"); + hasunsupported = true; + } + + TextPaintInfo tpi = (TextPaintInfo) aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO); + if ((tpi != null) + && ((tpi.strokeStroke != null && tpi.strokePaint != null) + || (tpi.strikethroughStroke != null) + || (tpi.underlineStroke != null) + || (tpi.overlineStroke != null))) { + log.trace("-> under/overlines etc. found"); + hasunsupported = true; + } + + //Alpha is not supported + Paint foreground = (Paint) aci.getAttribute(TextAttribute.FOREGROUND); + if (foreground instanceof Color) { + Color col = (Color)foreground; + if (col.getAlpha() != 255) { + log.trace("-> transparency found"); + hasunsupported = true; + } + } + + Object letSpace = aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.LETTER_SPACING); + if (letSpace != null) { + log.trace("-> letter spacing found"); + hasunsupported = true; + } + + Object wordSpace = aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.WORD_SPACING); + if (wordSpace != null) { + log.trace("-> word spacing found"); + hasunsupported = true; + } + + Object lengthAdjust = aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.LENGTH_ADJUST); + if (lengthAdjust != null) { + log.trace("-> length adjustments found"); + hasunsupported = true; + } + + Object writeMod = aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE); + if (writeMod != null + && !GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE_LTR.equals( + writeMod)) { + log.trace("-> Unsupported writing modes found"); + hasunsupported = true; + } + + Object vertOr = aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION); + if (GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_ANGLE.equals( + vertOr)) { + log.trace("-> vertical orientation found"); + hasunsupported = true; + } + + Object rcDel = aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.TEXT_COMPOUND_DELIMITER); + //Batik 1.6 returns null here which makes it impossible to determine whether this can + //be painted or not, i.e. fall back to stroking. :-( + if (rcDel != null && !(rcDel instanceof SVGOMTextElement)) { + log.trace("-> spans found"); + hasunsupported = true; //Filter spans + } + + if (hasunsupported) { + log.trace("Unsupported attributes found in ACI, using StrokingTextPainter"); + } + return hasunsupported; + } + + /** + * Paint a list of text runs on the Graphics2D at a given location. + * @param textRuns the list of text runs + * @param g2d the Graphics2D to paint to + * @param loc the current location of the "cursor" + */ + protected void paintTextRuns(List textRuns, Graphics2D g2d, Point2D loc) { + Point2D currentloc = loc; + Iterator i = textRuns.iterator(); + while (i.hasNext()) { + StrokingTextPainter.TextRun + run = (StrokingTextPainter.TextRun)i.next(); + currentloc = paintTextRun(run, g2d, currentloc); + } + } + + /** + * Paint a single text run on the Graphics2D at a given location. + * @param run the text run to paint + * @param g2d the Graphics2D to paint to + * @param loc the current location of the "cursor" + * @return the new location of the "cursor" after painting the text run + */ + protected Point2D paintTextRun(StrokingTextPainter.TextRun run, Graphics2D g2d, Point2D loc) { + AttributedCharacterIterator aci = run.getACI(); + aci.first(); + + updateLocationFromACI(aci, loc); + loc = g2d.getTransform().transform(loc, null); + + // font + Font font = makeFont(aci); + nativeTextHandler.setOverrideFont(font); + + // color + TextPaintInfo tpi = (TextPaintInfo) aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO); + if (tpi == null) { + return loc; + } + Paint foreground = tpi.fillPaint; + if (foreground instanceof Color) { + Color col = (Color)foreground; + g2d.setColor(col); + } + g2d.setPaint(foreground); + + String txt = getText(aci); + float advance = getStringWidth(txt, font); + float tx = 0; + TextNode.Anchor anchor = (TextNode.Anchor)aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE); + if (anchor != null) { + switch (anchor.getType()) { + case TextNode.Anchor.ANCHOR_MIDDLE: + tx = -advance / 2; + break; + case TextNode.Anchor.ANCHOR_END: + tx = -advance; + break; + default: //nop + } + } + + // draw string + try { + try { + nativeTextHandler.drawString(txt, (float)(loc.getX() + tx), (float)(loc.getY())); + } catch (IOException ioe) { + if (g2d instanceof AFPGraphics2D) { + ((AFPGraphics2D)g2d).handleIOException(ioe); + } + } + } finally { + nativeTextHandler.setOverrideFont(null); + } + loc.setLocation(loc.getX() + (double)advance, loc.getY()); + return loc; + } + + /** + * Extract the raw text from an ACI. + * @param aci ACI to inspect + * @return the extracted text + */ + protected String getText(AttributedCharacterIterator aci) { + StringBuffer sb = new StringBuffer(aci.getEndIndex() - aci.getBeginIndex()); + for (char c = aci.first(); c != CharacterIterator.DONE; c = aci.next()) { + sb.append(c); + } + return sb.toString(); + } + + private void updateLocationFromACI( + AttributedCharacterIterator aci, + Point2D loc) { + //Adjust position of span + Float xpos = (Float)aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.X); + Float ypos = (Float)aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.Y); + Float dxpos = (Float)aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.DX); + Float dypos = (Float)aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.DY); + if (xpos != null) { + loc.setLocation(xpos.doubleValue(), loc.getY()); + } + if (ypos != null) { + loc.setLocation(loc.getX(), ypos.doubleValue()); + } + if (dxpos != null) { + loc.setLocation(loc.getX() + dxpos.doubleValue(), loc.getY()); + } + if (dypos != null) { + loc.setLocation(loc.getX(), loc.getY() + dypos.doubleValue()); + } + } + + private String getStyle(AttributedCharacterIterator aci) { + Float posture = (Float)aci.getAttribute(TextAttribute.POSTURE); + return ((posture != null) && (posture.floatValue() > 0.0)) + ? "italic" + : "normal"; + } + + private int getWeight(AttributedCharacterIterator aci) { + Float taWeight = (Float)aci.getAttribute(TextAttribute.WEIGHT); + return ((taWeight != null) && (taWeight.floatValue() > 1.0)) + ? Font.WEIGHT_BOLD + : Font.WEIGHT_NORMAL; + } + + private Font makeFont(AttributedCharacterIterator aci) { + Float fontSize = (Float)aci.getAttribute(TextAttribute.SIZE); + if (fontSize == null) { + fontSize = new Float(10.0f); + } + String style = getStyle(aci); + int weight = getWeight(aci); + + FontInfo fontInfo = nativeTextHandler.getFontInfo(); + String fontFamily = null; + List gvtFonts = (List) aci.getAttribute( + GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES); + if (gvtFonts != null) { + Iterator i = gvtFonts.iterator(); + while (i.hasNext()) { + GVTFontFamily fam = (GVTFontFamily) i.next(); + /* (todo) Enable SVG Font painting + if (fam instanceof SVGFontFamily) { + PROXY_PAINTER.paint(node, g2d); + return; + }*/ + fontFamily = fam.getFamilyName(); + if (fontInfo.hasFont(fontFamily, style, weight)) { + FontTriplet triplet = fontInfo.fontLookup( + fontFamily, style, weight); + int fsize = (int)(fontSize.floatValue() * 1000); + return fontInfo.getFontInstance(triplet, fsize); + } + } + } + FontTriplet triplet = fontInfo.fontLookup("any", style, Font.WEIGHT_NORMAL); + int fsize = (int)(fontSize.floatValue() * 1000); + return fontInfo.getFontInstance(triplet, fsize); + } + + private float getStringWidth(String str, Font font) { + float wordWidth = 0; + float whitespaceWidth = font.getWidth(font.mapChar(' ')); + + for (int i = 0; i < str.length(); i++) { + float charWidth; + char c = str.charAt(i); + if (!((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))) { + charWidth = font.getWidth(font.mapChar(c)); + if (charWidth <= 0) { + charWidth = whitespaceWidth; + } + } else { + charWidth = whitespaceWidth; + } + wordWidth += charWidth; + } + return wordWidth / 1000f; + } + + private boolean hasUnsupportedGlyphs(String str, Font font) { + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (!((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))) { + if (!font.hasChar(c)) { + return true; + } + } + } + return false; + } + + /** + * Get the outline shape of the text characters. + * This uses the StrokingTextPainter to get the outline + * shape since in theory it should be the same. + * + * @param node the text node + * @return the outline shape of the text characters + */ + public Shape getOutline(TextNode node) { + return PROXY_PAINTER.getOutline(node); + } + + /** + * Get the bounds. + * This uses the StrokingTextPainter to get the bounds + * since in theory it should be the same. + * + * @param node the text node + * @return the bounds of the text + */ + public Rectangle2D getBounds2D(TextNode node) { + /* (todo) getBounds2D() is too slow + * because it uses the StrokingTextPainter. We should implement this + * method ourselves. */ + return PROXY_PAINTER.getBounds2D(node); + } + + /** + * Get the geometry bounds. + * This uses the StrokingTextPainter to get the bounds + * since in theory it should be the same. + * @param node the text node + * @return the bounds of the text + */ + public Rectangle2D getGeometryBounds(TextNode node) { + return PROXY_PAINTER.getGeometryBounds(node); + } + + // Methods that have no purpose for PS + + /** + * Get the mark. + * This does nothing since the output is pdf and not interactive. + * @param node the text node + * @param pos the position + * @param all select all + * @return null + */ + public Mark getMark(TextNode node, int pos, boolean all) { + return null; + } + + /** + * Select at. + * This does nothing since the output is pdf and not interactive. + * @param x the x position + * @param y the y position + * @param node the text node + * @return null + */ + public Mark selectAt(double x, double y, TextNode node) { + return null; + } + + /** + * Select to. + * This does nothing since the output is pdf and not interactive. + * @param x the x position + * @param y the y position + * @param beginMark the start mark + * @return null + */ + public Mark selectTo(double x, double y, Mark beginMark) { + return null; + } + + /** + * Selec first. + * This does nothing since the output is pdf and not interactive. + * @param node the text node + * @return null + */ + public Mark selectFirst(TextNode node) { + return null; + } + + /** + * Select last. + * This does nothing since the output is pdf and not interactive. + * @param node the text node + * @return null + */ + public Mark selectLast(TextNode node) { + return null; + } + + /** + * Get selected. + * This does nothing since the output is pdf and not interactive. + * @param start the start mark + * @param finish the finish mark + * @return null + */ + public int[] getSelected(Mark start, Mark finish) { + return null; + } + + /** + * Get the highlighted shape. + * This does nothing since the output is pdf and not interactive. + * @param beginMark the start mark + * @param endMark the end mark + * @return null + */ + public Shape getHighlightShape(Mark beginMark, Mark endMark) { + return null; + } + +} diff --git a/src/java/org/apache/fop/render/afp/modca/AFPDataStream.java b/src/java/org/apache/fop/render/afp/modca/AFPDataStream.java index ba37b989e..62de923c8 100644 --- a/src/java/org/apache/fop/render/afp/modca/AFPDataStream.java +++ b/src/java/org/apache/fop/render/afp/modca/AFPDataStream.java @@ -22,9 +22,12 @@ package org.apache.fop.render.afp.modca; import java.awt.Color; import java.io.IOException; import java.io.OutputStream; +import java.util.Iterator; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.render.afp.AFPFontAttributes; import org.apache.fop.render.afp.fonts.AFPFont; import org.apache.fop.render.afp.tools.StringUtils; @@ -132,7 +135,7 @@ public class AFPDataStream { * The outputstream for the data stream */ private OutputStream outputStream = null; - + /** * Default constructor for the AFPDataStream. */ @@ -147,7 +150,6 @@ public class AFPDataStream { * the outputStream which the document is written to. */ public void startDocument(OutputStream docOutputStream) { - if (document != null) { String msg = "Invalid state - document already started."; log.warn("startDocument():: " + msg); @@ -156,7 +158,6 @@ public class AFPDataStream { this.document = new Document(); this.outputStream = docOutputStream; - } /** @@ -168,7 +169,6 @@ public class AFPDataStream { * throws an I/O exception of some sort has occurred */ public void endDocument() throws IOException { - if (complete) { String msg = "Invalid state - document already ended."; log.warn("endDocument():: " + msg); @@ -206,19 +206,19 @@ public class AFPDataStream { * the height of the page * @param pageRotation * the rotation of the page - * @param pageWidthResolution + * @param pageWidthRes * the width resolution of the page - * @param pageHeightResolution + * @param pageHeightRes * the height resolution of the page */ public void startPage(int pageWidth, int pageHeight, int pageRotation, - int pageWidthResolution, int pageHeightResolution) { + int pageWidthRes, int pageHeightRes) { String pageName = "PGN" + StringUtils.lpad(String.valueOf(pageCount++), '0', 5); currentPageObject = new PageObject(pageName, pageWidth, pageHeight, - pageRotation, pageWidthResolution, pageHeightResolution); + pageRotation, pageWidthRes, pageHeightRes); currentPage = currentPageObject; currentOverlay = null; setOffsets(0, 0, 0); @@ -265,11 +265,9 @@ public class AFPDataStream { * Helper method to mark the end of the current overlay. */ public void endOverlay() { - currentOverlay.endPage(); currentOverlay = null; currentPage = currentPageObject; - } /** @@ -278,7 +276,6 @@ public class AFPDataStream { * @return current page object that was saved */ public PageObject savePage() { - PageObject pageObject = currentPageObject; if (currentPageGroup != null) { currentPageGroup.addPage(currentPageObject); @@ -288,7 +285,6 @@ public class AFPDataStream { currentPageObject = null; currentPage = null; return pageObject; - } /** @@ -298,10 +294,8 @@ public class AFPDataStream { * page object */ public void restorePage(PageObject pageObject) { - currentPageObject = pageObject; currentPage = pageObject; - } /** @@ -311,7 +305,6 @@ public class AFPDataStream { * thrown when an I/O exception of some sort has occurred */ public void endPage() throws IOException { - currentPageObject.endPage(); if (currentPageGroup != null) { currentPageGroup.addPage(currentPageObject); @@ -319,10 +312,8 @@ public class AFPDataStream { document.addPage(currentPageObject); document.writeDataStream(this.outputStream); } - currentPageObject = null; currentPage = null; - } /** @@ -342,6 +333,21 @@ public class AFPDataStream { } /** + * Creates the given page fonts in the current page + * @param pageFonts a collection of AFP font attributes + */ + public void addFontsToCurrentPage(Map pageFonts) { + Iterator iter = pageFonts.values().iterator(); + while (iter.hasNext()) { + AFPFontAttributes afpFontAttributes = (AFPFontAttributes)iter.next(); + createFont( + afpFontAttributes.getFontReference(), + afpFontAttributes.getFont(), + afpFontAttributes.getPointSize()); + } + } + + /** * Helper method to create a map coded font object on the current page, this * method delegates the construction of the map coded font object to the * active environment group on the current page. @@ -353,18 +359,17 @@ public class AFPDataStream { * @param size * the point size of the font */ - public void createFont(byte fontReference, AFPFont font, int size) { - + public void createFont(int fontReference, AFPFont font, int size) { currentPage.createFont(fontReference, font, size); - } + /** * Helper method to create text on the current page, this method delegates * to the current presentation text object in order to construct the text. * - * @param fontNumber - * the font number used as the resource identifier + * @param fontReference + * the font reference used as the resource identifier * @param x * the x coordinate of the text * @param y @@ -378,81 +383,125 @@ public class AFPDataStream { * @param data * the text data to create */ - public void createText(int fontNumber, int x, int y, Color col, int vsci, + public void createText(int fontReference, int x, int y, Color col, int vsci, int ica, byte[] data) { - - currentPage.createText(fontNumber, x + xOffset, y + yOffset, rotation, + currentPage.createText(fontReference, x + xOffset, y + yOffset, rotation, col, vsci, ica, data); - } /** * Returns an ImageObject used to create an image in the datastream. - * + * * @param x * the x position of the image * @param y * the y position of the image - * @param w + * @param width * the width of the image - * @param h + * @param height * the height of the image + * @param widthRes + * the resolution width of the image + * @param heightRes + * the resolution height of the image + * @return + * a new image object + */ + public ImageObject getImageObject(int x, int y, int width, int height, + int widthRes, int heightRes) { + ImageObject imageObj = currentPage.getImageObject(); + setObjectViewPort(imageObj, x, y, width, height, widthRes, heightRes); + return imageObj; + } + + /** + * Returns an GraphicObject used to create an graphic in the datastream. + * + * @param x + * the x position of the graphic + * @param y + * the y position of the graphic + * @param width + * the width of the graphic + * @param height + * the height of the graphic + * @param widthRes + * the resolution width of the graphic + * @param heightRes + * the resolution height of the graphic + * @return + * a new graphics object + */ + public GraphicsObject getGraphicsObject(int x, int y, int width, int height, + int widthRes, int heightRes) { + GraphicsObject graphicsObj = currentPage.getGraphicsObject(); + setObjectViewPort(graphicsObj, x, y, width, height, widthRes, heightRes); + return graphicsObj; + } + + /** + * Sets the object view port taking into account rotation. + * + * @param x + * the x position of the object + * @param y + * the y position of the object + * @param w + * the width of the object + * @param h + * the height of the object * @param wr - * the width resolution of the image + * the resolution width of the object * @param hr - * the height resolution of the image - * @return ImageObject used to create an image in the datastream + * the resolution height of the object + * @return + * a new graphics object */ - public ImageObject getImageObject(int x, int y, int w, int h, int wr, int hr) { - + private void setObjectViewPort(AbstractDataObject dataObj, + int x, int y, int w, int h, int wr, int hr) { int xOrigin; int yOrigin; int width; int height; - int widthResolution; - int heightResolution; - - switch (rotation) { + int widthRes; + int heightRes; + switch (this.rotation) { case 90: xOrigin = currentPage.getWidth() - y - yOffset; yOrigin = x + xOffset; width = h; height = w; - widthResolution = hr; - heightResolution = wr; + widthRes = hr; + heightRes = wr; break; case 180: xOrigin = currentPage.getWidth() - x - xOffset; yOrigin = currentPage.getHeight() - y - yOffset; width = w; height = h; - widthResolution = wr; - heightResolution = hr; + widthRes = wr; + heightRes = hr; break; case 270: xOrigin = y + yOffset; yOrigin = currentPage.getHeight() - x - xOffset; width = h; height = w; - widthResolution = hr; - heightResolution = wr; + widthRes = hr; + heightRes = wr; break; default: xOrigin = x + xOffset; yOrigin = y + yOffset; width = w; height = h; - widthResolution = wr; - heightResolution = hr; + widthRes = wr; + heightRes = hr; break; } - ImageObject io = currentPage.getImageObject(); - io.setImageViewport(xOrigin, yOrigin, width, height, rotation, - widthResolution, heightResolution); - return io; - + dataObj.setViewport(xOrigin, yOrigin, width, height, widthRes, heightRes, rotation); } - + /** * Method to create a line on the current page. * @@ -471,10 +520,8 @@ public class AFPDataStream { */ public void createLine(int x1, int y1, int x2, int y2, int thickness, Color col) { - currentPage.createLine(x1 + xOffset, y1 + yOffset, x2 + xOffset, y2 + yOffset, thickness, rotation, col); - } /** @@ -499,10 +546,8 @@ public class AFPDataStream { */ public void createShading(int x, int y, int w, int h, int red, int green, int blue) { - currentPage.createShading(x + xOffset, y + xOffset, w, h, red, green, blue); - } /** @@ -513,12 +558,10 @@ public class AFPDataStream { * the name of the static overlay */ public void createIncludePageOverlay(String name) { - currentPageObject.createIncludePageOverlay(name, 0, 0, rotation); ActiveEnvironmentGroup aeg = currentPageObject .getActiveEnvironmentGroup(); aeg.createOverlay(name); - } /** @@ -528,12 +571,10 @@ public class AFPDataStream { * the name of the medium map */ public void createInvokeMediumMap(String name) { - if (currentPageGroup == null) { startPageGroup(); } currentPageGroup.createInvokeMediumMap(name); - } /** @@ -547,7 +588,6 @@ public class AFPDataStream { * the y coordinate for the overlay */ public void createIncludePageSegment(String name, int x, int y) { - int xOrigin; int yOrigin; switch (rotation) { @@ -569,7 +609,6 @@ public class AFPDataStream { break; } currentPage.createIncludePageSegment(name, xOrigin, yOrigin); - } /** @@ -579,13 +618,11 @@ public class AFPDataStream { * the array of key value pairs. */ public void createPageTagLogicalElement(TagLogicalElementBean[] attributes) { - for (int i = 0; i < attributes.length; i++) { String name = (String) attributes[i].getKey(); String value = (String) attributes[i].getValue(); currentPage.createTagLogicalElement(name, value); } - } /** @@ -594,15 +631,12 @@ public class AFPDataStream { * @param attributes * the array of key value pairs. */ - public void createPageGroupTagLogicalElement( - TagLogicalElementBean[] attributes) { - + public void createPageGroupTagLogicalElement(TagLogicalElementBean[] attributes) { for (int i = 0; i < attributes.length; i++) { String name = (String) attributes[i].getKey(); String value = (String) attributes[i].getValue(); currentPageGroup.createTagLogicalElement(name, value); } - } /** @@ -614,13 +648,11 @@ public class AFPDataStream { * The tag value */ public void createTagLogicalElement(String name, String value) { - if (currentPageGroup != null) { currentPageGroup.createTagLogicalElement(name, value); } else { currentPage.createTagLogicalElement(name, value); } - } /** @@ -697,5 +729,4 @@ public class AFPDataStream { } } - } diff --git a/src/java/org/apache/fop/render/afp/modca/AbstractAFPObject.java b/src/java/org/apache/fop/render/afp/modca/AbstractAFPObject.java index ef1b988c0..cd8b25810 100644 --- a/src/java/org/apache/fop/render/afp/modca/AbstractAFPObject.java +++ b/src/java/org/apache/fop/render/afp/modca/AbstractAFPObject.java @@ -44,7 +44,7 @@ public abstract class AbstractAFPObject { * DataStream objects must implement the writeDataStream() * method to write its data to the given OutputStream * @param os The outputsteam stream - * @throws java.io.IOException + * @throws java.io.IOException in the event that an I/O exception occurred */ public abstract void writeDataStream(OutputStream os) throws IOException; @@ -52,15 +52,14 @@ public abstract class AbstractAFPObject { * Help method to write a set of AFPObjects to the AFP datastream. * @param afpObjects a list of AFPObjects * @param os The stream to write to - * @throws java.io.IOException + * @throws java.io.IOException in the event that an I/O exception occurred */ protected void writeObjectList(List afpObjects, OutputStream os) - throws IOException { + throws IOException { - for (Iterator it = afpObjects.iterator(); it.hasNext(); ) { + Iterator it = afpObjects.iterator(); + while (it.hasNext()) { ((AbstractAFPObject)it.next()).writeDataStream(os); } - } - } diff --git a/src/java/org/apache/fop/render/afp/modca/AbstractDataObject.java b/src/java/org/apache/fop/render/afp/modca/AbstractDataObject.java new file mode 100644 index 000000000..363e5c6e4 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/AbstractDataObject.java @@ -0,0 +1,90 @@ +/* + * 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.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.render.afp.modca.goca.AbstractGraphicsContainer; + +/** + * Abstract base class used by the ImageObject and GraphicsObject which both + * have define an ObjectEnvironmentGroup + */ +public abstract class AbstractDataObject extends AbstractGraphicsContainer { + + /** + * The object environment group + */ + protected ObjectEnvironmentGroup objectEnvironmentGroup = null; + + /** + * Named constructor + * @param name data object name + */ + public AbstractDataObject(String name) { + super(name); + } + + /** + * Sets the object display area position and size. + * + * @param x + * the x position of the object + * @param y + * the y position of the object + * @param width + * the width of the object + * @param height + * the height of the object + * @param widthRes + * the resolution width + * @param heightRes + * the resolution height + * @param rotation + * the rotation of the object + */ + public void setViewport(int x, int y, int width, int height, + int widthRes, int heightRes, int rotation) { + if (objectEnvironmentGroup == null) { + objectEnvironmentGroup = new ObjectEnvironmentGroup(); + } + objectEnvironmentGroup.setObjectArea(x, y, width, height, + widthRes, heightRes, rotation); + } + + /** + * Sets the ObjectEnvironmentGroup. + * @param objectEnvironmentGroup The objectEnvironmentGroup to set + */ + public void setObjectEnvironmentGroup(ObjectEnvironmentGroup objectEnvironmentGroup) { + this.objectEnvironmentGroup = objectEnvironmentGroup; + } + + /** + * {@inheritDoc} + */ + protected void writeContent(OutputStream os) throws IOException { + if (objectEnvironmentGroup != null) { + objectEnvironmentGroup.writeDataStream(os); + } + super.writeContent(os); + } +} diff --git a/src/java/org/apache/fop/render/afp/modca/AbstractDescriptor.java b/src/java/org/apache/fop/render/afp/modca/AbstractDescriptor.java index 6d827766e..29c619d32 100644 --- a/src/java/org/apache/fop/render/afp/modca/AbstractDescriptor.java +++ b/src/java/org/apache/fop/render/afp/modca/AbstractDescriptor.java @@ -28,22 +28,22 @@ public abstract class AbstractDescriptor extends AbstractAFPObject { /** height of this descriptor */ protected int height = 0; /** width resolution of this descriptor */ - protected int widthResolution = 0; + protected int widthRes = 0; /** height resolution of this descriptor */ - protected int heightResolution = 0; + protected int heightRes = 0; /** * Constructor a PresentationTextDescriptor for the specified * width and height. * @param width The width of the page. * @param height The height of the page. - * @param widthResolution The width resolution of the page. - * @param heightResolution The height resolution of the page. + * @param widthRes The width resolution of the page. + * @param heightRes The height resolution of the page. */ - public AbstractDescriptor(int width, int height, int widthResolution, int heightResolution) { + public AbstractDescriptor(int width, int height, int widthRes, int heightRes) { this.width = width; this.height = height; - this.widthResolution = widthResolution; - this.heightResolution = heightResolution; + this.widthRes = widthRes; + this.heightRes = heightRes; } } diff --git a/src/java/org/apache/fop/render/afp/modca/AbstractNamedAFPObject.java b/src/java/org/apache/fop/render/afp/modca/AbstractNamedAFPObject.java index d8c99fa9a..7545ee3af 100644 --- a/src/java/org/apache/fop/render/afp/modca/AbstractNamedAFPObject.java +++ b/src/java/org/apache/fop/render/afp/modca/AbstractNamedAFPObject.java @@ -25,7 +25,7 @@ import java.io.UnsupportedEncodingException; * A named data stream object has an 8 byte EBCIDIC name. */ public abstract class AbstractNamedAFPObject extends AbstractAFPObject { - + /** * The actual name of the object */ @@ -35,35 +35,50 @@ public abstract class AbstractNamedAFPObject extends AbstractAFPObject { * The name of the object in EBCIDIC bytes */ protected byte[] nameBytes; - + + /** + * Default constructor + */ + protected AbstractNamedAFPObject() { + } + + private static final int DEFAULT_NAME_LENGTH = 8; + + /** + * @return the name length of this object + */ + protected int getNameLength() { + return DEFAULT_NAME_LENGTH; + } + /** * Constructor for the ActiveEnvironmentGroup, this takes a * name parameter which should be 8 characters long. * @param name the object name */ public AbstractNamedAFPObject(String name) { - - this.name = name; - if (name.length() < 8) { - name = (name + " ").substring(0, 8); - } else if (name.length() > 8) { - log.warn("Constructor:: name truncated to 8 chars" + name); - name = name.substring(0, 8); + int nameLen = getNameLength(); + if (name.length() < nameLen) { + this.name = (name + " ").substring(0, nameLen); + } else if (name.length() > nameLen) { + log.warn("Constructor:: name truncated to " + nameLen + " chars: " + name); + this.name = name.substring(0, nameLen); + } else { + this.name = name; } try { - nameBytes = name.getBytes(AFPConstants.EBCIDIC_ENCODING); + this.nameBytes = name.getBytes(AFPConstants.EBCIDIC_ENCODING); } catch (UnsupportedEncodingException usee) { - nameBytes = name.getBytes(); + this.nameBytes = name.getBytes(); log.warn( "Constructor:: UnsupportedEncodingException translating the name " + name); } - } - + } } diff --git a/src/java/org/apache/fop/render/afp/modca/AbstractPageObject.java b/src/java/org/apache/fop/render/afp/modca/AbstractPageObject.java index a99b28107..4ffcc4d94 100644 --- a/src/java/org/apache/fop/render/afp/modca/AbstractPageObject.java +++ b/src/java/org/apache/fop/render/afp/modca/AbstractPageObject.java @@ -105,13 +105,13 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject { * the height of the page. * @param rotation * the rotation of the page. - * @param widthResolution + * @param widthRes * the width resolution of the page. - * @param heightResolution + * @param heightRes * the height resolution of the page. */ public AbstractPageObject(String name, int width, int height, int rotation, - int widthResolution, int heightResolution) { + int widthRes, int heightRes) { super(name); this.width = width; @@ -121,8 +121,7 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject { /** * Every page object must have an ActiveEnvironmentGroup */ - activeEnvironmentGroup = new ActiveEnvironmentGroup(width, height, - widthResolution, heightResolution); + activeEnvironmentGroup = new ActiveEnvironmentGroup(width, height, widthRes, heightRes); if (rotation != 0) { switch (rotation) { @@ -138,13 +137,6 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject { default: } } - - /** - * We have a presentation text object per page - */ - presentationTextObject = new PresentationTextObject(); - objects.add(presentationTextObject); - } /** @@ -159,10 +151,8 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject { * @param size * the point size of the font */ - public void createFont(byte fontReference, AFPFont font, int size) { - + public void createFont(int fontReference, AFPFont font, int size) { activeEnvironmentGroup.createFont(fontReference, font, size, 0); - } /** @@ -186,20 +176,14 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject { */ public void createLine(int x1, int y1, int x2, int y2, int thickness, int lineRotation, Color col) { - - if (presentationTextObject == null) { - presentationTextObject = new PresentationTextObject(); - objects.add(presentationTextObject); - } - presentationTextObject.createLineData(x1, y1, x2, y2, thickness, lineRotation, col); - + getPresentationTextObject().createLineData(x1, y1, x2, y2, thickness, lineRotation, col); } /** * Helper method to create text on the current page, this method delegates * to the presentation text object in order to construct the text. * - * @param fontNumber + * @param fontReference * the font number used as the resource identifier * @param x * the x coordinate of the text data @@ -216,15 +200,10 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject { * @param data * the text data to create */ - public void createText(int fontNumber, int x, int y, int textRotation, Color col, + public void createText(int fontReference, int x, int y, int textRotation, Color col, int vsci, int ica, byte[] data) { - - if (presentationTextObject == null) { - presentationTextObject = new PresentationTextObject(); - objects.add(presentationTextObject); - } - presentationTextObject.createTextData(fontNumber, x, y, textRotation, col, vsci, ica, data); - + getPresentationTextObject().createTextData( + fontReference, x, y, textRotation, col, vsci, ica, data); } /** @@ -232,13 +211,10 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject { * sequence on the current presenation text object. */ public void endPage() { - if (presentationTextObject != null) { presentationTextObject.endControlSequence(); } - complete = true; - } /** @@ -327,6 +303,19 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject { } /** + * Helper method to create a presentation text object + * on the current page and to return the object. + * @return the presentation text object + */ + private PresentationTextObject getPresentationTextObject() { + if (presentationTextObject == null) { + this.presentationTextObject = new PresentationTextObject(); + objects.add(this.presentationTextObject); + } + return presentationTextObject; + } + + /** * Helper method to create an image on the current page and to return * the object. * @return the image object @@ -335,16 +324,32 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject { if (presentationTextObject != null) { presentationTextObject.endControlSequence(); + presentationTextObject = null; } - presentationTextObject = null; - String imageName = "IMG" + StringUtils.lpad(String.valueOf(objects.size() + 1), '0', 5); + ImageObject imageObj = new ImageObject(imageName); + objects.add(imageObj); + return imageObj; + } - ImageObject io = new ImageObject(imageName); - objects.add(io); - return io; + /** + * Helper method to create a graphic on the current page and to return + * the object. + * @return the graphics object + */ + public GraphicsObject getGraphicsObject() { + if (presentationTextObject != null) { + presentationTextObject.endControlSequence(); + presentationTextObject = null; + } + String graphicName = "GRA" + + StringUtils.lpad(String.valueOf(objects.size() + 1), + '0', 5); + GraphicsObject graphicsObj = new GraphicsObject(graphicName); + objects.add(graphicsObj); + return graphicsObj; } /** @@ -356,10 +361,8 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject { * the value of the tag */ public void createTagLogicalElement(String name, String value) { - TagLogicalElement tle = new TagLogicalElement(name, value); tagLogicalElements.add(tle); - } /** @@ -368,10 +371,8 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject { * @param content the byte data */ public void createNoOperation(String content) { - NoOperation noOp = new NoOperation(content); objects.add(noOp); - } /** @@ -380,15 +381,13 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject { * @param name * the name of the page segment * @param xCoor - * the x cooridinate of the page segment. + * the x coordinate of the page segment. * @param yCoor - * the y cooridinate of the page segment. + * the y coordinate of the page segment. */ public void createIncludePageSegment(String name, int xCoor, int yCoor) { - IncludePageSegment ips = new IncludePageSegment(name, xCoor, yCoor); segments.add(ips); - } /** @@ -431,5 +430,4 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject { public int getRotation() { return rotation; } - } diff --git a/src/java/org/apache/fop/render/afp/modca/AbstractStructuredAFPObject.java b/src/java/org/apache/fop/render/afp/modca/AbstractStructuredAFPObject.java new file mode 100644 index 000000000..bc2bf9f99 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/AbstractStructuredAFPObject.java @@ -0,0 +1,83 @@ +/* + * 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.modca; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * An abstract class encapsulating an MODCA structured object + */ +public abstract class AbstractStructuredAFPObject extends AbstractNamedAFPObject { + + /** + * Default constructor + */ + public AbstractStructuredAFPObject() { + super(); + } + + /** + * Named constructor + * @param name name of structured object + */ + public AbstractStructuredAFPObject(String name) { + super(name); + } + + /** + * Helper method to write the start of the Object. + * @param os The stream to write to + * @throws an I/O exception if one occurred + */ + protected void writeStart(OutputStream os) throws IOException { + } + + /** + * Helper method to write the contents of the Object. + * @param os The stream to write to + * @throws an I/O exception if one occurred + */ + protected void writeContent(OutputStream os) throws IOException { + } + + /** + * Helper method to write the end of the Object. + * @param os The stream to write to + * @throws an I/O exception if one occurred + */ + protected void writeEnd(OutputStream os) throws IOException { + } + + /** + * Accessor method to write the AFP datastream for the Image Object + * @param os The stream to write to + * @throws java.io.IOException in the event that an I/O exception occurred + */ + public void writeDataStream(OutputStream os) + throws IOException { + + writeStart(os); + + writeContent(os); + + writeEnd(os); + } +} diff --git a/src/java/org/apache/fop/render/afp/modca/ActiveEnvironmentGroup.java b/src/java/org/apache/fop/render/afp/modca/ActiveEnvironmentGroup.java index 3e341c735..eb537b0d7 100644 --- a/src/java/org/apache/fop/render/afp/modca/ActiveEnvironmentGroup.java +++ b/src/java/org/apache/fop/render/afp/modca/ActiveEnvironmentGroup.java @@ -20,7 +20,7 @@ package org.apache.fop.render.afp.modca; import java.io.IOException; import java.io.OutputStream; -import java.util.ArrayList; +import java.util.List; import org.apache.fop.render.afp.fonts.AFPFont; @@ -47,7 +47,7 @@ public final class ActiveEnvironmentGroup extends AbstractNamedAFPObject { /** * The collection of MapCodedFont objects */ - private ArrayList mapCodedFonts = new ArrayList(); + private List mapCodedFonts = new java.util.ArrayList(); /** * The Object Area Descriptor for the active environment group @@ -72,19 +72,19 @@ public final class ActiveEnvironmentGroup extends AbstractNamedAFPObject { /** * The collection of MapPageOverlay objects */ - private ArrayList mapPageOverlays = new ArrayList(); + private List mapPageOverlays = new java.util.ArrayList(); /** * Default constructor for the ActiveEnvironmentGroup. * @param width the page width * @param height the page height - * @param widthResolution the page width resolution - * @param heightResolution the page height resolution + * @param widthRes the page width resolution + * @param heightRes the page height resolution */ public ActiveEnvironmentGroup(int width, int height, - int widthResolution, int heightResolution) { + int widthRes, int heightRes) { - this(DEFAULT_NAME, width, height, widthResolution, heightResolution); + this(DEFAULT_NAME, width, height, widthRes, heightRes); } @@ -94,24 +94,24 @@ public final class ActiveEnvironmentGroup extends AbstractNamedAFPObject { * @param name the active environment group name * @param width the page width * @param height the page height - * @param widthResolution the page width resolution - * @param heightResolution the page height resolution + * @param widthRes the page width resolution + * @param heightRes the page height resolution */ public ActiveEnvironmentGroup(String name, int width, int height, - int widthResolution, int heightResolution) { + int widthRes, int heightRes) { super(name); // Create PageDescriptor - pageDescriptor = new PageDescriptor(width, height, widthResolution, heightResolution); + pageDescriptor = new PageDescriptor(width, height, widthRes, heightRes); // Create ObjectAreaDescriptor objectAreaDescriptor = new ObjectAreaDescriptor(width, height, - widthResolution, heightResolution); + widthRes, heightRes); // Create PresentationTextDataDescriptor presentationTextDataDescriptor = new PresentationTextDescriptor(width, height, - widthResolution, heightResolution); + widthRes, heightRes); } @@ -243,7 +243,7 @@ public final class ActiveEnvironmentGroup extends AbstractNamedAFPObject { * @param orientation the orientation of the font (e.g. 0, 90, 180, 270) */ public void createFont( - byte fontReference, + int fontReference, AFPFont font, int size, int orientation) { @@ -256,7 +256,7 @@ public final class ActiveEnvironmentGroup extends AbstractNamedAFPObject { } try { - + mcf.addFont( fontReference, font, diff --git a/src/java/org/apache/fop/render/afp/modca/GraphicsDataDescriptor.java b/src/java/org/apache/fop/render/afp/modca/GraphicsDataDescriptor.java new file mode 100644 index 000000000..fdeb5c418 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/GraphicsDataDescriptor.java @@ -0,0 +1,118 @@ +/* + * 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.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.render.afp.tools.BinaryUtils; + +/** + * GOCA Graphics Data Descriptor + */ +public class GraphicsDataDescriptor extends AbstractAFPObject { + + private int xlwind; + private int xrwind; + private int ybwind; + private int ytwind; + private int xresol; + private int yresol; + + /** + * Main constructor + * @param xresol the x resolution of the graphics window + * @param yresol the y resolution of the graphics window + * @param xlwind the left edge of the graphics window + * @param xrwind the right edge of the graphics window + * @param ybwind the top edge of the graphics window + * @param ytwind the bottom edge of the graphics window + */ + protected GraphicsDataDescriptor(int xresol, int yresol, + int xlwind, int xrwind, int ybwind, int ytwind) { + this.xresol = xresol; + this.yresol = yresol; + this.xlwind = xlwind; + this.xrwind = xrwind; + this.ybwind = ybwind; + this.ytwind = ytwind; + } + + private static final int ABS = 2; + private static final int IMGRES = 8; + + /** + * {@inheritDoc} + */ + public void writeDataStream(OutputStream os) throws IOException { + byte[] xreswind = BinaryUtils.convert(xresol * 10, 2); + byte[] yreswind = BinaryUtils.convert(yresol * 10, 2); + byte[] xlcoord = BinaryUtils.convert(xlwind, 2); + byte[] xrcoord = BinaryUtils.convert(xrwind, 2); + byte[] xbcoord = BinaryUtils.convert(ybwind, 2); + byte[] ytcoord = BinaryUtils.convert(ytwind, 2); + byte[] imxyres = xreswind; + byte[] data = new byte[] { + 0x5A, + 0x00, + 0x25, + (byte) 0xD3, + (byte) 0xA6, + (byte) 0xBB, + 0x00, // Flags + 0x00, // Reserved + 0x00, // Reserved + + // Drawing order subset + (byte) 0xF7, + 7, // LENGTH + (byte) 0xB0, // drawing order subset + 0x00, // reserved (must be zero) + 0x00, // reserved (must be zero) + 0x02, // SUBLEV + 0x00, // VERSION 0 + 0x01, // LENGTH (of following field) + 0x00, // GEOM + + // Window specification + (byte) 0xF6, + 18, // LENGTH + (ABS + IMGRES), // FLAGS (ABS) + 0x00, // reserved (must be zero) + 0x00, // CFORMAT (coordinate format - 16bit high byte first signed) + 0x00, // UBASE (unit base - ten inches) + xreswind[0], // XRESOL + xreswind[1], + yreswind[0], // YRESOL + yreswind[1], + imxyres[0], // IMXYRES (Number of image points per ten inches + imxyres[1], // in X and Y directions) + xlcoord[0], // XLWIND + xlcoord[1], + xrcoord[0], // XRWIND + xrcoord[1], + xbcoord[0], // YBWIND + xbcoord[1], + ytcoord[0], // YTWIND + ytcoord[1] + }; + os.write(data); + } +} diff --git a/src/java/org/apache/fop/render/afp/modca/GraphicsObject.java b/src/java/org/apache/fop/render/afp/modca/GraphicsObject.java new file mode 100644 index 000000000..45c9f5751 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/GraphicsObject.java @@ -0,0 +1,321 @@ +/* + * 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.modca; + +import java.awt.Color; +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.render.afp.modca.goca.GraphicsBox; +import org.apache.fop.render.afp.modca.goca.GraphicsData; +import org.apache.fop.render.afp.modca.goca.GraphicsFillet; +import org.apache.fop.render.afp.modca.goca.GraphicsFullArc; +import org.apache.fop.render.afp.modca.goca.GraphicsImageBegin; +import org.apache.fop.render.afp.modca.goca.GraphicsImageData; +import org.apache.fop.render.afp.modca.goca.GraphicsImageEnd; +import org.apache.fop.render.afp.modca.goca.GraphicsLine; +import org.apache.fop.render.afp.modca.goca.GraphicsSetArcParameters; +import org.apache.fop.render.afp.modca.goca.GraphicsSetCharacterSet; +import org.apache.fop.render.afp.modca.goca.GraphicsSetCurrentPosition; +import org.apache.fop.render.afp.modca.goca.GraphicsSetLineType; +import org.apache.fop.render.afp.modca.goca.GraphicsSetLineWidth; +import org.apache.fop.render.afp.modca.goca.GraphicsSetPatternSymbol; +import org.apache.fop.render.afp.modca.goca.GraphicsSetProcessColor; +import org.apache.fop.render.afp.modca.goca.GraphicsString; + +/** + * Top-level GOCA graphics object. + * + * Acts as container and factory of all other graphic objects + */ +public class GraphicsObject extends AbstractDataObject { + + /** + * The graphics data + */ + private GraphicsData graphicsData = null; + + /** + * Default constructor + * + * @param name the name of graphics object + */ + public GraphicsObject(String name) { + super(name); + } + + /** + * {@inheritDoc} + */ + public void setViewport(int x, int y, int width, int height, + int widthRes, int heightRes, int rotation) { + super.setViewport(x, y, width, height, widthRes, heightRes, rotation); + objectEnvironmentGroup.setGraphicsData( + widthRes, heightRes, 0, x + width, 0, y + height); + } + + /** + * {@inheritDoc} + */ + protected void writeStart(OutputStream os) throws IOException { + super.writeStart(os); + byte[] data = new byte[] { + 0x5A, // Structured field identifier + 0x00, //sfLen[0], // Length byte 1 + 0x10, //sfLen[1], // Length byte 2 + (byte) 0xD3, // Structured field id byte 1 + (byte) 0xA8, // Structured field id byte 2 + (byte) 0xBB, // Structured field id byte 3 + 0x00, // Flags + 0x00, // Reserved + 0x00, // Reserved + super.nameBytes[0], // gdoName + super.nameBytes[1], + super.nameBytes[2], + super.nameBytes[3], + super.nameBytes[4], + super.nameBytes[5], + super.nameBytes[6], + super.nameBytes[7] + }; + os.write(data); + } + + /** + * {@inheritDoc} + */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[] { + 0x5A, // Structured field identifier + 0x00, // sfLen[0], // Length byte 1 + 0x10, // sfLen[1], // Length byte 2 + (byte) 0xD3, // Structured field id byte 1 + (byte) 0xA9, // Structured field id byte 2 + (byte) 0xBB, // Structured field id byte 3 + 0x00, // Flags + 0x00, // Reserved + 0x00, // Reserved + super.nameBytes[0], // gdoName + super.nameBytes[1], + super.nameBytes[2], + super.nameBytes[3], + super.nameBytes[4], + super.nameBytes[5], + super.nameBytes[6], + super.nameBytes[7] + }; + os.write(data); + } + + /** + * {@inheritDoc} + */ + protected PreparedAFPObject addDrawingOrder(PreparedAFPObject drawingOrder) { + if (graphicsData == null + || (graphicsData.getDataLength() + drawingOrder.getDataLength()) + >= GraphicsData.MAX_DATA_LEN) { + newData(); + } + graphicsData.addDrawingOrder(drawingOrder); + return drawingOrder; + } + + /** + * Gets the current graphics data, creating a new one if necessary + * @return the current graphics data + */ + private GraphicsData getData() { + if (this.graphicsData == null) { + return newData(); + } + return this.graphicsData; + } + + /** + * Creates a new graphics data + * @return a newly created graphics data + */ + private GraphicsData newData() { + this.graphicsData = new GraphicsData(); + super.addDrawingOrder(graphicsData); + return graphicsData; + } + + /** + * Sets the current color + * @param col the active color to use + */ + public void setColor(Color col) { + addDrawingOrder(new GraphicsSetProcessColor(col)); + } + + /** + * Sets the current position + * @param coords the x and y coordinates of the current position + */ + public void setCurrentPosition(int[] coords) { + addDrawingOrder(new GraphicsSetCurrentPosition(coords)); + } + + /** + * Sets the line width + * @param multiplier the line width multiplier + */ + public void setLineWidth(int multiplier) { + GraphicsSetLineWidth lw = new GraphicsSetLineWidth(multiplier); + addDrawingOrder(lw); + } + + /** + * Sets the line type + * @param type the line type + */ + public void setLineType(byte type) { + GraphicsSetLineType lt = new GraphicsSetLineType(type); + addDrawingOrder(lt); + } + + /** + * Sets whether to fill the next shape + * @param fill whether to fill the next shape + */ + public void setFill(boolean fill) { + GraphicsSetPatternSymbol pat = new GraphicsSetPatternSymbol( + fill ? GraphicsSetPatternSymbol.SOLID_FILL + : GraphicsSetPatternSymbol.NO_FILL + ); + addDrawingOrder(pat); + } + + /** + * Sets the character set to use + * @param fontReference the character set (font) reference + */ + public void setCharacterSet(int fontReference) { + addDrawingOrder(new GraphicsSetCharacterSet(fontReference)); + } + + /** + * Adds a line at the given x/y coordinates + * @param coords the x/y coordinates (can be a series) + */ + public void addLine(int[] coords) { + addDrawingOrder(new GraphicsLine(coords)); + } + + /** + * Adds a box at the given coordinates + * @param coords the x/y coordinates + */ + public void addBox(int[] coords) { + addDrawingOrder(new GraphicsBox(coords)); + } + + /** + * Adds a fillet (curve) at the given coordinates + * @param coords the x/y coordinates + */ + public void addFillet(int[] coords) { + addDrawingOrder(new GraphicsFillet(coords)); + } + + /** + * Sets the arc parameters + * @param xmaj the maximum value of the x coordinate + * @param ymin the minimum value of the y coordinate + * @param xmin the minimum value of the x coordinate + * @param ymaj the maximum value of the y coordinate + */ + public void setArcParams(int xmaj, int ymin, int xmin, int ymaj) { + addDrawingOrder(new GraphicsSetArcParameters(xmaj, ymin, xmin, ymaj)); + } + + /** + * Adds an arc + * @param x the x coordinate + * @param y the y coordinate + * @param mh the integer portion of the multiplier + * @param mhr the fractional portion of the multiplier + */ + public void addFullArc(int x, int y, int mh, int mhr) { + addDrawingOrder(new GraphicsFullArc(x, y, mh, mhr)); + } + + /** + * Adds an image + * @param x the x coordinate + * @param y the y coordinate + * @param width the image width + * @param height the image height + * @param rawData the image data + */ + public void addImage(int x, int y, int width, int height, byte[] rawData) { + addDrawingOrder(new GraphicsImageBegin(x, y, width, height)); + for (int startIndex = 0; + startIndex <= rawData.length; + startIndex += GraphicsImageData.MAX_DATA_LEN) { + addDrawingOrder(new GraphicsImageData(rawData, startIndex)); + } + addDrawingOrder(new GraphicsImageEnd()); + } + + /** + * Adds a string + * @param str the string + * @param x the x coordinate + * @param y the y coordinate + */ + public void addString(String str, int x, int y) { + addDrawingOrder(new GraphicsString(str, x, y)); + } + + /** + * Begins a graphics area (start of fill) + */ + public void beginArea() { + if (graphicsData == null) { + newData(); + } + graphicsData.beginArea(); + } + + /** + * Ends a graphics area (end of fill) + */ + public void endArea() { + if (graphicsData != null) { + graphicsData.endArea(); + } + } + + /** + * {@inheritDoc} + */ + public String toString() { + return "GraphicsObject"; + } + + /** + * Creates a new graphics segment + */ + public void newSegment() { + getData().newSegment(); + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/ImageContent.java b/src/java/org/apache/fop/render/afp/modca/ImageContent.java index e6f9f1857..e7fd538e1 100644 --- a/src/java/org/apache/fop/render/afp/modca/ImageContent.java +++ b/src/java/org/apache/fop/render/afp/modca/ImageContent.java @@ -18,43 +18,45 @@ /* $Id$ */ package org.apache.fop.render.afp.modca; + import java.io.IOException; import java.io.OutputStream; import org.apache.fop.render.afp.tools.BinaryUtils; /** + * Image content IOCA object */ public class ImageContent extends AbstractAFPObject { /** * The image size parameter */ - private ImageSizeParameter _imageSizeParameter = null; + private ImageSizeParameter imageSizeParam = null; /** * The image encoding */ - private byte _encoding = 0x03; + private byte encoding = 0x03; /** * The image ide size */ - private byte _size = 1; + private byte size = 1; /** * The image compression */ - private byte _compression = (byte)0xC0; + private byte compression = (byte)0xC0; /** * The image color model */ - private byte _colorModel = 0x01; + private byte colorModel = 0x01; /** * The image data */ - private byte _data[] = null; + private byte[] data = null; /** * Constructor for the image content @@ -72,60 +74,60 @@ public class ImageContent extends AbstractAFPObject { * @param vsize The vertival size of the image. */ public void setImageSize(int hresol, int vresol, int hsize, int vsize) { - _imageSizeParameter = new ImageSizeParameter(hresol, vresol, hsize, vsize); + this.imageSizeParam = new ImageSizeParameter(hresol, vresol, hsize, vsize); } /** * Sets the image encoding. - * @param encoding The image encoding. + * @param enc The image encoding. */ - public void setImageEncoding(byte encoding) { - _encoding = encoding; + public void setImageEncoding(byte enc) { + this.encoding = enc; } /** * Sets the image compression. - * @param compression The image compression. + * @param comp The image compression. */ - public void setImageCompression(byte compression) { - _compression = compression; + public void setImageCompression(byte comp) { + this.compression = comp; } /** * Sets the image IDE size. - * @param size The IDE size. + * @param siz The IDE size. */ - public void setImageIDESize(byte size) { - _size = size; + public void setImageIDESize(byte siz) { + this.size = siz; } /** * Sets the image IDE color model. - * @param colorModel the IDE color model. + * @param model the IDE color model. */ - public void setImageIDEColorModel(byte colorModel) { - _colorModel = colorModel; + public void setImageIDEColorModel(byte model) { + this.colorModel = model; } /** * Set the data of the image. + * @param dat the image data */ - public void setImageData(byte data[]) { - _data = data; + public void setImageData(byte[] dat) { + this.data = dat; } /** * Accessor method to write the AFP datastream for the Image Content * @param os The stream to write to - * @throws java.io.IOException + * @throws java.io.IOException if an I/O exception occurs */ - public void writeDataStream(OutputStream os) - throws IOException { + public void writeDataStream(OutputStream os) throws IOException { writeStart(os); - if (_imageSizeParameter != null) { - _imageSizeParameter.writeDataStream(os); + if (imageSizeParam != null) { + imageSizeParam.writeDataStream(os); } os.write(getImageEncodingParameter()); @@ -136,12 +138,12 @@ public class ImageContent extends AbstractAFPObject { os.write(getExternalAlgorithmParameter()); - if (_data != null) { + if (data != null) { int off = 0; - while (off < _data.length) { - int len = Math.min(30000, _data.length - off); + while (off < data.length) { + int len = Math.min(30000, data.length - off); os.write(getImageDataStart(len)); - os.write(_data, off, len); + os.write(data, off, len); off += len; } } @@ -154,33 +156,25 @@ public class ImageContent extends AbstractAFPObject { * Helper method to write the start of the Image Content. * @param os The stream to write to */ - private void writeStart(OutputStream os) - throws IOException { - - byte[] data = new byte[] { + private void writeStart(OutputStream os) throws IOException { + byte[] startData = new byte[] { (byte)0x91, // ID 0x01, // Length (byte)0xff, // Object Type = IOCA Image Object }; - - os.write(data); - + os.write(startData); } /** * Helper method to write the end of the Image Content. * @param os The stream to write to */ - private void writeEnd(OutputStream os) - throws IOException { - - byte[] data = new byte[] { + private void writeEnd(OutputStream os) throws IOException { + byte[] endData = new byte[] { (byte)0x93, // ID 0x00, // Length }; - - os.write(data); - + os.write(endData); } /** @@ -188,21 +182,16 @@ public class ImageContent extends AbstractAFPObject { * @return byte[] The data stream. */ private byte[] getImageDataStart(int len) { - - byte[] data = new byte[] { + byte[] imageDataStartData = new byte[] { (byte)0xFE, // ID (byte)0x92, // ID 0x00, // Length 0x00, // Length }; - byte[] l = BinaryUtils.convert(len, 2); - data[2] = l[0]; - data[3] = l[1]; - - - return data; - + imageDataStartData[2] = l[0]; + imageDataStartData[3] = l[1]; + return imageDataStartData; } /** @@ -210,16 +199,13 @@ public class ImageContent extends AbstractAFPObject { * @return byte[] The data stream. */ private byte[] getImageEncodingParameter() { - - byte[] data = new byte[] { + byte[] imageEncParamData = new byte[] { (byte)0x95, // ID 0x02, // Length - _encoding, + encoding, 0x01, // RECID }; - - return data; - + return imageEncParamData; } /** @@ -227,9 +213,8 @@ public class ImageContent extends AbstractAFPObject { * @return byte[] The data stream. */ private byte[] getExternalAlgorithmParameter() { - - if (_encoding == (byte)0x83 && _compression != 0) { - byte[] data = new byte[] { + if (encoding == (byte)0x83 && compression != 0) { + byte[] extAlgParamData = new byte[] { (byte)0x95, // ID 0x00, // Length 0x10, // ALGTYPE = Compression Algorithm @@ -238,13 +223,13 @@ public class ImageContent extends AbstractAFPObject { 0x00, // Reserved 0x00, // Reserved 0x00, // Reserved - _compression, // MARKER + compression, // MARKER 0x00, // Reserved 0x00, // Reserved 0x00, // Reserved }; - data[1] = (byte)(data.length - 2); - return data; + extAlgParamData[1] = (byte)(extAlgParamData.length - 2); + return extAlgParamData; } return new byte[0]; } @@ -254,15 +239,12 @@ public class ImageContent extends AbstractAFPObject { * @return byte[] The data stream. */ private byte[] getImageIDESizeParameter() { - - byte[] data = new byte[] { + byte[] imageIDESizeParamData = new byte[] { (byte)0x96, // ID 0x01, // Length - _size, + size, }; - - return data; - + return imageIDESizeParamData; } /** @@ -270,15 +252,14 @@ public class ImageContent extends AbstractAFPObject { * @return byte[] The data stream. */ private byte[] getIDEStructureParameter() { - - if (_colorModel != 0 && _size == 24) { - byte bits = (byte)(_size / 3); - byte[] data = new byte[] { + if (colorModel != 0 && size == 24) { + byte bits = (byte)(size / 3); + byte[] ideStructParamData = new byte[] { (byte)0x9B, // ID 0x00, // Length 0x00, // FLAGS 0x00, // Reserved - _colorModel, // COLOR MODEL + colorModel, // COLOR MODEL 0x00, // Reserved 0x00, // Reserved 0x00, // Reserved @@ -286,10 +267,9 @@ public class ImageContent extends AbstractAFPObject { bits, bits, }; - data[1] = (byte)(data.length - 2); - return data; + ideStructParamData[1] = (byte)(ideStructParamData.length - 2); + return ideStructParamData; } return new byte[0]; } - } diff --git a/src/java/org/apache/fop/render/afp/modca/ImageDataDescriptor.java b/src/java/org/apache/fop/render/afp/modca/ImageDataDescriptor.java index 9250f0c7f..d1c2c11c7 100644 --- a/src/java/org/apache/fop/render/afp/modca/ImageDataDescriptor.java +++ b/src/java/org/apache/fop/render/afp/modca/ImageDataDescriptor.java @@ -27,10 +27,17 @@ import org.apache.fop.render.afp.tools.BinaryUtils; */ public class ImageDataDescriptor extends AbstractAFPObject { - private int _xresol = 0; - private int _yresol = 0; - private int _width = 0; - private int _height = 0; + /** x resolution */ + private int xresol = 0; + + /** y resolution */ + private int yresol = 0; + + /** width */ + private int width = 0; + + /** height */ + private int height = 0; /** * Constructor for a ImageDataDescriptor for the specified @@ -41,26 +48,25 @@ public class ImageDataDescriptor extends AbstractAFPObject { * @param height The height of the height. */ public ImageDataDescriptor(int xresol, int yresol, int width, int height) { - - _xresol = xresol; - _yresol = yresol; - _width = width; - _height = height; - + this.xresol = xresol; + this.yresol = yresol; + this.width = width; + this.height = height; } /** - * Accessor method to write the AFP datastream for the Image Data Descriptor - * @param os The stream to write to - * @throws java.io.IOException + * {@inheritDoc} */ - public void writeDataStream(OutputStream os) - throws IOException { - + public void writeDataStream(OutputStream os) throws IOException { + byte[] len = BinaryUtils.convert(21, 2); + byte[] xres = BinaryUtils.convert(xresol, 2); + byte[] yres = BinaryUtils.convert(yresol, 2); + byte[] w = BinaryUtils.convert(width, 2); + byte[] h = BinaryUtils.convert(height, 2); byte[] data = new byte[] { 0x5A, - 0x00, - 0x20, + len[0], + len[1], (byte) 0xD3, (byte) 0xA6, (byte) 0xFB, @@ -68,42 +74,19 @@ public class ImageDataDescriptor extends AbstractAFPObject { 0x00, // Reserved 0x00, // Reserved 0x00, // Unit base - 10 Inches - 0x00, // XRESOL - 0x00, // - 0x00, // YRESOL - 0x00, // - 0x00, // XSIZE - 0x00, // - 0x00, // YSIZE - 0x00, // + xres[0], // XRESOL + xres[1], // + yres[0], // YRESOL + yres[1], // + w[0], // XSIZE + w[1], // + h[0], // YSIZE + h[1], // (byte)0xF7, // ID = Set IOCA Function Set 0x02, // Length 0x01, // Category = Function set identifier 0x0B, // FCNSET = IOCA FS 11 }; - - byte[] l = BinaryUtils.convert(data.length - 1, 2); - data[1] = l[0]; - data[2] = l[1]; - - byte[] x = BinaryUtils.convert(_xresol, 2); - data[10] = x[0]; - data[11] = x[1]; - - byte[] y = BinaryUtils.convert(_yresol, 2); - data[12] = y[0]; - data[13] = y[1]; - - byte[] w = BinaryUtils.convert(_width, 2); - data[14] = w[0]; - data[15] = w[1]; - - byte[] h = BinaryUtils.convert(_height, 2); - data[16] = h[0]; - data[17] = h[1]; - os.write(data); - } - } diff --git a/src/java/org/apache/fop/render/afp/modca/ImageObject.java b/src/java/org/apache/fop/render/afp/modca/ImageObject.java index 66c46c872..c13fcbb59 100644 --- a/src/java/org/apache/fop/render/afp/modca/ImageObject.java +++ b/src/java/org/apache/fop/render/afp/modca/ImageObject.java @@ -27,12 +27,7 @@ import org.apache.fop.render.afp.tools.BinaryUtils; /** * An IOCA Image Data Object */ -public class ImageObject extends AbstractNamedAFPObject { - - /** - * The object environment group - */ - private ObjectEnvironmentGroup objectEnvironmentGroup = null; +public class ImageObject extends AbstractDataObject { /** * The image segment @@ -45,34 +40,7 @@ public class ImageObject extends AbstractNamedAFPObject { * @param name The name of the image. */ public ImageObject(String name) { - super(name); - - } - - /** - * Sets the image display area position and size. - * - * @param x - * the x position of the image - * @param y - * the y position of the image - * @param w - * the width of the image - * @param h - * the height of the image - * @param r - * the rotation of the image - * @param wr - * the width resolution of the image - * @param hr - * the height resolution of the image - */ - public void setImageViewport(int x, int y, int w, int h, int r, int wr, int hr) { - if (objectEnvironmentGroup == null) { - objectEnvironmentGroup = new ObjectEnvironmentGroup(); - } - objectEnvironmentGroup.setObjectArea(x, y, w, h, r, wr, hr); } /** @@ -149,24 +117,16 @@ public class ImageObject extends AbstractNamedAFPObject { } /** - * Sets the ObjectEnvironmentGroup. - * @param objectEnvironmentGroup The objectEnvironmentGroup to set - */ - public void setObjectEnvironmentGroup(ObjectEnvironmentGroup objectEnvironmentGroup) { - this.objectEnvironmentGroup = objectEnvironmentGroup; - } - - /** * Helper method to return the start of the image object. + * @param len the length of this ipd start * @return byte[] The data stream. */ private byte[] getIPDStart(int len) { - + byte[] l = BinaryUtils.convert(len + 8, 2); byte[] data = new byte[] { - 0x5A, // Structured field identifier - 0x00, // Length byte 1 - 0x10, // Length byte 2 + l[0], // Length byte 1 + l[1], // Length byte 2 (byte) 0xD3, // Structured field id byte 1 (byte) 0xEE, // Structured field id byte 2 (byte) 0xFB, // Structured field id byte 3 @@ -174,29 +134,14 @@ public class ImageObject extends AbstractNamedAFPObject { 0x00, // Reserved 0x00, // Reserved }; - - byte[] l = BinaryUtils.convert(len + 8, 2); - data[1] = l[0]; - data[2] = l[1]; - return data; - } /** - * Accessor method to write the AFP datastream for the Image Object - * @param os The stream to write to - * @throws java.io.IOException thrown if an I/O exception of some sort has occurred + * {@inheritDoc} */ - public void writeDataStream(OutputStream os) - throws IOException { - - writeStart(os); - - if (objectEnvironmentGroup != null) { - objectEnvironmentGroup.writeDataStream(os); - } - + protected void writeContent(OutputStream os) throws IOException { + super.writeContent(os); if (imageSegment != null) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); imageSegment.writeDataStream(baos); @@ -209,20 +154,13 @@ public class ImageObject extends AbstractNamedAFPObject { off += len; } } - - writeEnd(os); - } /** - * Helper method to write the start of the Image Object. - * @param os The stream to write to + * {@inheritDoc} */ - private void writeStart(OutputStream os) - throws IOException { - + protected void writeStart(OutputStream os) throws IOException { byte[] data = new byte[17]; - data[0] = 0x5A; // Structured field identifier data[1] = 0x00; // Length byte 1 data[2] = 0x10; // Length byte 2 @@ -232,26 +170,19 @@ public class ImageObject extends AbstractNamedAFPObject { data[6] = 0x00; // Flags data[7] = 0x00; // Reserved data[8] = 0x00; // Reserved - for (int i = 0; i < nameBytes.length; i++) { - data[9 + i] = nameBytes[i]; - } - os.write(data); - } /** * Helper method to write the end of the Image Object. * @param os The stream to write to + * @throws IOException in the event */ - private void writeEnd(OutputStream os) - throws IOException { - + protected void writeEnd(OutputStream os) throws IOException { byte[] data = new byte[17]; - data[0] = 0x5A; // Structured field identifier data[1] = 0x00; // Length byte 1 data[2] = 0x10; // Length byte 2 @@ -261,15 +192,9 @@ public class ImageObject extends AbstractNamedAFPObject { data[6] = 0x00; // Flags data[7] = 0x00; // Reserved data[8] = 0x00; // Reserved - for (int i = 0; i < nameBytes.length; i++) { - data[9 + i] = nameBytes[i]; - } - os.write(data); - } - } diff --git a/src/java/org/apache/fop/render/afp/modca/ImageSegment.java b/src/java/org/apache/fop/render/afp/modca/ImageSegment.java index 7d6cc18aa..5f8454fa8 100644 --- a/src/java/org/apache/fop/render/afp/modca/ImageSegment.java +++ b/src/java/org/apache/fop/render/afp/modca/ImageSegment.java @@ -18,6 +18,7 @@ /* $Id$ */ package org.apache.fop.render.afp.modca; + import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; @@ -67,15 +68,12 @@ public class ImageSegment extends AbstractAFPObject { * @param name The name of the image. */ public ImageSegment(String name) { - if (name.length() != 4) { String msg = "Image segment name must be 4 characters long " + name; log.error("Constructor:: " + msg); throw new IllegalArgumentException(msg); } - this.name = name; - try { this.nameBytes = name.getBytes(AFPConstants.EBCIDIC_ENCODING); } catch (UnsupportedEncodingException usee) { @@ -162,24 +160,18 @@ public class ImageSegment extends AbstractAFPObject { * @throws java.io.IOException if an I/O exception occurred */ public void writeDataStream(OutputStream os) throws IOException { - writeStart(os); - if (imageContent != null) { imageContent.writeDataStream(os); } - writeEnd(os); - } /** * Helper method to write the start of the Image Segment. * @param os The stream to write to */ - private void writeStart(OutputStream os) - throws IOException { - + private void writeStart(OutputStream os) throws IOException { byte[] data = new byte[] { 0x70, // ID 0x04, // Length @@ -188,13 +180,9 @@ public class ImageSegment extends AbstractAFPObject { 0x00, // Name byte 3 0x00, // Name byte 4 }; - for (int i = 0; i < nameBytes.length; i++) { - data[2 + i] = nameBytes[i]; - } - os.write(data); } @@ -204,7 +192,6 @@ public class ImageSegment extends AbstractAFPObject { * @param os The stream to write to */ private void writeEnd(OutputStream os) throws IOException { - byte[] data = new byte[] { 0x71, // ID 0x00, // Length diff --git a/src/java/org/apache/fop/render/afp/modca/ObjectAreaDescriptor.java b/src/java/org/apache/fop/render/afp/modca/ObjectAreaDescriptor.java index 7c940148b..aa35db10e 100644 --- a/src/java/org/apache/fop/render/afp/modca/ObjectAreaDescriptor.java +++ b/src/java/org/apache/fop/render/afp/modca/ObjectAreaDescriptor.java @@ -35,11 +35,11 @@ public class ObjectAreaDescriptor extends AbstractDescriptor { * and object height. * @param width The page width. * @param height The page height. - * @param widthResolution The page width resolution. - * @param heightResolution The page height resolution. + * @param widthRes The page width resolution. + * @param heightRes The page height resolution. */ - public ObjectAreaDescriptor(int width, int height, int widthResolution, int heightResolution) { - super(width, height, widthResolution, heightResolution); + public ObjectAreaDescriptor(int width, int height, int widthRes, int heightRes) { + super(width, height, widthRes, heightRes); } /** @@ -47,8 +47,7 @@ public class ObjectAreaDescriptor extends AbstractDescriptor { * @param os The stream to write to * @throws java.io.IOException thrown if an I/O exception of some sort has occurred */ - public void writeDataStream(OutputStream os) - throws IOException { + public void writeDataStream(OutputStream os) throws IOException { byte[] data = new byte[29]; data[0] = 0x5A; @@ -72,12 +71,12 @@ public class ObjectAreaDescriptor extends AbstractDescriptor { data[15] = 0x00; // YaoBase = 10 inches // XaoUnits - byte[] xdpi = BinaryUtils.convert(widthResolution * 10, 2); + byte[] xdpi = BinaryUtils.convert(this.widthRes * 10, 2); data[16] = xdpi[0]; data[17] = xdpi[1]; // YaoUnits - byte[] ydpi = BinaryUtils.convert(heightResolution * 10, 2); + byte[] ydpi = BinaryUtils.convert(this.heightRes * 10, 2); data[18] = ydpi[0]; data[19] = ydpi[1]; @@ -85,18 +84,16 @@ public class ObjectAreaDescriptor extends AbstractDescriptor { data[21] = 0x4C; // tid = Object Area Size data[22] = 0x02; // Size Type - byte[] x = BinaryUtils.convert(width, 3); + byte[] x = BinaryUtils.convert(this.width, 3); data[23] = x[0]; data[24] = x[1]; data[25] = x[2]; - byte[] y = BinaryUtils.convert(height, 3); + byte[] y = BinaryUtils.convert(this.height, 3); data[26] = y[0]; data[27] = y[1]; data[28] = y[2]; os.write(data); - } - }
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/ObjectAreaPosition.java b/src/java/org/apache/fop/render/afp/modca/ObjectAreaPosition.java index e500c1269..688288063 100644 --- a/src/java/org/apache/fop/render/afp/modca/ObjectAreaPosition.java +++ b/src/java/org/apache/fop/render/afp/modca/ObjectAreaPosition.java @@ -30,9 +30,9 @@ import org.apache.fop.render.afp.tools.BinaryUtils; */ public class ObjectAreaPosition extends AbstractAFPObject { - private int _x = 0; - private int _y = 0; - private int _rot = 0; + private int x; + private int y; + private int rotation; /** * Construct an object area position for the specified object y, y position. @@ -41,24 +41,25 @@ public class ObjectAreaPosition extends AbstractAFPObject { * @param rotation The coordinate system rotation (must be 0, 90, 180, 270). */ public ObjectAreaPosition(int x, int y, int rotation) { - - _x = x; - _y = y; - _rot = rotation; + this.x = x; + this.y = y; + this.rotation = rotation; } /** * Accessor method to write the AFP datastream for the Object Area Position * @param os The stream to write to - * @throws java.io.IOException + * @throws java.io.IOException in the event that an I/O exception of some sort has occurred. */ - public void writeDataStream(OutputStream os) - throws IOException { + public void writeDataStream(OutputStream os) throws IOException { + byte[] len = BinaryUtils.convert(32, 2); + byte[] xcoord = BinaryUtils.convert(x, 3); + byte[] ycoord = BinaryUtils.convert(y, 3); byte[] data = new byte[] { 0x5A, - 0x00, // Length - 0x20, // Length + len[0], // Length + len[1], // Length (byte) 0xD3, (byte) 0xAC, (byte) 0x6B, @@ -67,15 +68,15 @@ public class ObjectAreaPosition extends AbstractAFPObject { 0x00, // Reserved 0x01, // OAPosID = 1 0x17, // RGLength = 23 - 0x00, // XoaOSet - 0x00, - 0x00, - 0x00, // YoaOSet - 0x00, - 0x00, - (byte)(_rot / 2), // XoaOrent + xcoord[0], // XoaOSet + xcoord[1], + xcoord[2], + ycoord[0], // YoaOSet + ycoord[1], + ycoord[2], + (byte)(rotation / 2), // XoaOrent 0x00, - (byte)(_rot / 2 + 45), // YoaOrent + (byte)(rotation / 2 + 45), // YoaOrent 0x00, 0x00, // Reserved 0x00, // XocaOSet @@ -88,23 +89,9 @@ public class ObjectAreaPosition extends AbstractAFPObject { 0x00, 0x2D, // YocaOrent 0x00, - 0x01, // RefCSys + 0x00, // RefCSys }; - - byte[] l = BinaryUtils.convert(data.length - 1, 2); - data[1] = l[0]; - data[2] = l[1]; - - byte[] x = BinaryUtils.convert(_x, 3); - data[11] = x[0]; - data[12] = x[1]; - data[13] = x[2]; - - byte[] y = BinaryUtils.convert(_y, 3); - data[14] = y[0]; - data[15] = y[1]; - data[16] = y[2]; - + os.write(data); } diff --git a/src/java/org/apache/fop/render/afp/modca/ObjectEnvironmentGroup.java b/src/java/org/apache/fop/render/afp/modca/ObjectEnvironmentGroup.java index d6b029122..27fe7c270 100644 --- a/src/java/org/apache/fop/render/afp/modca/ObjectEnvironmentGroup.java +++ b/src/java/org/apache/fop/render/afp/modca/ObjectEnvironmentGroup.java @@ -18,6 +18,7 @@ /* $Id$ */ package org.apache.fop.render.afp.modca; + import java.io.IOException; import java.io.OutputStream; @@ -33,7 +34,7 @@ import java.io.OutputStream; * normally contained in the object environment group, or it may specify that one or * more default values are to be used. */ -public final class ObjectEnvironmentGroup extends AbstractNamedAFPObject { +public final class ObjectEnvironmentGroup extends AbstractStructuredAFPObject { /** * Default name for the object environment group @@ -56,12 +57,15 @@ public final class ObjectEnvironmentGroup extends AbstractNamedAFPObject { private ImageDataDescriptor imageDataDescriptor = null; /** + * The GraphicsDataDescriptor for the object environment group + */ + private GraphicsDataDescriptor graphicsDataDescriptor = null; + + /** * Default constructor for the ObjectEnvironmentGroup. */ public ObjectEnvironmentGroup() { - this(DEFAULT_NAME); - } /** @@ -70,9 +74,7 @@ public final class ObjectEnvironmentGroup extends AbstractNamedAFPObject { * @param name the object environment group name */ public ObjectEnvironmentGroup(String name) { - super(name); - } /** @@ -82,15 +84,14 @@ public final class ObjectEnvironmentGroup extends AbstractNamedAFPObject { * @param width the object width * @param height the object height * @param rotation the object orientation - * @param widthResolution the object resolution width - * @param heightResolution the object resolution height + * @param widthRes the object resolution width + * @param heightRes the object resolution height */ - public void setObjectArea(int x, int y, int width, int height, int rotation, - int widthResolution, int heightResolution) { - - objectAreaDescriptor = new ObjectAreaDescriptor(width, height, - widthResolution, heightResolution); - objectAreaPosition = new ObjectAreaPosition(x, y, rotation); + public void setObjectArea(int x, int y, int width, int height, + int widthRes, int heightRes, int rotation) { + this.objectAreaDescriptor = new ObjectAreaDescriptor(width, height, + widthRes, heightRes); + this.objectAreaPosition = new ObjectAreaPosition(x, y, rotation); } @@ -102,40 +103,28 @@ public final class ObjectEnvironmentGroup extends AbstractNamedAFPObject { * @param height the image height */ public void setImageData(int xresol, int yresol, int width, int height) { - imageDataDescriptor = new ImageDataDescriptor(xresol, yresol, width, height); + this.imageDataDescriptor = new ImageDataDescriptor(xresol, yresol, width, height); } /** - * Accessor method to obtain write the AFP datastream for - * the object environment group. - * @param os The stream to write to - * @throws java.io.IOException throw if an I/O exception of some sort has occurred + * Set the graphics data descriptor. + * @param xresol the x resolution of the graphics window + * @param yresol the y resolution of the graphics window + * @param xlwind the left edge of the graphics window + * @param xrwind the right edge of the graphics window + * @param ybwind the top edge of the graphics window + * @param ytwind the bottom edge of the graphics window */ - public void writeDataStream(OutputStream os) - throws IOException { - - - writeStart(os); - - objectAreaDescriptor.writeDataStream(os); - - objectAreaPosition.writeDataStream(os); - - if (imageDataDescriptor != null) { - imageDataDescriptor.writeDataStream(os); - } - - writeEnd(os); - + public void setGraphicsData(int xresol, int yresol, + int xlwind, int xrwind, int ybwind, int ytwind) { + this.graphicsDataDescriptor = new GraphicsDataDescriptor(xresol, yresol, + xlwind, xrwind, ybwind, ytwind); } /** - * Helper method to write the start of the object environment group. - * @param os The stream to write to + * {@inheritDoc} */ - private void writeStart(OutputStream os) - throws IOException { - + protected void writeStart(OutputStream os) throws IOException { byte[] data = new byte[] { 0x5A, // Structured field identifier 0x00, // Length byte 1 @@ -146,53 +135,57 @@ public final class ObjectEnvironmentGroup extends AbstractNamedAFPObject { 0x00, // Flags 0x00, // Reserved 0x00, // Reserved - 0x00, // Name - 0x00, // - 0x00, // - 0x00, // - 0x00, // - 0x00, // - 0x00, // - 0x00, // + nameBytes[0], // Name + nameBytes[1], // + nameBytes[2], // + nameBytes[3], // + nameBytes[4], // + nameBytes[5], // + nameBytes[6], // + nameBytes[7] // }; - - for (int i = 0; i < nameBytes.length; i++) { - - data[9 + i] = nameBytes[i]; - - } - os.write(data); - } /** - * Helper method to write the end of the object environment group. - * @param os The stream to write to + * {@inheritDoc} */ - private void writeEnd(OutputStream os) - throws IOException { - - byte[] data = new byte[17]; - - data[0] = 0x5A; // Structured field identifier - data[1] = 0x00; // Length byte 1 - data[2] = 0x10; // Length byte 2 - data[3] = (byte) 0xD3; // Structured field id byte 1 - data[4] = (byte) 0xA9; // Structured field id byte 2 - data[5] = (byte) 0xC7; // Structured field id byte 3 - data[6] = 0x00; // Flags - data[7] = 0x00; // Reserved - data[8] = 0x00; // Reserved - - for (int i = 0; i < nameBytes.length; i++) { + public void writeContent(OutputStream os) throws IOException { + objectAreaDescriptor.writeDataStream(os); + objectAreaPosition.writeDataStream(os); - data[9 + i] = nameBytes[i]; + if (imageDataDescriptor != null) { + imageDataDescriptor.writeDataStream(os); + } + if (graphicsDataDescriptor != null) { + graphicsDataDescriptor.writeDataStream(os); } + } + /** + * {@inheritDoc} + */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[] { + 0x5A, // Structured field identifier + 0x00, // Length byte 1 + 0x10, // Length byte 2 + (byte) 0xD3, // Structured field id byte 1 + (byte) 0xA9, // Structured field id byte 2 + (byte) 0xC7, // Structured field id byte 3 + 0x00, // Flags + 0x00, // Reserved + 0x00, // Reserved + nameBytes[0], // Name + nameBytes[1], // + nameBytes[2], // + nameBytes[3], // + nameBytes[4], // + nameBytes[5], // + nameBytes[6], // + nameBytes[7], // + }; os.write(data); - } - -}
\ No newline at end of file +} diff --git a/src/java/org/apache/fop/render/afp/modca/PageDescriptor.java b/src/java/org/apache/fop/render/afp/modca/PageDescriptor.java index 1cdec7616..ffa5f3c85 100644 --- a/src/java/org/apache/fop/render/afp/modca/PageDescriptor.java +++ b/src/java/org/apache/fop/render/afp/modca/PageDescriptor.java @@ -35,11 +35,11 @@ public class PageDescriptor extends AbstractDescriptor { * and page height. * @param width The page width. * @param height The page height. - * @param widthResolution The page width resolution - * @param heightResolution The page height resolution + * @param widthRes The page width resolution + * @param heightRes The page height resolution */ - public PageDescriptor(int width, int height, int widthResolution, int heightResolution) { - super(width, height, widthResolution, heightResolution); + public PageDescriptor(int width, int height, int widthRes, int heightRes) { + super(width, height, widthRes, heightRes); } /** @@ -68,12 +68,12 @@ public class PageDescriptor extends AbstractDescriptor { data[10] = 0x00; // YpgBase = 10 inches // XpgUnits - byte[] xdpi = BinaryUtils.convert(widthResolution * 10, 2); + byte[] xdpi = BinaryUtils.convert(widthRes * 10, 2); data[11] = xdpi[0]; data[12] = xdpi[1]; // YpgUnits - byte[] ydpi = BinaryUtils.convert(heightResolution * 10, 2); + byte[] ydpi = BinaryUtils.convert(heightRes * 10, 2); data[13] = ydpi[0]; data[14] = ydpi[1]; diff --git a/src/java/org/apache/fop/render/afp/modca/PageObject.java b/src/java/org/apache/fop/render/afp/modca/PageObject.java index 5b9a00a89..a9a4581e7 100644 --- a/src/java/org/apache/fop/render/afp/modca/PageObject.java +++ b/src/java/org/apache/fop/render/afp/modca/PageObject.java @@ -62,15 +62,15 @@ public class PageObject extends AbstractPageObject { * the height of the page. * @param rotation * the rotation of the page. - * @param widthResolution + * @param widthRes * the width resolution of the page. - * @param heightResolution + * @param heightRes * the height resolution of the page. */ public PageObject(String name, int width, int height, int rotation, - int widthResolution, int heightResolution) { + int widthRes, int heightRes) { - super(name, width, height, rotation, widthResolution, heightResolution); + super(name, width, height, rotation, widthRes, heightRes); } diff --git a/src/java/org/apache/fop/render/afp/modca/PreparedAFPObject.java b/src/java/org/apache/fop/render/afp/modca/PreparedAFPObject.java new file mode 100644 index 000000000..8da724f36 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/PreparedAFPObject.java @@ -0,0 +1,31 @@ +/* + * 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.modca; + +/** + * An AFP object which is able to know its own data length before write() + */ +public interface PreparedAFPObject { + /** + * @return the current data length of this container including + * all enclosed GOCA drawing objects + */ + int getDataLength(); +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/PresentationTextData.java b/src/java/org/apache/fop/render/afp/modca/PresentationTextData.java index 98beb96f7..30a78d6c9 100644 --- a/src/java/org/apache/fop/render/afp/modca/PresentationTextData.java +++ b/src/java/org/apache/fop/render/afp/modca/PresentationTextData.java @@ -56,42 +56,42 @@ public class PresentationTextData extends AbstractAFPObject { /** * The afp data relating to this presentaion text data. */ - private ByteArrayOutputStream _baos = new ByteArrayOutputStream(1024); + private ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); /** * The current x coordinate. */ - private int _currentXCoordinate = -1; + private int currentXCoordinate = -1; /** * The current y cooridnate */ - private int _currentYCoordinate = -1; + private int currentYCoordinate = -1; /** * The current font */ - private String _currentFont = ""; + private String currentFont = ""; /** * The current orientation */ - private int _currentOrientation = 0; + private int currentOrientation = 0; /** * The current color */ - private Color _currentColor = new Color(0, 0, 0); + private Color currentColor = new Color(0, 0, 0); /** * The current variable space increment */ - private int _currentVariableSpaceCharacterIncrement = 0; + private int currentVariableSpaceCharacterIncrement = 0; /** * The current inter character adjustment */ - private int _currentInterCharacterAdjustment = 0; + private int currentInterCharacterAdjustment = 0; /** * Default constructor for the PresentationTextData. @@ -112,7 +112,7 @@ public class PresentationTextData extends AbstractAFPObject { */ public PresentationTextData(boolean controlInd) { - _baos.write(new byte[] { 0x5A, // Structured field identifier + baos.write(new byte[] {0x5A, // Structured field identifier 0x00, // Record length byte 1 0x00, // Record length byte 2 (byte) 0xD3, // PresentationTextData identifier byte 1 @@ -124,7 +124,7 @@ public class PresentationTextData extends AbstractAFPObject { }, 0, 9); if (controlInd) { - _baos.write(new byte[] { 0x2B, (byte) 0xD3 }, 0, 2); + baos.write(new byte[] {0x2B, (byte) 0xD3}, 0, 2); } } @@ -142,13 +142,13 @@ public class PresentationTextData extends AbstractAFPObject { private void setCodedFont(byte font, ByteArrayOutputStream afpdata) { // Avoid unnecessary specification of the font - if (String.valueOf(font).equals(_currentFont)) { + if (String.valueOf(font).equals(currentFont)) { return; } else { - _currentFont = String.valueOf(font); + currentFont = String.valueOf(font); } - afpdata.write(new byte[] { 0x03, (byte) 0xF1, font, }, 0, 3); + afpdata.write(new byte[] {0x03, (byte) 0xF1, font}, 0, 3); } @@ -167,9 +167,9 @@ public class PresentationTextData extends AbstractAFPObject { byte[] b = BinaryUtils.convert(coordinate, 2); - afpdata.write(new byte[] { 0x04, (byte) 0xC7, b[0], b[1], }, 0, 4); + afpdata.write(new byte[] {0x04, (byte) 0xC7, b[0], b[1]}, 0, 4); - _currentXCoordinate = coordinate; + currentXCoordinate = coordinate; } @@ -188,9 +188,9 @@ public class PresentationTextData extends AbstractAFPObject { byte[] b = BinaryUtils.convert(coordinate, 2); - afpdata.write(new byte[] { 0x04, (byte) 0xD3, b[0], b[1], }, 0, 4); + afpdata.write(new byte[] {0x04, (byte) 0xD3, b[0], b[1]}, 0, 4); - _currentYCoordinate = coordinate; + currentYCoordinate = coordinate; } @@ -214,7 +214,7 @@ public class PresentationTextData extends AbstractAFPObject { "Transparent data is longer than 253 bytes: " + data); } - afpdata.write(new byte[] { BinaryUtils.convert(l)[0], (byte) 0xDB, }, + afpdata.write(new byte[] {BinaryUtils.convert(l)[0], (byte) 0xDB}, 0, 2); afpdata.write(data, 0, data.length); @@ -236,7 +236,7 @@ public class PresentationTextData extends AbstractAFPObject { private void drawBaxisRule(int length, int width, ByteArrayOutputStream afpdata) { - afpdata.write(new byte[] { 0x07, // Length + afpdata.write(new byte[] {0x07, // Length (byte) 0xE7, // Type }, 0, 2); @@ -266,7 +266,7 @@ public class PresentationTextData extends AbstractAFPObject { private void drawIaxisRule(int length, int width, ByteArrayOutputStream afpdata) { - afpdata.write(new byte[] { 0x07, // Length + afpdata.write(new byte[] {0x07, // Length (byte) 0xE5, // Type }, 0, 2); @@ -284,7 +284,7 @@ public class PresentationTextData extends AbstractAFPObject { /** * Create the presentation text data for the byte array of data. * - * @param fontNumber + * @param fontReference * The font resource identifier. * @param x * The x coordinate for the text data. @@ -300,64 +300,64 @@ public class PresentationTextData extends AbstractAFPObject { * The inter character adjustment. * @param data * The text data to be created. - * @throws MaximumSizeExceededException + * @throws MaximumSizeExceededException if the maximum size is exceeded */ - public void createTextData(int fontNumber, int x, int y, int orientation, + public void createTextData(int fontReference, int x, int y, int orientation, Color col, int vsci, int ica, byte[] data) throws MaximumSizeExceededException { ByteArrayOutputStream afpdata = new ByteArrayOutputStream(); - if (_currentOrientation != orientation) { + if (currentOrientation != orientation) { setTextOrientation(orientation, afpdata); - _currentOrientation = orientation; - _currentXCoordinate = -1; - _currentYCoordinate = -1; + currentOrientation = orientation; + currentXCoordinate = -1; + currentYCoordinate = -1; } // Avoid unnecessary specification of the Y co-ordinate - if (y != _currentYCoordinate) { + if (y != currentYCoordinate) { absoluteMoveBaseline(y, afpdata); - _currentXCoordinate = -1; + currentXCoordinate = -1; } // Avoid unnecessary specification of the X co-ordinate - if (x != _currentXCoordinate) { + if (x != currentXCoordinate) { absoluteMoveInline(x, afpdata); } // Avoid unnecessary specification of the variable space increment - if (vsci != _currentVariableSpaceCharacterIncrement) { + if (vsci != currentVariableSpaceCharacterIncrement) { setVariableSpaceCharacterIncrement(vsci, afpdata); - _currentVariableSpaceCharacterIncrement = vsci; + currentVariableSpaceCharacterIncrement = vsci; } // Avoid unnecessary specification of the inter character adjustment - if (ica != _currentInterCharacterAdjustment) { + if (ica != currentInterCharacterAdjustment) { setInterCharacterAdjustment(ica, afpdata); - _currentInterCharacterAdjustment = ica; + currentInterCharacterAdjustment = ica; } // Avoid unnecessary specification of the text color - if (!col.equals(_currentColor)) { + if (!col.equals(currentColor)) { setExtendedTextColor(col, afpdata); - _currentColor = col; + currentColor = col; } - setCodedFont(BinaryUtils.convert(fontNumber)[0], afpdata); + setCodedFont(BinaryUtils.convert(fontReference)[0], afpdata); addTransparentData(data, afpdata); - _currentXCoordinate = -1; + currentXCoordinate = -1; int s = afpdata.size(); - if (_baos.size() + s > MAX_SIZE) { - _currentXCoordinate = -1; - _currentYCoordinate = -1; + if (baos.size() + s > MAX_SIZE) { + currentXCoordinate = -1; + currentYCoordinate = -1; throw new MaximumSizeExceededException(); } byte[] outputdata = afpdata.toByteArray(); - _baos.write(outputdata, 0, outputdata.length); + baos.write(outputdata, 0, outputdata.length); } @@ -379,30 +379,31 @@ public class PresentationTextData extends AbstractAFPObject { * The orientation of the text data. * @param col * The text color. + * @throws MaximumSizeExceededException if the maximum size is exceeded */ public void createLineData(int x1, int y1, int x2, int y2, int thickness, int orientation, Color col) throws MaximumSizeExceededException { ByteArrayOutputStream afpdata = new ByteArrayOutputStream(); - if (_currentOrientation != orientation) { + if (currentOrientation != orientation) { setTextOrientation(orientation, afpdata); - _currentOrientation = orientation; + currentOrientation = orientation; } // Avoid unnecessary specification of the Y coordinate - if (y1 != _currentYCoordinate) { + if (y1 != currentYCoordinate) { absoluteMoveBaseline(y1, afpdata); } // Avoid unnecessary specification of the X coordinate - if (x1 != _currentXCoordinate) { + if (x1 != currentXCoordinate) { absoluteMoveInline(x1, afpdata); } - if (!col.equals(_currentColor)) { + if (!col.equals(currentColor)) { setExtendedTextColor(col, afpdata); - _currentColor = col; + currentColor = col; } if (y1 == y2) { @@ -415,14 +416,14 @@ public class PresentationTextData extends AbstractAFPObject { int s = afpdata.size(); - if (_baos.size() + s > MAX_SIZE) { - _currentXCoordinate = -1; - _currentYCoordinate = -1; + if (baos.size() + s > MAX_SIZE) { + currentXCoordinate = -1; + currentYCoordinate = -1; throw new MaximumSizeExceededException(); } byte[] outputdata = afpdata.toByteArray(); - _baos.write(outputdata, 0, outputdata.length); + baos.write(outputdata, 0, outputdata.length); } @@ -443,7 +444,7 @@ public class PresentationTextData extends AbstractAFPObject { private void setTextOrientation(int orientation, ByteArrayOutputStream afpdata) { - afpdata.write(new byte[] { 0x06, (byte) 0xF7, }, 0, 2); + afpdata.write(new byte[] {0x06, (byte) 0xF7}, 0, 2); switch (orientation) { case 90: @@ -559,12 +560,11 @@ public class PresentationTextData extends AbstractAFPObject { * Accessor method to write the AFP datastream for * the text data. * @param os The stream to write to - * @throws java.io.IOException + * @throws java.io.IOException if an I/O exception occurred */ - public void writeDataStream(OutputStream os) - throws IOException { + public void writeDataStream(OutputStream os) throws IOException { - byte[] data = _baos.toByteArray(); + byte[] data = baos.toByteArray(); byte[] size = BinaryUtils.convert(data.length - 1, 2); data[1] = size[0]; data[2] = size[1]; @@ -580,7 +580,7 @@ public class PresentationTextData extends AbstractAFPObject { * presentation text data objects, but must eventually be terminated. This * method terminates the control sequence. * - * @throws MaximumSizeExceededException + * @throws MaximumSizeExceededException if the maximum size is exceeded */ public void endControlSequence() throws MaximumSizeExceededException { @@ -588,12 +588,10 @@ public class PresentationTextData extends AbstractAFPObject { data[0] = 0x02; data[1] = (byte) 0xF8; - if (data.length + _baos.size() > MAX_SIZE) { + if (data.length + baos.size() > MAX_SIZE) { throw new MaximumSizeExceededException(); } - - _baos.write(data, 0, data.length); - + baos.write(data, 0, data.length); } }
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/PresentationTextDescriptor.java b/src/java/org/apache/fop/render/afp/modca/PresentationTextDescriptor.java index 3858f4169..27b3de5ca 100644 --- a/src/java/org/apache/fop/render/afp/modca/PresentationTextDescriptor.java +++ b/src/java/org/apache/fop/render/afp/modca/PresentationTextDescriptor.java @@ -52,12 +52,11 @@ public class PresentationTextDescriptor extends AbstractDescriptor { * width and height. * @param width The width of the page. * @param height The height of the page. - * @param widthResolution The width resolution of the page. - * @param heightResolution The height resolution of the page. + * @param widthRes The width resolution of the page. + * @param heightRes The height resolution of the page. */ - public PresentationTextDescriptor(int width, int height, - int widthResolution, int heightResolution) { - super(width, height, widthResolution, heightResolution); + public PresentationTextDescriptor(int width, int height, int widthRes, int heightRes) { + super(width, height, widthRes, heightRes); } /** @@ -81,11 +80,11 @@ public class PresentationTextDescriptor extends AbstractDescriptor { data[9] = 0x00; data[10] = 0x00; - byte[] xdpi = BinaryUtils.convert(widthResolution * 10, 2); + byte[] xdpi = BinaryUtils.convert(widthRes * 10, 2); data[11] = xdpi[0]; // xdpi data[12] = xdpi[1]; - byte[] ydpi = BinaryUtils.convert(heightResolution * 10, 2); + byte[] ydpi = BinaryUtils.convert(heightRes * 10, 2); data[13] = ydpi[0]; // ydpi data[14] = ydpi[1]; diff --git a/src/java/org/apache/fop/render/afp/modca/PresentationTextObject.java b/src/java/org/apache/fop/render/afp/modca/PresentationTextObject.java index c0f06439e..901f24bb1 100644 --- a/src/java/org/apache/fop/render/afp/modca/PresentationTextObject.java +++ b/src/java/org/apache/fop/render/afp/modca/PresentationTextObject.java @@ -100,7 +100,7 @@ public class PresentationTextObject extends AbstractNamedAFPObject { /** * Create the presentation text data for the byte array of data. * - * @param fontNumber + * @param fontReference * The font resource identifier. * @param x * The x coordinate for the text data. @@ -117,7 +117,7 @@ public class PresentationTextObject extends AbstractNamedAFPObject { * @param data * The text data to be created. */ - public void createTextData(int fontNumber, int x, int y, int orientation, + public void createTextData(int fontReference, int x, int y, int orientation, Color col, int vsci, int ica, byte[] data) { if (currentPresentationTextData == null) { @@ -126,13 +126,13 @@ public class PresentationTextObject extends AbstractNamedAFPObject { try { - currentPresentationTextData.createTextData(fontNumber, x, y, + currentPresentationTextData.createTextData(fontReference, x, y, orientation, col, vsci, ica, data); } catch (MaximumSizeExceededException msee) { endPresentationTextData(); - createTextData(fontNumber, x, y, orientation, col, vsci, ica, data); + createTextData(fontReference, x, y, orientation, col, vsci, ica, data); } diff --git a/src/java/org/apache/fop/render/afp/modca/TagLogicalElementBean.java b/src/java/org/apache/fop/render/afp/modca/TagLogicalElementBean.java index 29ac9eb5d..99f31ba14 100644 --- a/src/java/org/apache/fop/render/afp/modca/TagLogicalElementBean.java +++ b/src/java/org/apache/fop/render/afp/modca/TagLogicalElementBean.java @@ -47,7 +47,7 @@ public class TagLogicalElementBean { * @return the key */ public String getKey() { - return key; + return this.key; } /** @@ -55,7 +55,7 @@ public class TagLogicalElementBean { * @return the value */ public String getValue() { - return value; + return this.value; } } diff --git a/src/java/org/apache/fop/render/afp/modca/goca/AbstractGraphicsContainer.java b/src/java/org/apache/fop/render/afp/modca/goca/AbstractGraphicsContainer.java new file mode 100644 index 000000000..27a80acc4 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/AbstractGraphicsContainer.java @@ -0,0 +1,95 @@ +/* + * 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.modca.goca; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.List; + +import org.apache.fop.render.afp.modca.AbstractStructuredAFPObject; +import org.apache.fop.render.afp.modca.PreparedAFPObject; + +/** + * A base class container of GOCA structured objects + */ +public abstract class AbstractGraphicsContainer extends AbstractStructuredAFPObject +implements PreparedAFPObject { + + /** + * list of objects contained within this container + */ + protected List list = null; + + /** + * Default constructor + */ + public AbstractGraphicsContainer() { + } + + /** + * Named constructor + * @param name the name of the container + */ + public AbstractGraphicsContainer(String name) { + super(name); + } + + /** + * {@inheritDoc} + */ + protected void writeContent(OutputStream os) throws IOException { + if (list != null) { + super.writeObjectList(list, os); + } + } + + /** + * Adds a given graphics drawing order to this container + * @param drawingOrder the graphics drawing order + * @return the drawingOrder if it was added, null otherwise + */ + protected PreparedAFPObject addDrawingOrder(PreparedAFPObject drawingOrder) { + log.debug(this + " adding " + drawingOrder); + if (list == null) { + this.list = new java.util.ArrayList(); + } + list.add(drawingOrder); + return drawingOrder; + } + + /** + * @return the current data length of this container including + * all enclosed GOCA drawing objects (and their containers) + */ + public int getDataLength() { + int dataLen = 0; + if (list != null) { + Iterator it = list.iterator(); + while (it.hasNext()) { + Object obj = it.next(); + if (obj instanceof PreparedAFPObject) { + dataLen += ((PreparedAFPObject)obj).getDataLength(); + } + } + } + return dataLen; + } +} diff --git a/src/java/org/apache/fop/render/afp/modca/goca/AbstractGraphicsCoord.java b/src/java/org/apache/fop/render/afp/modca/goca/AbstractGraphicsCoord.java new file mode 100644 index 000000000..7378a5c07 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/AbstractGraphicsCoord.java @@ -0,0 +1,126 @@ +/* + * 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.modca.goca; + +import org.apache.fop.render.afp.tools.BinaryUtils; + +/** + * A base class encapsulating the structure of coordinate based GOCA objects + */ +public abstract class AbstractGraphicsCoord extends AbstractPreparedAFPObject { + + /** array of x/y coordinates */ + protected int[] coords = null; + + /** + * @param coords the x/y coordinates for this object + */ + public AbstractGraphicsCoord(int[] coords) { + this.coords = coords; + prepareData(); + } + + /** + * @param x the x coordinate for this object + * @param y the y coordinate for this object + */ + public AbstractGraphicsCoord(int x, int y) { + this(new int[] {x, y}); + } + + /** + * @param x1 the x1 coordinate for this object + * @param y1 the y1 coordinate for this object + * @param x2 the x2 coordinate for this object + * @param y2 the y2 coordinate for this object + */ + public AbstractGraphicsCoord(int x1, int y1, int x2, int y2) { + this(new int[] {x1, y1, x2, y2}); + } + + /** + * @return the order code to use + */ + protected abstract byte getOrderCode(); + + /** + * @return the length of this order code + * (typically this is the same as the coordinate length) + */ + protected int getLength() { + return this.coords.length * 2; + } + + /** + * Creates a newly created and initialized byte data + * @return a newly created and initialized byte data + */ + protected byte[] createData() { + int len = getLength(); + byte[] data = new byte[len + 2]; + data[0] = getOrderCode(); // ORDER CODE + data[1] = (byte)len; // LENGTH + return data; + } + + /** + * {@inheritDoc} + */ + protected void prepareData() { + super.data = createData(); + int fromIndex = data.length - getLength(); + addCoords(data, fromIndex); + } + + /** + * Adds the coordinates to the structured field data + * @param data the structured field data + * @param fromIndex the start index + */ + protected void addCoords(byte[] data, int fromIndex) { + // X/Y POS + for (int i = 0; i < coords.length; i++, fromIndex += 2) { + byte[] coord = BinaryUtils.convert(coords[i], 2); + data[fromIndex] = coord[0]; + data[fromIndex + 1] = coord[1]; + } + } + + /** + * @return the short name of this GOCA object + */ + protected String getName() { + String className = getClass().getName(); + return className.substring(className.lastIndexOf(".") + 1); + } + + /** + * {@inheritDoc} + */ + public String toString() { + String coordsStr = ""; + for (int i = 0; i < coords.length; i++) { + coordsStr += (i % 2 == 0) ? "x" : "y"; + coordsStr += (i / 2) + "=" + coords[i] + ","; + } + coordsStr = coordsStr.substring(0, coordsStr.length() - 1); + return getName() + "(" + coordsStr + ")"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/AbstractPreparedAFPObject.java b/src/java/org/apache/fop/render/afp/modca/goca/AbstractPreparedAFPObject.java new file mode 100644 index 000000000..ed10e5456 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/AbstractPreparedAFPObject.java @@ -0,0 +1,56 @@ +/* + * 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.modca.goca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.render.afp.modca.AbstractAFPObject; +import org.apache.fop.render.afp.modca.PreparedAFPObject; + +/** + * A base class that carries out early preparation of structured field data + * for the AFP object (so the data length can be pre-calculated) + */ +public abstract class AbstractPreparedAFPObject extends AbstractAFPObject +implements PreparedAFPObject { + + /** structured field data to be written */ + protected byte[] data = null; + + /** + * {@inheritDoc} + */ + public void writeDataStream(OutputStream os) throws IOException { + if (this.data != null) { + os.write(this.data); + } + } + + /** + * @return the data length of this prepared AFP object + */ + public int getDataLength() { + if (this.data != null) { + return this.data.length; + } + return 0; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsArea.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsArea.java new file mode 100644 index 000000000..c96ca2973 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsArea.java @@ -0,0 +1,82 @@ +/* + * 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.modca.goca; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * A GOCA graphics area (container for filled shapes/objects) + */ +public final class GraphicsArea extends AbstractGraphicsContainer { + + /** draw boundary lines around this area */ + private boolean drawBoundary = false; + + /** + * Sets whether boundary lines are drawn + * @param drawBoundaryLines whether boundary lines are drawn + */ + public void setDrawBoundaryLines(boolean drawBoundaryLines) { + this.drawBoundary = drawBoundaryLines; + } + + private static final int RES1 = 1; + private static final int BOUNDARY = 2; + private static final int NO_BOUNDARY = 0; + + /** + * {@inheritDoc} + */ + public int getDataLength() { + // start len + end len + data len + return 4 + super.getDataLength(); + } + + /** + * {@inheritDoc} + */ + protected void writeStart(OutputStream os) throws IOException { + super.writeStart(os); + byte[] data = new byte[] { + (byte)0x68, // GBAR order code + (byte)(RES1 + (drawBoundary ? BOUNDARY : NO_BOUNDARY)) + }; + os.write(data); + } + + /** + * {@inheritDoc} + */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] endData = new byte[] { + (byte)0x60, // GEAR order code + 0x00, // LENGTH + }; + os.write(endData); + } + + /** + * {@inheritDoc} + */ + public String toString() { + return "GraphicsArea"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsBox.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsBox.java new file mode 100644 index 000000000..ea4894e84 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsBox.java @@ -0,0 +1,66 @@ +/* + * 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.modca.goca; + +/** + * A GOCA graphics rectangular box + */ +public final class GraphicsBox extends AbstractGraphicsCoord { + + /** + * @param coords the x/y coordinates for this object + */ + public GraphicsBox(int[] coords) { + super(coords); + } + + /** + * {@inheritDoc} + */ + protected byte getOrderCode() { + return (byte)0xC0; + } + + /** + * {@inheritDoc} + */ + protected int getLength() { + return 10; + } + + /** + * {@inheritDoc} + */ + protected void prepareData() { + super.data = createData(); + final int fromIndex = 4; + addCoords(data, fromIndex); + } + + /** + * {@inheritDoc} + */ + protected byte[] createData() { + byte[] data = super.createData(); + data[2] = (byte)0x20; // CONTROL draw control flags + data[3] = 0x00; // reserved + return data; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsChainedSegment.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsChainedSegment.java new file mode 100644 index 000000000..2c8f68857 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsChainedSegment.java @@ -0,0 +1,179 @@ +/* + * 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.modca.goca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.render.afp.modca.PreparedAFPObject; +import org.apache.fop.render.afp.tools.BinaryUtils; + +/** + * A GOCA graphics segment + */ +public final class GraphicsChainedSegment extends AbstractGraphicsContainer { + + /** + * The maximum segment data length + */ + protected static final int MAX_DATA_LEN = 8192; + + /** the current area */ + private GraphicsArea currentArea = null; + + /** the previous segment in the chain */ + private GraphicsChainedSegment previous = null; + + /** the next segment in the chain */ + private GraphicsChainedSegment next = null; + + /** + * Main constructor + * + * @param name + * the name of this graphics segment + */ + public GraphicsChainedSegment(String name) { + super(name); + } + + /** + * Constructor + * + * @param name + * the name of this graphics segment + * @param previous + * the previous graphics segment in this chain + */ + public GraphicsChainedSegment(String name, GraphicsChainedSegment previous) { + super(name); + previous.next = this; + this.previous = previous; + } + + /** + * {@inheritDoc} + */ + public int getDataLength() { + int dataLen = 14 + super.getDataLength(); + if (previous == null) { + GraphicsChainedSegment current = this.next; + while (current != null) { + dataLen += current.getDataLength(); + current = current.next; + } + } + return dataLen; + } + + /** + * {@inheritDoc} + */ + protected int getNameLength() { + return 4; + } + + private static final byte APPEND_NEW_SEGMENT = 0; + + private static final byte PROLOG = 4; + + private static final byte APPEND_TO_EXISING = 48; + + /** + * {@inheritDoc} + */ + protected void writeStart(OutputStream os) throws IOException { + super.writeStart(os); + int len = super.getDataLength(); + byte[] segLen = BinaryUtils.convert(len, 2); + byte[] data = new byte[] { + 0x70, // BEGIN_SEGMENT + 0x0C, // Length of following parameters + this.nameBytes[0], + this.nameBytes[1], + this.nameBytes[2], + this.nameBytes[3], + 0x00, // FLAG1 (ignored) + APPEND_NEW_SEGMENT, + segLen[0], // SEGL + segLen[1], + 0x00, + 0x00, + 0x00, + 0x00 + }; + // P/S NAME (predecessor name) + if (previous != null) { + data[10] = previous.nameBytes[0]; + data[11] = previous.nameBytes[1]; + data[12] = previous.nameBytes[2]; + data[13] = previous.nameBytes[3]; + } + os.write(data); + } + + /** + * {@inheritDoc} + */ + protected void writeEnd(OutputStream os) throws IOException { + // I am the first segment in the chain so write out the rest + if (previous == null) { + GraphicsChainedSegment current = this.next; + while (current != null) { + current.writeDataStream(os); + current = current.next; + } + } + } + + /** + * Begins a graphics area (start of fill) + */ + protected void beginArea() { + this.currentArea = new GraphicsArea(); + super.addDrawingOrder(currentArea); + } + + /** + * Ends a graphics area (end of fill) + */ + protected void endArea() { + this.currentArea = null; + } + + /** + * {@inheritDoc} + */ + protected PreparedAFPObject addDrawingOrder(PreparedAFPObject drawingOrder) { + if (currentArea != null) { + currentArea.addDrawingOrder(drawingOrder); + } else { + super.addDrawingOrder(drawingOrder); + } + return drawingOrder; + } + + /** + * {@inheritDoc} + */ + public String toString() { + return "GraphicsChainedSegment(name=" + super.name + ")"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsData.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsData.java new file mode 100644 index 000000000..b660d5b9a --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsData.java @@ -0,0 +1,147 @@ +/* + * 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.modca.goca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.render.afp.modca.PreparedAFPObject; +import org.apache.fop.render.afp.tools.BinaryUtils; +import org.apache.fop.render.afp.tools.StringUtils; + +/** + * A GOCA graphics data + */ +public final class GraphicsData extends AbstractGraphicsContainer { + + /** + * The maximum graphics data length + */ + public static final int MAX_DATA_LEN = 32767; + + /** + * Default constructor + */ + public GraphicsData() { + } + + /** + * The graphics segment + */ + private GraphicsChainedSegment currentSegment = null; + + /** + * {@inheritDoc} + */ + public int getDataLength() { + return 8 + super.getDataLength(); + } + + /** + * {@inheritDoc} + */ + protected void writeStart(OutputStream os) throws IOException { + super.writeStart(os); + int l = getDataLength(); + byte[] len = BinaryUtils.convert(l, 2); + byte[] data = new byte[] { + 0x5A, // Structured field identifier + len[0], // Length byte 1 + len[1], // Length byte 2 + (byte) 0xD3, // Structured field id byte 1 + (byte) 0xEE, // Structured field id byte 2 + (byte) 0xBB, // Structured field id byte 3 + 0x00, // Flags + 0x00, // Reserved + 0x00 // Reserved + }; + os.write(data); + } + + /** + * Begins a graphics area (start of fill) + */ + public void beginArea() { + getSegment().beginArea(); + } + + /** + * Ends a graphics area (end of fill) + */ + public void endArea() { + getSegment().endArea(); + } + + /** + * Returns a new segment name + * @return a new segment name + */ + private String createSegmentName() { + return StringUtils.lpad(String.valueOf( + (super.list != null ? super.list.size() : 0) + 1), + '0', 4); + } + + /** + * Returns the current graphics segment, creating one if one does not exist + * @return the current graphics chained segment + */ + GraphicsChainedSegment getSegment() { + if (currentSegment == null) { + newSegment(); + } + return this.currentSegment; + } + + /** + * Creates a new graphics segment + * @return a newly created graphics segment + */ + public GraphicsChainedSegment newSegment() { + String name = createSegmentName(); + if (currentSegment == null) { + this.currentSegment = new GraphicsChainedSegment(name); + } else { + this.currentSegment = new GraphicsChainedSegment(name, currentSegment); + } + super.addDrawingOrder(currentSegment); + return currentSegment; + } + + /** + * {@inheritDoc} + */ + public PreparedAFPObject addDrawingOrder(PreparedAFPObject drawingOrder) { + if (currentSegment == null + || (currentSegment.getDataLength() + drawingOrder.getDataLength()) + >= GraphicsChainedSegment.MAX_DATA_LEN) { + newSegment(); + } + currentSegment.addDrawingOrder(drawingOrder); + return drawingOrder; + } + + /** + * {@inheritDoc} + */ + public String toString() { + return "GraphicsData"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsFillet.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsFillet.java new file mode 100644 index 000000000..ab30a3d93 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsFillet.java @@ -0,0 +1,41 @@ +/* + * 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.modca.goca; + +/** + * A GOCA graphics curved tangential line to a specified set of + * straight lines drawn from the given position or current position + */ +public final class GraphicsFillet extends AbstractGraphicsCoord { + + /** + * @param coords the x/y coordinates for this object + */ + public GraphicsFillet(int[] coords) { + super(coords); + } + + /** + * {@inheritDoc} + */ + protected byte getOrderCode() { + return (byte)0xC5; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsFullArc.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsFullArc.java new file mode 100644 index 000000000..b0dcf9c22 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsFullArc.java @@ -0,0 +1,81 @@ +/* + * 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.modca.goca; + +import org.apache.fop.render.afp.tools.BinaryUtils; + +/** + * A GOCA graphics arc (circle/ellipse) + */ +public class GraphicsFullArc extends AbstractGraphicsCoord { + /** the integer portion of the multiplier */ + private int mh; + + /** the fractional portion of the multiplier */ + private int mhr; + + /** + * @param x the x coordinate of the center of the circle/ellipse + * @param y the y coordinate of the center of the circle/ellipse + * @param mh the integer portion of the multiplier + * @param mhr the fractional portion of the multiplier + */ + public GraphicsFullArc(int x, int y, int mh, int mhr) { + super(x, y); + this.mh = mh; + this.mhr = mhr; + // integer portion of multiplier + data[data.length - 2] = BinaryUtils.convert(mh, 1)[0]; + // fractional portion of multiplier + data[data.length - 1] = BinaryUtils.convert(mhr, 1)[0]; + } + + /** + * {@inheritDoc} + */ + protected byte getOrderCode() { + return (byte)0xC7; + } + + /** + * {@inheritDoc} + */ + protected int getLength() { + return super.getLength() + 2; + } + + /** + * {@inheritDoc} + */ + protected void prepareData() { + super.data = super.createData(); + final int fromIndex = 2; + super.addCoords(data, fromIndex); + } + + /** + * {@inheritDoc} + */ + public String toString() { + return super.getName() + + "(centerx=" + coords[0] + ",centery=" + coords[1] + + ",mh=" + mh + ",mhr=" + mhr + ")"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsImageBegin.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsImageBegin.java new file mode 100644 index 000000000..f7511e54f --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsImageBegin.java @@ -0,0 +1,85 @@ +/* + * 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.modca.goca; + +import org.apache.fop.render.afp.tools.BinaryUtils; + +/** + * A GOCA graphics begin image object + */ +public final class GraphicsImageBegin extends AbstractPreparedAFPObject { + /** x coordinate */ + private int x; + + /** y coordinate */ + private int y; + + /** width */ + private int width; + + /** height */ + private int height; + + /** + * @param x the x coordinate of the image + * @param y the y coordinate of the image + * @param width the image width + * @param height the image height + */ + public GraphicsImageBegin(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + prepareData(); + } + + /** + * {@inheritDoc} + */ + protected void prepareData() { + byte[] xcoord = BinaryUtils.convert(x, 2); + byte[] ycoord = BinaryUtils.convert(y, 2); + byte[] w = BinaryUtils.convert(width, 2); + byte[] h = BinaryUtils.convert(height, 2); + super.data = new byte[] { + (byte) 0xD1, // GBIMG order code + (byte) 0x0A, // LENGTH + xcoord[0], + xcoord[1], + ycoord[0], + ycoord[1], + 0x00, // FORMAT + 0x00, // RES + w[0], // WIDTH + w[1], // + h[0], // HEIGHT + h[1] // + }; + } + + /** + * {@inheritDoc} + */ + public String toString() { + return "GraphicsImageBegin(x=" + x + ",y=" + y + + ",width=" + width + ",height=" + height + ")"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsImageData.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsImageData.java new file mode 100644 index 000000000..4cb59e51a --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsImageData.java @@ -0,0 +1,57 @@ +/* + * 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.modca.goca; + +import org.apache.fop.render.afp.tools.BinaryUtils; + +/** + * A GOCA graphics image data + */ +public final class GraphicsImageData extends AbstractPreparedAFPObject { + + /** the maximum image data length */ + public static final short MAX_DATA_LEN = 255; + + /** + * Main constructor + * + * @param imageData the image data + * @param startIndex the start index to read the image data from + */ + public GraphicsImageData(byte[] imageData, int startIndex) { + int dataLen = MAX_DATA_LEN; + if (startIndex + MAX_DATA_LEN >= imageData.length) { + dataLen = imageData.length - startIndex - 1; + } + super.data = new byte[dataLen + 2]; + data[0] = (byte) 0x92; // GIMD + data[1] = BinaryUtils.convert(dataLen, 1)[0]; // LENGTH + System.arraycopy(imageData, startIndex, data, 2, dataLen); + } + + /** + * {@inheritDoc} + */ + public String toString() { + return "GraphicsImageData(" + + (data != null ? "" + (data.length - 2) : "null") + + ")"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsImageEnd.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsImageEnd.java new file mode 100644 index 000000000..e365e4444 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsImageEnd.java @@ -0,0 +1,50 @@ +/* + * 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.modca.goca; + +/** + * A GOCA graphics image data + */ +public class GraphicsImageEnd extends AbstractPreparedAFPObject { + + /** + * Default constructor + */ + public GraphicsImageEnd() { + prepareData(); + } + + /** + * {@inheritDoc} + */ + protected void prepareData() { + super.data = new byte[] { + (byte) 0x93, // GEIMG order code + 0x00 // LENGTH + }; + } + + /** + * {@inheritDoc} + */ + public String toString() { + return "GraphicsImageEnd"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsLine.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsLine.java new file mode 100644 index 000000000..4bf396d0b --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsLine.java @@ -0,0 +1,42 @@ +/* + * 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.modca.goca; + + +/** + * A GOCA graphics straight line drawn from the + * given position or current position. + */ +public class GraphicsLine extends AbstractGraphicsCoord { + + /** + * @param coords the x/y coordinates for this object + */ + public GraphicsLine(int[] coords) { + super(coords); + } + + /** + * {@inheritDoc} + */ + protected byte getOrderCode() { + return (byte)0xC1; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetArcParameters.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetArcParameters.java new file mode 100644 index 000000000..6e1c7abf9 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetArcParameters.java @@ -0,0 +1,53 @@ +/* + * 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.modca.goca; + +/** + * Sets the arc parameters for a GOCA graphics arc (circle/ellipse) + */ +public class GraphicsSetArcParameters extends AbstractGraphicsCoord { + + /** + * @param xmaj x coordinate of the major axis point + * @param ymin y coordinate of the minor axis point + * @param xmin x coordinate of the minor axis point + * @param ymaj y coordinate of the major axis point + */ + public GraphicsSetArcParameters(int xmaj, int ymin, int xmin, int ymaj) { + super(xmaj, ymin, xmin, ymaj); + } + + /** + * {@inheritDoc} + */ + protected byte getOrderCode() { + return 0x22; + } + + /** + * {@inheritDoc} + */ + public String toString() { + return getName() + "(xmaj=" + coords[0] + + ",ymin=" + coords[1] + + ",xmin=" + coords[2] + + ",ymaj=" + coords[3] + ")"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetCharacterSet.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetCharacterSet.java new file mode 100644 index 000000000..be244bd06 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetCharacterSet.java @@ -0,0 +1,55 @@ +/* + * 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.modca.goca; + +import org.apache.fop.render.afp.tools.BinaryUtils; + +/** + * Sets the current character set (font) to be used for following graphics strings + */ +public class GraphicsSetCharacterSet extends AbstractPreparedAFPObject { + /** font character set reference */ + private int fontReference; + + /** + * @param fontReference character set font reference + */ + public GraphicsSetCharacterSet(int fontReference) { + this.fontReference = fontReference; + prepareData(); + } + + /** + * {@inheritDoc} + */ + protected void prepareData() { + super.data = new byte[] { + 0x38, // GSCS order code + BinaryUtils.convert(fontReference)[0] + }; + } + + /** + * {@inheritDoc} + */ + public String toString() { + return "GraphicsSetCharacterSet(" + fontReference + ")"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetCurrentPosition.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetCurrentPosition.java new file mode 100644 index 000000000..afa825a84 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetCurrentPosition.java @@ -0,0 +1,41 @@ +/* + * 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.modca.goca; + + +/** + * Sets the current painting position of the graphics object + */ +public class GraphicsSetCurrentPosition extends AbstractGraphicsCoord { + + /** + * @param coords the x/y coordinates for this object + */ + public GraphicsSetCurrentPosition(int[] coords) { + super(coords); + } + + /** + * {@inheritDoc} + */ + protected byte getOrderCode() { + return (byte)0x21; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetLineType.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetLineType.java new file mode 100644 index 000000000..99c2902c0 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetLineType.java @@ -0,0 +1,86 @@ +/* + * 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.modca.goca; + +/** + * Sets the value of the current line type attribute when stroking GOCA shapes (structured fields) + */ +public class GraphicsSetLineType extends AbstractPreparedAFPObject { + /** the default line type */ + public static final byte DEFAULT = 0x00; // normally SOLID + + /** the default line type */ + public static final byte DOTTED = 0x01; + + /** short dashed line type */ + public static final byte SHORT_DASHED = 0x02; + + /** dashed dotted line type */ + public static final byte DASH_DOT = 0x03; + + /** double dotted line type */ + public static final byte DOUBLE_DOTTED = 0x04; + + /** long dashed line type */ + public static final byte LONG_DASHED = 0x05; + + /** dash double dotted line type */ + public static final byte DASH_DOUBLE_DOTTED = 0x06; + + /** solid line type */ + public static final byte SOLID = 0x07; + + /** invisible line type */ + public static final byte INVISIBLE = 0x08; + + /** line type */ + private byte type = DEFAULT; + + /** + * Main constructor + * @param type line type + */ + public GraphicsSetLineType(byte type) { + this.type = type; + prepareData(); + } + + /** + * {@inheritDoc} + */ + protected void prepareData() { + super.data = new byte[] { + 0x18, // GSLW order code + type // line type + }; + } + + private static final String[] TYPES = { + "DEFAULT", "DOTTED", "SHORT_DASHED", "DASH_DOT", "DOUBLE_DOTTED", + "LONG_DASHED", "DASH_DOUBLE_DOTTED", "SOLID", "INVISIBLE" + }; + + /** + * {@inheritDoc} + */ + public String toString() { + return "GraphicsSetLineType(type=" + TYPES[type] + ")"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetLineWidth.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetLineWidth.java new file mode 100644 index 000000000..8e08d09e2 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetLineWidth.java @@ -0,0 +1,54 @@ +/* + * 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.modca.goca; + +/** + * Sets the line width to use when stroking GOCA shapes (structured fields) + */ +public class GraphicsSetLineWidth extends AbstractPreparedAFPObject { + /** line width multiplier */ + private int multiplier = 1; + + /** + * Main constructor + * @param multiplier the line width multiplier + */ + public GraphicsSetLineWidth(int multiplier) { + this.multiplier = multiplier; + prepareData(); + } + + /** + * {@inheritDoc} + */ + protected void prepareData() { + super.data = new byte[] { + 0x19, // GSLW order code + (byte)multiplier // MH (line-width) + }; + } + + /** + * {@inheritDoc} + */ + public String toString() { + return "GraphicsSetLineWidth(multiplier=" + multiplier + ")"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetPatternSymbol.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetPatternSymbol.java new file mode 100644 index 000000000..9a04139a2 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetPatternSymbol.java @@ -0,0 +1,106 @@ +/* + * 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.modca.goca; + +/** + * Sets the pattern symbol to use when filling following GOCA structured fields + */ +public class GraphicsSetPatternSymbol extends AbstractPreparedAFPObject { + /** dotted density 1 */ + public static final byte DOTTED_DENSITY_1 = 0x01; + + /** dotted density 2 */ + public static final byte DOTTED_DENSITY_2 = 0x02; + + /** dotted density 3 */ + public static final byte DOTTED_DENSITY_3 = 0x03; + + /** dotted density 4 */ + public static final byte DOTTED_DENSITY_4 = 0x04; + + /** dotted density 5 */ + public static final byte DOTTED_DENSITY_5 = 0x05; + + /** dotted density 6 */ + public static final byte DOTTED_DENSITY_6 = 0x06; + + /** dotted density 7 */ + public static final byte DOTTED_DENSITY_7 = 0x07; + + /** dotted density 8 */ + public static final byte DOTTED_DENSITY_8 = 0x08; + + /** dotted density 9 */ + public static final byte VERTICAL_LINES = 0x09; + + /** horizontal lines */ + public static final byte HORIZONTAL_LINES = 0x0A; + + /** diagonal lines, bottom left to top right 1 */ + public static final byte DIAGONAL_LINES_BLTR_1 = 0x0B; + + /** diagonal lines, bottom left to top right 2 */ + public static final byte DIAGONAL_LINES_BLTR_2 = 0x0C; + + /** diagonal lines, top left to bottom right 1 */ + public static final byte DIAGONAL_LINES_TLBR_1 = 0x0D; + + /** diagonal lines, top left to bottom right 2 */ + public static final byte DIAGONAL_LINES_TLBR_2 = 0x0E; + + /** no fill */ + public static final byte NO_FILL = 0x0F; + + /** solid fill */ + public static final byte SOLID_FILL = 0x10; + + /** blank (same as no fill) */ + public static final byte BLANK = 0x40; // processed same as NO_FILL + + /** the graphics pattern symbol to use */ + private byte symbol; + + /** + * Main constructor + * @param symb the pattern symbol to use + */ + public GraphicsSetPatternSymbol(byte symb) { + this.symbol = symb; + prepareData(); + } + + /** + * {@inheritDoc} + */ + protected void prepareData() { + super.data = new byte[] { + 0x28, // GSPT order code + symbol + }; + } + + /** + * {@inheritDoc} + */ + public String toString() { + return "GraphicsSetPatternSymbol(fill=" + + (symbol == SOLID_FILL ? true : false) + ")"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetProcessColor.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetProcessColor.java new file mode 100644 index 000000000..47df7ba14 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsSetProcessColor.java @@ -0,0 +1,92 @@ +/* + * 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.modca.goca; + +import java.awt.Color; +import java.awt.color.ColorSpace; + +import org.apache.fop.render.afp.modca.GraphicsObject; + +/** + * Sets the current processing color for the following GOCA structured fields + */ +public class GraphicsSetProcessColor extends AbstractPreparedAFPObject { + /** the color to set */ + private Color col; + + /** + * Main constructor + * @param col the color to set + */ + public GraphicsSetProcessColor(Color col) { + this.col = col; + prepareData(); + } + + /** + * {@inheritDoc} + */ + protected void prepareData() { + // COLSPCE + byte colspace; + int colSpaceType = col.getColorSpace().getType(); + if (colSpaceType == ColorSpace.TYPE_CMYK) { + colspace = 0x04; + } else if (colSpaceType == ColorSpace.TYPE_RGB) { + colspace = 0x01; + } else { + GraphicsObject.log.error("unsupported colorspace " + colSpaceType); + colspace = 0x01; + } + + // COLSIZE(S) + float[] colcomp = col.getColorComponents(null); + byte[] colsizes = new byte[] {0x00, 0x00, 0x00, 0x00}; + for (int i = 0; i < colcomp.length; i++) { + colsizes[i] = (byte)8; + } + + int len = 10 + colcomp.length; + super.data = new byte[len + 2]; + data[0] = (byte)0xB2; // GSPCOL order code + data[1] = (byte)len; // LEN + data[2] = 0x00; // reserved; must be zero + data[3] = colspace; // COLSPCE + data[4] = 0x00; // reserved; must be zero + data[5] = 0x00; // reserved; must be zero + data[6] = 0x00; // reserved; must be zero + data[7] = 0x00; // reserved; must be zero + data[8] = colsizes[0]; // COLSIZE(S) + data[9] = colsizes[1]; + data[10] = colsizes[2]; + data[11] = colsizes[3]; + // COLVALUE(S) + for (int i = 0; i < colcomp.length; i++) { + data[i + 12] = (byte)(colcomp[i] * 255); + } + } + + /** + * {@inheritDoc} + */ + public String toString() { + return "GraphicsSetProcessColor(col=" + col + ")"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/goca/GraphicsString.java b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsString.java new file mode 100644 index 000000000..1750c4348 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/modca/goca/GraphicsString.java @@ -0,0 +1,115 @@ +/* + * 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.modca.goca; + +import java.io.UnsupportedEncodingException; + +import org.apache.fop.render.afp.modca.AFPConstants; +import org.apache.fop.render.afp.modca.GraphicsObject; +import org.apache.fop.render.afp.tools.BinaryUtils; + +/** + * A GOCA graphics string + */ +public class GraphicsString extends AbstractPreparedAFPObject { + /** Up to 255 bytes of character data */ + private static final int MAX_STR_LEN = 255; + + /** drawn from the current position */ + private boolean fromCurrentPosition = false; + + /** the string to draw */ + private String str = null; + + /** x coordinate */ + private int x; + + /** y coordinate */ + private int y; + + /** + * @param str the character string + */ + public GraphicsString(String str) { + this.str = str; + fromCurrentPosition = true; + prepareData(); + } + + /** + * @param str the character string + * @param x the x coordinate + * @param y the y coordinate + */ + public GraphicsString(String str, int x, int y) { + this.str = str; + this.x = x; + this.y = y; + prepareData(); + } + + /** + * {@inheritDoc} + */ + protected void prepareData() { + int maxStrLen = MAX_STR_LEN - (fromCurrentPosition ? 0 : 4); + if (str.length() > maxStrLen) { + str = str.substring(0, maxStrLen); + log.warn("truncated character string, longer than " + maxStrLen + " chars"); + } + byte[] strData = null; + try { + strData = str.getBytes(AFPConstants.EBCIDIC_ENCODING); + } catch (UnsupportedEncodingException ex) { + GraphicsObject.log.error("unsupported encoding: " + ex.getMessage()); + } + int len = strData.length; + if (fromCurrentPosition) { + data = new byte[len + 2]; + data[0] = (byte)0x83; + data[1] = (byte)len; + System.arraycopy(strData, 0, data, 2, strData.length); + } else { + len += 4; // x/y coordinates + byte[] osx = BinaryUtils.convert(x, 2); + byte[] osy = BinaryUtils.convert(y, 2); + data = new byte[len + 2]; + data[0] = (byte)0xC3; + data[1] = (byte)len; + data[2] = osx[0]; + data[3] = osx[1]; + data[4] = osy[0]; + data[5] = osy[1]; + System.arraycopy(strData, 0, data, 6, strData.length); + } + } + + /** + * {@inheritDoc} + */ + public String toString() { + String string = "GraphicsString(str='" + str + "'"; + if (!fromCurrentPosition) { + string += ",x=" + x + ",y=" + y; + } + string += ")"; + return string; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java b/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java index e6a855b83..75ed0de52 100644 --- a/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java +++ b/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java @@ -35,7 +35,7 @@ import org.apache.batik.transcoder.TranscoderException; import org.apache.batik.transcoder.TranscoderOutput; import org.apache.batik.transcoder.image.ImageTranscoder; import org.apache.xmlgraphics.java2d.ps.AbstractPSDocumentGraphics2D; -import org.apache.xmlgraphics.java2d.ps.TextHandler; +import org.apache.xmlgraphics.java2d.TextHandler; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontSetup; diff --git a/src/java/org/apache/fop/render/ps/NativeTextHandler.java b/src/java/org/apache/fop/render/ps/NativeTextHandler.java index f0cb140f9..5b840484d 100644 --- a/src/java/org/apache/fop/render/ps/NativeTextHandler.java +++ b/src/java/org/apache/fop/render/ps/NativeTextHandler.java @@ -28,14 +28,14 @@ import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontSetup; import org.apache.fop.fonts.FontTriplet; import org.apache.xmlgraphics.java2d.ps.PSGraphics2D; -import org.apache.xmlgraphics.java2d.ps.TextHandler; +import org.apache.xmlgraphics.java2d.ps.PSTextHandler; import org.apache.xmlgraphics.ps.PSGenerator; /** * Specialized TextHandler implementation that the PSGraphics2D class delegates to to paint text * using PostScript text operations. */ -public class NativeTextHandler implements TextHandler { +public class NativeTextHandler implements PSTextHandler { private PSGraphics2D g2d; diff --git a/src/java/org/apache/fop/render/ps/PSTextPainter.java b/src/java/org/apache/fop/render/ps/PSTextPainter.java index 955db492d..08cea6517 100644 --- a/src/java/org/apache/fop/render/ps/PSTextPainter.java +++ b/src/java/org/apache/fop/render/ps/PSTextPainter.java @@ -40,7 +40,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xmlgraphics.java2d.ps.PSGraphics2D; -import org.apache.xmlgraphics.java2d.ps.TextHandler; +import org.apache.xmlgraphics.java2d.TextHandler; import org.apache.batik.dom.svg.SVGOMTextElement; import org.apache.batik.gvt.text.Mark; @@ -385,7 +385,6 @@ public class PSTextPainter implements TextPainter { String style = getStyle(aci); int weight = getWeight(aci); - boolean found = false; String fontFamily = null; List gvtFonts = (List) aci.getAttribute( GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES); |