diff options
author | Jeremias Maerki <jeremias@apache.org> | 2008-12-09 15:00:35 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2008-12-09 15:00:35 +0000 |
commit | a6ddced309701a1ca8d79a9e7bec3288afba2cc8 (patch) | |
tree | c3d2bcfe7277246d9a2acc3675721a99f4de5727 /src/java | |
parent | 9d339f0968314f0cfcc4a720628fed1845292ce1 (diff) | |
parent | f9d4720b99f5e0fb423b097d7207dfab446d911c (diff) | |
download | xmlgraphics-fop-a6ddced309701a1ca8d79a9e7bec3288afba2cc8.tar.gz xmlgraphics-fop-a6ddced309701a1ca8d79a9e7bec3288afba2cc8.zip |
Merge from Trunk revisions 719662 - 724689.
Conflict for ImageHandler interface resolved by renaming Trunk's ImageHandler to ImageHandlerBase and extending the other ImageHandler from that.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign@724729 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java')
291 files changed, 21696 insertions, 8675 deletions
diff --git a/src/java/META-INF/services/org.apache.fop.render.afp.AFPImageHandler b/src/java/META-INF/services/org.apache.fop.render.afp.AFPImageHandler new file mode 100644 index 000000000..deab7d259 --- /dev/null +++ b/src/java/META-INF/services/org.apache.fop.render.afp.AFPImageHandler @@ -0,0 +1,5 @@ +org.apache.fop.render.afp.AFPImageHandlerRenderedImage
+org.apache.fop.render.afp.AFPImageHandlerRawCCITTFax
+org.apache.fop.render.afp.AFPImageHandlerRawStream
+org.apache.fop.render.afp.AFPImageHandlerGraphics2D
+org.apache.fop.render.afp.AFPImageHandlerXML
diff --git a/src/java/org/apache/fop/afp/AFPBorderPainter.java b/src/java/org/apache/fop/afp/AFPBorderPainter.java new file mode 100644 index 000000000..4c56c0def --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPBorderPainter.java @@ -0,0 +1,194 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +import java.awt.geom.AffineTransform; + +import org.apache.fop.fo.Constants; +import org.apache.fop.util.ColorUtil; + +/** + * Handles the drawing of borders/lines in AFP + */ +public class AFPBorderPainter extends AbstractAFPPainter { + + /** + * Main constructor + * + * @param paintingState the AFP painting state converter + * @param dataStream the AFP datastream + */ + public AFPBorderPainter(AFPPaintingState paintingState, DataStream dataStream) { + super(paintingState, dataStream); + } + + /** {@inheritDoc} */ + public void paint(PaintingInfo paintInfo) { + BorderPaintingInfo borderPaintInfo = (BorderPaintingInfo)paintInfo; + float w = borderPaintInfo.getX2() - borderPaintInfo.getX1(); + float h = borderPaintInfo.getY2() - borderPaintInfo.getY1(); + if ((w < 0) || (h < 0)) { + log.error("Negative extent received. Border won't be painted."); + return; + } + + int pageWidth = dataStream.getCurrentPage().getWidth(); + int pageHeight = dataStream.getCurrentPage().getHeight(); + AFPUnitConverter unitConv = paintingState.getUnitConverter(); + AffineTransform at = paintingState.getData().getTransform(); + + float x1 = unitConv.pt2units(borderPaintInfo.getX1()); + float y1 = unitConv.pt2units(borderPaintInfo.getY1()); + float x2 = unitConv.pt2units(borderPaintInfo.getX2()); + float y2 = unitConv.pt2units(borderPaintInfo.getY2()); + + switch (paintingState.getRotation()) { + case 0: + x1 += at.getTranslateX(); + y1 += at.getTranslateY(); + x2 += at.getTranslateX(); + y2 += at.getTranslateY(); + break; + case 90: + x1 += at.getTranslateY(); + y1 += (float) (pageWidth - at.getTranslateX()); + x2 += at.getTranslateY(); + y2 += (float) (pageWidth - at.getTranslateX()); + break; + case 180: + x1 += (float) (pageWidth - at.getTranslateX()); + y1 += (float) (pageHeight - at.getTranslateY()); + x2 += (float) (pageWidth - at.getTranslateX()); + y2 += (float) (pageHeight - at.getTranslateY()); + break; + case 270: + x1 = (float) (pageHeight - at.getTranslateY()); + y1 += (float) at.getTranslateX(); + x2 += x1; + y2 += (float) at.getTranslateX(); + break; + } + + AFPLineDataInfo lineDataInfo = new AFPLineDataInfo(); + lineDataInfo.setColor(borderPaintInfo.getColor()); + lineDataInfo.setRotation(paintingState.getRotation()); + lineDataInfo.x1 = Math.round(x1); + lineDataInfo.y1 = Math.round(y1); + if (borderPaintInfo.isHorizontal()) { + lineDataInfo.setThickness(Math.round(y2 - y1)); + } else { + lineDataInfo.setThickness(Math.round(x2 - x1)); + } + + // handle border-*-style + switch (borderPaintInfo.getStyle()) { + case Constants.EN_DOUBLE: + if (borderPaintInfo.isHorizontal()) { + lineDataInfo.x2 = Math.round(x2); + lineDataInfo.y2 = lineDataInfo.y1; + dataStream.createLine(lineDataInfo); + lineDataInfo.y1 += Math.round((lineDataInfo.thickness / 3) * 2); + dataStream.createLine(lineDataInfo); + } else { + lineDataInfo.x2 = lineDataInfo.x1; + lineDataInfo.y2 = Math.round(y2); + dataStream.createLine(lineDataInfo); + lineDataInfo.x1 += Math.round((lineDataInfo.thickness / 3) * 2); + dataStream.createLine(lineDataInfo); + } + break; + case Constants.EN_DASHED: + int thick = lineDataInfo.thickness * 3; + if (borderPaintInfo.isHorizontal()) { + lineDataInfo.x2 = lineDataInfo.x1 + thick; + lineDataInfo.y2 = lineDataInfo.y1; + int ex2 = Math.round(x2); + while (lineDataInfo.x1 + thick < ex2) { + dataStream.createLine(lineDataInfo); + lineDataInfo.x1 += 2 * thick; + lineDataInfo.x2 = lineDataInfo.x1 + thick; + } + } else { + lineDataInfo.x2 = lineDataInfo.x1; + lineDataInfo.y2 = lineDataInfo.y1 + thick; + int ey2 = Math.round(y2); + while (lineDataInfo.y1 + thick < ey2) { + dataStream.createLine(lineDataInfo); + lineDataInfo.y1 += 2 * thick; + lineDataInfo.y2 = lineDataInfo.y1 + thick; + } + } + break; + case Constants.EN_DOTTED: + if (borderPaintInfo.isHorizontal()) { + lineDataInfo.x2 = lineDataInfo.x1 + lineDataInfo.thickness; + lineDataInfo.y2 = lineDataInfo.y1; + int ex2 = Math.round(x2); + while (lineDataInfo.x1 + lineDataInfo.thickness < ex2) { + dataStream.createLine(lineDataInfo); + lineDataInfo.x1 += 3 * lineDataInfo.thickness; + lineDataInfo.x2 = lineDataInfo.x1 + lineDataInfo.thickness; + } + } else { + lineDataInfo.x2 = lineDataInfo.x1; + lineDataInfo.y2 = lineDataInfo.y1 + lineDataInfo.thickness; + int ey2 = Math.round(y2); + while (lineDataInfo.y1 + lineDataInfo.thickness < ey2) { + dataStream.createLine(lineDataInfo); + lineDataInfo.y1 += 3 * lineDataInfo.thickness; + lineDataInfo.y2 = lineDataInfo.y1 + lineDataInfo.thickness; + } + } + break; + case Constants.EN_GROOVE: + case Constants.EN_RIDGE: + //TODO + lineDataInfo.x2 = Math.round(x2); + float colFactor = (borderPaintInfo.getStyle() == Constants.EN_GROOVE ? 0.4f : -0.4f); + float h3 = (y2 - y1) / 3; + lineDataInfo.color = ColorUtil.lightenColor(borderPaintInfo.getColor(), -colFactor); + lineDataInfo.thickness = Math.round(h3); + lineDataInfo.y1 = lineDataInfo.y2 = Math.round(y1); + dataStream.createLine(lineDataInfo); + lineDataInfo.color = borderPaintInfo.getColor(); + lineDataInfo.y1 = lineDataInfo.y2 = Math.round(y1 + h3); + dataStream.createLine(lineDataInfo); + lineDataInfo.color = ColorUtil.lightenColor(borderPaintInfo.getColor(), colFactor); + lineDataInfo.y1 = lineDataInfo.y2 = Math.round(y1 + h3 + h3); + dataStream.createLine(lineDataInfo); + break; + case Constants.EN_HIDDEN: + break; + case Constants.EN_INSET: + case Constants.EN_OUTSET: + case Constants.EN_SOLID: + default: + if (borderPaintInfo.isHorizontal()) { + lineDataInfo.x2 = Math.round(x2); + lineDataInfo.y2 = lineDataInfo.y1; + } else { + lineDataInfo.x2 = lineDataInfo.x1; + lineDataInfo.y2 = Math.round(y2); + } + dataStream.createLine(lineDataInfo); + } + } + +} diff --git a/src/java/org/apache/fop/render/afp/modca/AFPConstants.java b/src/java/org/apache/fop/afp/AFPConstants.java index 73c39f2f0..3462ddfe6 100644 --- a/src/java/org/apache/fop/render/afp/modca/AFPConstants.java +++ b/src/java/org/apache/fop/afp/AFPConstants.java @@ -17,7 +17,7 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp; /** * Constants used by the AFP renderer. @@ -34,4 +34,20 @@ public interface AFPConstants { * The encoding to use to convert to ASCII */ String ASCII_ENCODING = "Cp1252"; + + /** + * The encoding to use to convert to US ASCII (7 bit) + */ + String US_ASCII_ENCODING = "US-ASCII"; + + /** + * The scaling of the default transform is set to + * approximately 72 user space coordinates per square inch + */ + int DPI_72 = 72; + + /** + * 72dpi in millipoints + */ + int DPI_72_MPTS = DPI_72 * 1000; } diff --git a/src/java/org/apache/fop/afp/AFPDataObjectFactory.java b/src/java/org/apache/fop/afp/AFPDataObjectFactory.java new file mode 100644 index 000000000..80cb40713 --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPDataObjectFactory.java @@ -0,0 +1,272 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +import java.awt.geom.Rectangle2D; + +import org.apache.fop.afp.ioca.ImageContent; +import org.apache.fop.afp.modca.AbstractDataObject; +import org.apache.fop.afp.modca.AbstractNamedAFPObject; +import org.apache.fop.afp.modca.Document; +import org.apache.fop.afp.modca.GraphicsObject; +import org.apache.fop.afp.modca.ImageObject; +import org.apache.fop.afp.modca.IncludeObject; +import org.apache.fop.afp.modca.ObjectContainer; +import org.apache.fop.afp.modca.Overlay; +import org.apache.fop.afp.modca.PageSegment; +import org.apache.fop.afp.modca.Registry; +import org.apache.fop.afp.modca.ResourceObject; +import org.apache.fop.afp.modca.triplets.MappingOptionTriplet; +import org.apache.fop.afp.modca.triplets.ObjectClassificationTriplet; +import org.apache.xmlgraphics.image.codec.tiff.TIFFImage; +import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; + +/** + * Factory for high level data objects (Image/Graphics etc) + */ +public class AFPDataObjectFactory { + + private final Factory factory; + + /** + * Main constructor + * + * @param factory an object factory + */ + public AFPDataObjectFactory(Factory factory) { + this.factory = factory; + } + + /** + * Creates and configures an ObjectContainer. + * + * @param dataObjectInfo the object container info + * @return a newly created Object Container + */ + public ObjectContainer createObjectContainer(AFPDataObjectInfo dataObjectInfo) { + ObjectContainer objectContainer = factory.createObjectContainer(); + + // set data object viewport (i.e. position, rotation, dimension, resolution) + objectContainer.setViewport(dataObjectInfo); + + // set object classification + Registry.ObjectType objectType = dataObjectInfo.getObjectType(); + AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo(); + AFPResourceLevel resourceLevel = resourceInfo.getLevel(); + final boolean dataInContainer = true; + final boolean containerHasOEG = resourceLevel.isInline(); + final boolean dataInOCD = true; + objectContainer.setObjectClassification( + ObjectClassificationTriplet.CLASS_TIME_INVARIANT_PAGINATED_PRESENTATION_OBJECT, + objectType, dataInContainer, containerHasOEG, dataInOCD); + + objectContainer.setData(dataObjectInfo.getData()); + return objectContainer; + } + + /** + * Creates and configures an IOCA Image Object. + * + * @param imageObjectInfo the image object info + * @return a newly created IOCA Image Object + */ + public ImageObject createImage(AFPImageObjectInfo imageObjectInfo) { + // IOCA bitmap image + ImageObject imageObj = factory.createImageObject(); + + // set data object viewport (i.e. position, rotation, dimension, resolution) + imageObj.setViewport(imageObjectInfo); + + if (imageObjectInfo.hasCompression()) { + int compression = imageObjectInfo.getCompression(); + switch (compression) { + case TIFFImage.COMP_FAX_G3_1D: + imageObj.setEncoding(ImageContent.COMPID_G3_MH); + break; + case TIFFImage.COMP_FAX_G3_2D: + imageObj.setEncoding(ImageContent.COMPID_G3_MR); + break; + case TIFFImage.COMP_FAX_G4_2D: + imageObj.setEncoding(ImageContent.COMPID_G3_MMR); + break; + default: + throw new IllegalStateException( + "Invalid compression scheme: " + compression); + } + } + + if (imageObjectInfo.isColor()) { + imageObj.setIDESize((byte) 24); + } else { + imageObj.setIDESize((byte) imageObjectInfo.getBitsPerPixel()); + } + + imageObj.setData(imageObjectInfo.getData()); + + return imageObj; + } + + /** + * Creates and returns a new graphics object. + * + * @param graphicsObjectInfo the graphics object info + * @return a new graphics object + */ + public GraphicsObject createGraphic(AFPGraphicsObjectInfo graphicsObjectInfo) { + // set newly created graphics object in g2d + GraphicsObject graphicsObj = factory.createGraphicsObject(); + + // set data object viewport (i.e. position, rotation, dimension, resolution) + graphicsObj.setViewport(graphicsObjectInfo); + + AFPGraphics2D g2d = graphicsObjectInfo.getGraphics2D(); + g2d.setGraphicsObject(graphicsObj); + + // paint to graphics object + Graphics2DImagePainter painter = graphicsObjectInfo.getPainter(); + Rectangle2D area = graphicsObjectInfo.getArea(); + g2d.scale(1, -1); + g2d.translate(0, -area.getHeight()); + + painter.paint(g2d, area); + + graphicsObj.setComplete(true); + + // return painted graphics object + return graphicsObj; + } + + /** + * Creates and returns a new include object. + * + * @param includeName the include name + * @param dataObjectInfo a data object info + * + * @return a new include object + */ + public IncludeObject createInclude(String includeName, AFPDataObjectInfo dataObjectInfo) { + IncludeObject includeObj = factory.createInclude(includeName); + + if (dataObjectInfo instanceof AFPImageObjectInfo) { + // IOCA image object + includeObj.setObjectType(IncludeObject.TYPE_IMAGE); + } else if (dataObjectInfo instanceof AFPGraphicsObjectInfo) { + // graphics object + includeObj.setObjectType(IncludeObject.TYPE_GRAPHIC); + } else { + // object container + includeObj.setObjectType(IncludeObject.TYPE_OTHER); + + // set mandatory object classification (type other) + Registry.ObjectType objectType = dataObjectInfo.getObjectType(); + if (objectType != null) { + // set object classification + final boolean dataInContainer = true; + final boolean containerHasOEG = false; // environment parameters set in include + final boolean dataInOCD = true; + includeObj.setObjectClassification( + // object scope not defined + ObjectClassificationTriplet.CLASS_TIME_VARIANT_PRESENTATION_OBJECT, + objectType, dataInContainer, containerHasOEG, dataInOCD); + } else { + throw new IllegalStateException( + "Failed to set Object Classification Triplet on Object Container."); + } + } + + AFPObjectAreaInfo objectAreaInfo = dataObjectInfo.getObjectAreaInfo(); + + int xOffset = objectAreaInfo.getX(); + int yOffset = objectAreaInfo.getY(); + includeObj.setObjectAreaOffset(xOffset, yOffset); + + int width = objectAreaInfo.getWidth(); + int height = objectAreaInfo.getHeight(); + includeObj.setObjectAreaSize(width, height); + + int rotation = objectAreaInfo.getRotation(); + includeObj.setObjectAreaOrientation(rotation); + + int widthRes = objectAreaInfo.getWidthRes(); + int heightRes = objectAreaInfo.getHeightRes(); + includeObj.setMeasurementUnits(widthRes, heightRes); + + includeObj.setMappingOption(MappingOptionTriplet.SCALE_TO_FIT); + + return includeObj; + } + + /** + * Creates a resource object wrapper for named includable data objects + * + * @param namedObj an named object + * @param resourceInfo resource information + * @param objectType the object type + * @return a new resource object wrapper + */ + public ResourceObject createResource(AbstractNamedAFPObject namedObj, + AFPResourceInfo resourceInfo, Registry.ObjectType objectType) { + ResourceObject resourceObj = null; + String resourceName = resourceInfo.getName(); + if (resourceName != null) { + resourceObj = factory.createResource(resourceName); + } else { + resourceObj = factory.createResource(); + } + + if (namedObj instanceof Document) { + resourceObj.setType(ResourceObject.TYPE_DOCUMENT); + } else if (namedObj instanceof PageSegment) { + resourceObj.setType(ResourceObject.TYPE_PAGE_SEGMENT); + } else if (namedObj instanceof Overlay) { + resourceObj.setType(ResourceObject.TYPE_OVERLAY_OBJECT); + } else if (namedObj instanceof AbstractDataObject) { + AbstractDataObject dataObj = (AbstractDataObject)namedObj; + if (namedObj instanceof ObjectContainer) { + resourceObj.setType(ResourceObject.TYPE_OBJECT_CONTAINER); + + // set object classification + final boolean dataInContainer = true; + final boolean containerHasOEG = false; // must be included + final boolean dataInOCD = true; + // mandatory triplet for object container + resourceObj.setObjectClassification( + ObjectClassificationTriplet.CLASS_TIME_INVARIANT_PAGINATED_PRESENTATION_OBJECT, + objectType, dataInContainer, containerHasOEG, dataInOCD); + } else if (namedObj instanceof ImageObject) { + // ioca image type + resourceObj.setType(ResourceObject.TYPE_IMAGE); + } else if (namedObj instanceof GraphicsObject) { + resourceObj.setType(ResourceObject.TYPE_GRAPHIC); + } else { + throw new UnsupportedOperationException( + "Unsupported resource object for data object type " + dataObj); + } + } else { + throw new UnsupportedOperationException( + "Unsupported resource object type " + namedObj); + } + + // set the resource information/classification on the data object + resourceObj.setDataObject(namedObj); + return resourceObj; + } + +} diff --git a/src/java/org/apache/fop/afp/AFPDataObjectInfo.java b/src/java/org/apache/fop/afp/AFPDataObjectInfo.java new file mode 100644 index 000000000..f6ff0046a --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPDataObjectInfo.java @@ -0,0 +1,247 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.afp.modca.Registry; + +/** + * A list of parameters associated with an AFP data objects + */ +public class AFPDataObjectInfo { + private static final Log log = LogFactory.getLog("org.apache.xmlgraphics.afp"); + + /** the object area info */ + private AFPObjectAreaInfo objectAreaInfo; + + /** resource info */ + private AFPResourceInfo resourceInfo; + + /** the data object width */ + private int dataWidth; + + /** the data object height */ + private int dataHeight; + + /** the object registry mimetype */ + private String mimeType; + + /** the object data in a byte array */ + private byte[] data; + + /** the object data height resolution */ + private int dataHeightRes; + + /** the object data width resolution */ + private int dataWidthRes; + + /** + * Default constructor + */ + public AFPDataObjectInfo() { + } + + /** + * Sets the image mime type + * + * @param mimeType the image mime type + */ + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + /** + * Returns the mime type of this data object + * + * @return the mime type of this data object + */ + public String getMimeType() { + return mimeType; + } + + /** + * Convenience method to return the object type + * + * @return the object type + */ + public Registry.ObjectType getObjectType() { + return Registry.getInstance().getObjectType(getMimeType()); + } + + /** + * Returns the resource level at which this data object should reside + * + * @return the resource level at which this data object should reside + */ + public AFPResourceInfo getResourceInfo() { + if (resourceInfo == null) { + this.resourceInfo = new AFPResourceInfo(); + } + return resourceInfo; + } + + /** + * Sets the resource level at which this object should reside + * + * @param resourceInfo the resource level at which this data object should reside + */ + public void setResourceInfo(AFPResourceInfo resourceInfo) { + this.resourceInfo = resourceInfo; + } + + /** + * Sets the object area info + * + * @param objectAreaInfo the object area info + */ + public void setObjectAreaInfo(AFPObjectAreaInfo objectAreaInfo) { + this.objectAreaInfo = objectAreaInfo; + } + + /** + * Returns the object area info + * + * @return the object area info + */ + public AFPObjectAreaInfo getObjectAreaInfo() { + return this.objectAreaInfo; + } + + /** + * Returns the uri of this data object + * + * @return the uri of this data object + */ + public String getUri() { + return getResourceInfo().getUri(); + } + + /** + * Sets the data object uri + * + * @param uri the data object uri + */ + public void setUri(String uri) { + getResourceInfo().setUri(uri); + } + + /** + * Returns the image data width + * + * @return the image data width + */ + public int getDataWidth() { + return dataWidth; + } + + /** + * Sets the image data width + * + * @param imageDataWidth the image data width + */ + public void setDataWidth(int imageDataWidth) { + this.dataWidth = imageDataWidth; + } + + /** + * Returns the image data height + * + * @return the image data height + */ + public int getDataHeight() { + return dataHeight; + } + + /** + * Sets the image data height + * + * @param imageDataHeight the image data height + */ + public void setDataHeight(int imageDataHeight) { + this.dataHeight = imageDataHeight; + } + + /** + * Returns the data height resolution + * + * @return the data height resolution + */ + public int getDataHeightRes() { + return this.dataHeightRes; + } + + /** + * Sets the data width resolution + * + * @param dataWidthRes the data width resolution + */ + public void setDataHeightRes(int dataHeightRes) { + this.dataHeightRes = dataHeightRes; + } + + /** + * Returns the data width resolution + * + * @return the data width resolution + */ + public int getDataWidthRes() { + return this.dataWidthRes; + } + + /** + * Sets the data width resolution + * + * @param dataWidthRes the data width resolution + */ + public void setDataWidthRes(int dataWidthRes) { + this.dataWidthRes = dataWidthRes; + } + + /** + * Sets the object data + * + * @param data the object data + */ + public void setData(byte[] data) { + this.data = data; + } + + /** + * Returns the object data + * + * @return the object data + */ + public byte[] getData() { + return this.data; + } + + /** {@inheritDoc} */ + public String toString() { + return "AFPDataObjectInfo{" + + "mimeType=" + mimeType + + ", dataWidth=" + dataWidth + + ", dataHeight=" + dataHeight + + ", dataWidthRes=" + dataWidthRes + + ", dataHeightRes=" + dataHeightRes + + (objectAreaInfo != null ? ", objectAreaInfo=" + objectAreaInfo : "") + + (resourceInfo != null ? ", resourceInfo=" + resourceInfo : ""); + } +} diff --git a/src/java/org/apache/fop/render/afp/AFPEventProducer.java b/src/java/org/apache/fop/afp/AFPEventProducer.java index 08641b20e..49792183f 100644 --- a/src/java/org/apache/fop/render/afp/AFPEventProducer.java +++ b/src/java/org/apache/fop/afp/AFPEventProducer.java @@ -17,7 +17,7 @@ /* $Id$ */ -package org.apache.fop.render.afp; +package org.apache.fop.afp; import org.apache.fop.events.EventBroadcaster; import org.apache.fop.events.EventProducer; @@ -55,9 +55,29 @@ public interface AFPEventProducer extends EventProducer { /** * Warn about using default font setup. + * * @param source the event source * @event.severity WARN */ void warnDefaultFontSetup(Object source); + /** + * Warn about a missing default "any" font configuration. + * + * @param source the event source + * @param style the font style + * @param weight the font weight + * @event.severity WARN + */ + void warnMissingDefaultFont(Object source, String style, int weight); + + /** + * A character set encoding error occurred. + * + * @param source the event source + * @param charSetName the character set name + * @param encoding the encoding + * @event.severity ERROR + */ + void characterSetEncodingError(Object source, String charSetName, String encoding); } diff --git a/src/java/org/apache/fop/afp/AFPEventProducer.xml b/src/java/org/apache/fop/afp/AFPEventProducer.xml new file mode 100644 index 000000000..8e6bb5429 --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPEventProducer.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<catalogue xml:lang="en"> + <message key="org.apache.fop.afp.AFPEventProducer.warnDefaultFontSetup">No AFP fonts configured. Using default setup.</message> + <message key="org.apache.fop.afp.AFPEventProducer.warnMissingDefaultFont">No AFP default "any", {style}, {weight} font configured.</message> + <message key="org.apache.fop.afp.AFPEventProducer.characterSetEncodingError">An error occurred when attempting to encode character set {charSetName} with encoding scheme {encoding}.</message> +</catalogue> diff --git a/src/java/org/apache/fop/afp/AFPGraphics2D.java b/src/java/org/apache/fop/afp/AFPGraphics2D.java new file mode 100644 index 000000000..ee160feca --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPGraphics2D.java @@ -0,0 +1,698 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.TexturePaint; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +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.commons.io.output.ByteArrayOutputStream; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.afp.goca.GraphicsSetLineType; +import org.apache.fop.afp.modca.GraphicsObject; +import org.apache.fop.afp.svg.AFPGraphicsConfiguration; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.svg.NativeImageHandler; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageSize; +import org.apache.xmlgraphics.image.loader.impl.ImageRendered; +import org.apache.xmlgraphics.java2d.AbstractGraphics2D; +import org.apache.xmlgraphics.java2d.GraphicContext; +import org.apache.xmlgraphics.java2d.StrokingTextHandler; +import org.apache.xmlgraphics.java2d.TextHandler; +import org.apache.xmlgraphics.ps.ImageEncodingHelper; +import org.apache.xmlgraphics.util.MimeConstants; + +/** + * 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 implements NativeImageHandler { + + private static final Log log = LogFactory.getLog(AFPGraphics2D.class); + + private static final int X = 0; + + private static final int Y = 1; + + private static final int X1 = 0; + + private static final int Y1 = 1; + + private static final int X2 = 2; + + private static final int Y2 = 3; + + private static final int X3 = 4; + + private static final int Y3 = 5; + + /** graphics object */ + private GraphicsObject graphicsObj = null; + + /** Fallback text handler */ + protected TextHandler fallbackTextHandler = new StrokingTextHandler(); + + /** Custom text handler */ + protected TextHandler customTextHandler = null; + + /** AFP resource manager */ + private AFPResourceManager resourceManager = null; + + /** AFP resource info */ + private AFPResourceInfo resourceInfo = null; + + /** Current AFP state */ + private AFPPaintingState paintingState = null; + + /** AFP graphics configuration */ + private final AFPGraphicsConfiguration graphicsConfig = new AFPGraphicsConfiguration(); + + /** The AFP FontInfo */ + private FontInfo fontInfo; + + /** + * Main constructor + * + * @param textAsShapes + * if true, all text is turned into shapes in the convertion. No + * text is output. + * @param paintingState painting state + * @param resourceManager resource manager + * @param resourceInfo resource info + * @param fontInfo font info + */ + public AFPGraphics2D(boolean textAsShapes, AFPPaintingState paintingState, + AFPResourceManager resourceManager, AFPResourceInfo resourceInfo, + FontInfo fontInfo) { + super(textAsShapes); + this.paintingState = paintingState; + this.resourceManager = resourceManager; + this.resourceInfo = resourceInfo; + this.fontInfo = fontInfo; + } + + /** + * Copy Constructor + * + * @param g2d + * a AFPGraphics2D whose properties should be copied + */ + public AFPGraphics2D(AFPGraphics2D g2d) { + super(g2d); + this.paintingState = g2d.paintingState; + this.resourceManager = g2d.resourceManager; + this.resourceInfo = g2d.resourceInfo; + this.fontInfo = g2d.fontInfo; + + this.graphicsObj = g2d.graphicsObj; + this.fallbackTextHandler = g2d.fallbackTextHandler; + this.customTextHandler = g2d.customTextHandler; + } + + /** + * Sets the AFP resource manager + * + * @param resourceManager the AFP resource manager + */ + public void setResourceManager(AFPResourceManager resourceManager) { + this.resourceManager = resourceManager; + } + + /** + * Sets the AFP resource info + * + * @param resourceInfo the AFP resource info + */ + public void setResourceInfo(AFPResourceInfo resourceInfo) { + this.resourceInfo = resourceInfo; + } + + /** + * 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; + + // set line width + float lineWidth = basicStroke.getLineWidth(); + graphicsObj.setLineWidth(Math.round(lineWidth / 2)); + + // set line type/style (note: this is an approximation at best!) + float[] dashArray = basicStroke.getDashArray(); + if (paintingState.setDashArray(dashArray)) { + byte type = GraphicsSetLineType.DEFAULT; // normally SOLID + if (dashArray != null) { + type = GraphicsSetLineType.DOTTED; // default to plain DOTTED if dashed line + // 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; + } + } + } + graphicsObj.setLineType(type); + } + } else { + log.warn("Unsupported Stroke: " + stroke.getClass().getName()); + } + } + + /** + * Apply the java paint to the AFP. + * This takes the java paint sets up the appropriate AFP commands + * for the drawing with that paint. + * Currently this supports the gradients and patterns from batik. + * + * @param paint the paint to convert to AFP + * @param fill true if the paint should be set for filling + * @return true if the paint is handled natively, false if the paint should be rasterized + */ + private boolean applyPaint(Paint paint, boolean fill) { + if (paint instanceof Color) { + return true; + } + log.debug("NYI: applyPaint() " + paint + " fill=" + fill); + if (paint instanceof TexturePaint) { +// TexturePaint texturePaint = (TexturePaint)paint; +// BufferedImage bufferedImage = texturePaint.getImage(); +// AffineTransform at = paintingState.getTransform(); +// int x = (int)Math.round(at.getTranslateX()); +// int y = (int)Math.round(at.getTranslateY()); +// drawImage(bufferedImage, x, y, null); + } + return false; + } + + + /** + * 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) { + if (!fill) { + graphicsObj.newSegment(); + } + + graphicsObj.setColor(gc.getColor()); + + applyPaint(gc.getPaint(), fill); + + if (fill) { + graphicsObj.beginArea(); + } else { + applyStroke(gc.getStroke()); + } + + AffineTransform trans = gc.getTransform(); + PathIterator iter = shape.getPathIterator(trans); + if (shape instanceof Line2D) { + double[] dstPts = new double[6]; + iter.currentSegment(dstPts); + int[] coords = new int[4]; + coords[X1] = (int) Math.round(dstPts[X]); + coords[Y1] = (int) Math.round(dstPts[Y]); + iter.next(); + iter.currentSegment(dstPts); + coords[X2] = (int) Math.round(dstPts[X]); + coords[Y2] = (int) Math.round(dstPts[Y]); + graphicsObj.addLine(coords); + } else if (shape instanceof Rectangle2D) { + double[] dstPts = new double[6]; + iter.currentSegment(dstPts); + int[] coords = new int[4]; + coords[X2] = (int) Math.round(dstPts[X]); + coords[Y2] = (int) Math.round(dstPts[Y]); + iter.next(); + iter.next(); + iter.currentSegment(dstPts); + coords[X1] = (int) Math.round(dstPts[X]); + coords[Y1] = (int) Math.round(dstPts[Y]); + graphicsObj.addBox(coords); + } else if (shape instanceof Ellipse2D) { + double[] dstPts = new double[6]; + Ellipse2D elip = (Ellipse2D) shape; + double scale = trans.getScaleX(); + double radiusWidth = elip.getWidth() / 2; + double radiusHeight = elip.getHeight() / 2; + graphicsObj.setArcParams( + (int)Math.round(radiusWidth * scale), + (int)Math.round(radiusHeight * scale), + 0, + 0 + ); + double[] srcPts = new double[] {elip.getCenterX(), elip.getCenterY()}; + trans.transform(srcPts, 0, dstPts, 0, 1); + final int mh = 1; + final int mhr = 0; + graphicsObj.addFullArc( + (int)Math.round(dstPts[X]), + (int)Math.round(dstPts[Y]), + mh, + mhr + ); + } else { + processPathIterator(iter); + } + + if (fill) { + graphicsObj.endArea(); + } + } + + /** + * Processes a path iterator generating the necessary painting operations. + * + * @param iter PathIterator to process + */ + private void processPathIterator(PathIterator iter) { + double[] dstPts = new double[6]; + for (int[] openingCoords = new int[2]; !iter.isDone(); iter.next()) { + switch (iter.currentSegment(dstPts)) { + case PathIterator.SEG_LINETO: + graphicsObj.addLine(new int[] { + (int)Math.round(dstPts[X]), + (int)Math.round(dstPts[Y]) + }, true); + break; + case PathIterator.SEG_QUADTO: + graphicsObj.addFillet(new int[] { + (int)Math.round(dstPts[X1]), + (int)Math.round(dstPts[Y1]), + (int)Math.round(dstPts[X2]), + (int)Math.round(dstPts[Y2]) + }, true); + break; + case PathIterator.SEG_CUBICTO: + graphicsObj.addFillet(new int[] { + (int)Math.round(dstPts[X1]), + (int)Math.round(dstPts[Y1]), + (int)Math.round(dstPts[X2]), + (int)Math.round(dstPts[Y2]), + (int)Math.round(dstPts[X3]), + (int)Math.round(dstPts[Y3]) + }, true); + break; + case PathIterator.SEG_MOVETO: + openingCoords = new int[] { + (int)Math.round(dstPts[X]), + (int)Math.round(dstPts[Y]) + }; + graphicsObj.setCurrentPosition(openingCoords); + break; + case PathIterator.SEG_CLOSE: + graphicsObj.addLine(openingCoords, true); + break; + default: + log.debug("Unrecognised path iterator type"); + break; + } + } + } + + /** {@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. + log.error(ioe.getMessage()); + ioe.printStackTrace(); + } + + /** {@inheritDoc} */ + public void drawString(String str, float x, float y) { + try { + if (customTextHandler != null && !textAsShapes) { + customTextHandler.drawString(this, str, x, y); + } else { + fallbackTextHandler.drawString(this, str, x, y); + } + } catch (IOException ioe) { + handleIOException(ioe); + } + } + + /** {@inheritDoc} */ + public GraphicsConfiguration getDeviceConfiguration() { + return graphicsConfig; + } + + /** {@inheritDoc} */ + public Graphics create() { + return new AFPGraphics2D(this); + } + + /** {@inheritDoc} */ + public void dispose() { + this.graphicsObj = null; + } + + /** {@inheritDoc} */ + public boolean drawImage(Image img, int x, int y, ImageObserver observer) { + return drawImage(img, x, y, img.getWidth(observer), img.getHeight(observer), observer); + } + + private BufferedImage buildBufferedImage(Dimension size) { + return new BufferedImage(size.width, size.height, + BufferedImage.TYPE_INT_ARGB); + } + + private AFPImageObjectInfo createImageObjectInfo( + RenderedImage img, int x, int y, int width, int height) throws IOException { + ImageInfo imageInfo = new ImageInfo(null, "image/unknown"); + ImageSize size = new ImageSize(img.getWidth(), img.getHeight(), 72); + imageInfo.setSize(size); + + ImageRendered imageRendered = new ImageRendered(imageInfo, img, null); + RenderedImage renderedImage = imageRendered.getRenderedImage(); + + // create image object info + AFPImageObjectInfo imageObjectInfo = new AFPImageObjectInfo(); + + imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS45); + + int bitsPerPixel = paintingState.getBitsPerPixel(); + imageObjectInfo.setBitsPerPixel(bitsPerPixel); + + imageObjectInfo.setResourceInfo(resourceInfo); + + int dataHeight = renderedImage.getHeight(); + imageObjectInfo.setDataHeight(dataHeight); + + int dataWidth = renderedImage.getWidth(); + imageObjectInfo.setDataWidth(dataWidth); + + boolean colorImages = paintingState.isColorImages(); + imageObjectInfo.setColor(colorImages); + + ByteArrayOutputStream boas = new ByteArrayOutputStream(); + ImageEncodingHelper.encodeRenderedImageAsRGB(renderedImage, boas); + byte[] imageData = boas.toByteArray(); + + // convert to grayscale + if (!colorImages) { + boas.reset(); + imageObjectInfo.setBitsPerPixel(bitsPerPixel); + ImageEncodingHelper.encodeRGBAsGrayScale( + imageData, dataWidth, dataHeight, bitsPerPixel, boas); + imageData = boas.toByteArray(); + } + imageObjectInfo.setData(imageData); + + if (imageInfo != null) { + imageObjectInfo.setUri(imageInfo.getOriginalURI()); + } + + // create object area info + AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo(); + objectAreaInfo.setX(x); + objectAreaInfo.setY(y); + objectAreaInfo.setWidth(width); + objectAreaInfo.setHeight(height); + + int resolution = paintingState.getResolution(); + objectAreaInfo.setWidthRes(resolution); + objectAreaInfo.setHeightRes(resolution); + + imageObjectInfo.setObjectAreaInfo(objectAreaInfo); + + return imageObjectInfo; + } + + /** + * Draws an AWT image into a BufferedImage using an AWT Graphics2D implementation + * + * @param img the AWT image + * @param bufferedImage the AWT buffered image + * @param width the image width + * @param height the image height + * @param observer the image observer + * @return true if the image was drawn + */ + private boolean drawBufferedImage(Image img, BufferedImage bufferedImage, + int width, int height, ImageObserver observer) { + + java.awt.Graphics2D g2d = bufferedImage.createGraphics(); + try { + g2d.setComposite(AlphaComposite.SrcOver); + + Color color = new Color(1, 1, 1, 0); + g2d.setBackground(color); + g2d.setPaint(color); + + g2d.fillRect(0, 0, width, height); + + int imageWidth = bufferedImage.getWidth(); + int imageHeight = bufferedImage.getHeight(); + Rectangle clipRect = new Rectangle(0, 0, imageWidth, imageHeight); + g2d.clip(clipRect); + + g2d.setComposite(gc.getComposite()); + + return g2d.drawImage(img, 0, 0, imageWidth, imageHeight, observer); + } finally { + g2d.dispose(); //drawn so dispose immediately to free system resource + } + } + + /** {@inheritDoc} */ + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) { + + // draw with AWT Graphics2D + Dimension imageSize = new Dimension(width, height); + BufferedImage bufferedImage = buildBufferedImage(imageSize); + + boolean drawn = drawBufferedImage(img, bufferedImage, width, height, observer); + if (drawn) { + AffineTransform at = gc.getTransform(); + float[] srcPts = new float[] {x, y}; + float[] dstPts = new float[srcPts.length]; + at.transform(srcPts, 0, dstPts, 0, 1); + x = Math.round(dstPts[X]); + y = Math.round(dstPts[Y]); + try { + // get image object info + AFPImageObjectInfo imageObjectInfo + = createImageObjectInfo(bufferedImage, x, y, width, height); + + // create image resource + resourceManager.createObject(imageObjectInfo); + return true; + } catch (IOException ioe) { + handleIOException(ioe); + } + } + return false; + } + + /** {@inheritDoc} */ + public void drawRenderedImage(RenderedImage img, AffineTransform xform) { + int imgWidth = img.getWidth(); + int imgHeight = img.getHeight(); + + AffineTransform at = paintingState.getData().getTransform(); + AffineTransform gat = gc.getTransform(); + int graphicsObjectHeight + = graphicsObj.getObjectEnvironmentGroup().getObjectAreaDescriptor().getHeight(); + int x = (int)Math.round(at.getTranslateX() + gat.getTranslateX()); + int y = (int)Math.round(at.getTranslateY() - (gat.getTranslateY() - graphicsObjectHeight)); + int width = (int)Math.round(imgWidth * gat.getScaleX()); + int height = (int)Math.round(imgHeight * -gat.getScaleY()); + try { + // get image object info + AFPImageObjectInfo imageObjectInfo + = createImageObjectInfo(img, x, y, width, height); + // create image resource + resourceManager.createObject(imageObjectInfo); + } catch (IOException ioe) { + handleIOException(ioe); + } + } + + /** + * 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; + } + + /** + * Returns the GOCA graphics object + * + * @return the GOCA graphics object + */ + public GraphicsObject getGraphicsObject() { + return this.graphicsObj; + } + + /** + * Sets the GOCA graphics object + * + * @param obj the GOCA graphics object + */ + public void setGraphicsObject(GraphicsObject obj) { + this.graphicsObj = obj; + } + + /** + * Sets the AFP painting state + * + * @param paintingState the AFP painting state + */ + public void setPaintingState(AFPPaintingState paintingState) { + this.paintingState = paintingState; + } + + /** + * Returns the AFP painting state + * + * @return the AFP painting state + */ + public AFPPaintingState getPaintingState() { + return this.paintingState; + } + + /** + * Sets the FontInfo + * + * @param the FontInfo + */ + public void setFontInfo(FontInfo fontInfo) { + this.fontInfo = fontInfo; + } + + /** + * Returns the FontInfo + * + * @return the FontInfo + */ + public FontInfo getFontInfo() { + return this.fontInfo; + } + + /** {@inheritDoc} */ + public void drawRenderableImage(RenderableImage img, AffineTransform xform) { + log.debug("drawRenderableImage() NYI: img=" + img + ", xform=" + xform); + } + + /** {@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); + } + + /** {@inheritDoc} */ + public void addNativeImage(org.apache.xmlgraphics.image.loader.Image image, + float x, float y, float width, float height) { + log.debug("NYI: addNativeImage() "+ "image=" + image + + ",x=" + x + ",y=" + y + ",width=" + width + ",height=" + height); + } + + /** {@inheritDoc} */ + public void copyArea(int x, int y, int width, int height, int dx, int dy) { + log.debug("copyArea() NYI: "); + } +} diff --git a/src/java/org/apache/fop/afp/AFPGraphicsObjectInfo.java b/src/java/org/apache/fop/afp/AFPGraphicsObjectInfo.java new file mode 100644 index 000000000..cd8c7c303 --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPGraphicsObjectInfo.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; + +import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; +import org.apache.xmlgraphics.util.MimeConstants; + +/** + * A graphics object info which contains necessary painting objects + */ +public class AFPGraphicsObjectInfo extends AFPDataObjectInfo { + + /** the graphics object painter implementation */ + private Graphics2DImagePainter painter; + + /** the graphics object area */ + private Rectangle2D area; + + /** the AFP graphics 2d implementation */ + private AFPGraphics2D g2d; + + /** + * Returns the graphics painter + * + * @return the graphics painter + */ + public Graphics2DImagePainter getPainter() { + return this.painter; + } + + /** + * Sets the graphics painter + * + * @param graphicsPainter the graphics painter + */ + public void setPainter(Graphics2DImagePainter graphicsPainter) { + this.painter = graphicsPainter; + } + + /** + * Returns the graphics area + * + * @return the graphics area + */ + public Rectangle2D getArea() { + AFPObjectAreaInfo objectAreaInfo = getObjectAreaInfo(); + int width = objectAreaInfo.getWidth(); + int height = objectAreaInfo.getHeight(); + return new Rectangle(width, height); + } + + /** + * Sets the graphics area area + * + * @param area the graphics object area + */ + public void setArea(Rectangle2D area) { + this.area = area; + } + + /** + * Sets the AFP graphics 2D implementation + * + * @param g2d the AFP graphics 2D implementation + */ + public void setGraphics2D(AFPGraphics2D g2d) { + this.g2d = g2d; + } + + /** + * Returns the AFP graphics 2D implementation + * + * @return the AFP graphics 2D implementation + */ + public AFPGraphics2D getGraphics2D() { + return this.g2d; + } + + /** {@inheritDoc} */ + public String toString() { + return "GraphicsObjectInfo{" + super.toString() + "}"; + } + + /** {@inheritDoc} */ + public String getMimeType() { + return MimeConstants.MIME_SVG; + } + +} diff --git a/src/java/org/apache/fop/afp/AFPImageObjectInfo.java b/src/java/org/apache/fop/afp/AFPImageObjectInfo.java new file mode 100644 index 000000000..f3677534f --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPImageObjectInfo.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.afp; + + +/** + * A list of parameters associated with an image + */ +public class AFPImageObjectInfo extends AFPDataObjectInfo { + + /** number of bits per pixel used */ + private int bitsPerPixel; + + /** is this a color image? */ + private boolean color; + + /** compression type if any */ + private int compression = -1; + + /** + * Default constructor + */ + public AFPImageObjectInfo() { + super(); + } + + /** + * Sets the number of bits per pixel + * + * @param bitsPerPixel the number of bits per pixel + */ + public void setBitsPerPixel(int bitsPerPixel) { + this.bitsPerPixel = bitsPerPixel; + } + + /** + * Sets if this image is color + * + * @param color true if this is a color image + */ + public void setColor(boolean color) { + this.color = color; + } + + /** + * Returns the number of bits used per pixel + * + * @return the number of bits used per pixel + */ + public int getBitsPerPixel() { + return bitsPerPixel; + } + + /** + * Returns true if this is a color image + * + * @return true if this is a color image + */ + public boolean isColor() { + return color; + } + + /** + * Returns true if this image uses compression + * + * @return true if this image uses compression + */ + public boolean hasCompression() { + return compression > -1; + } + + /** + * Returns the compression type + * + * @return the compression type + */ + public int getCompression() { + return compression; + } + + /** + * Sets the compression used with this image + * + * @param compression the type of compression used with this image + */ + public void setCompression(int compression) { + this.compression = compression; + } + + /** {@inheritDoc} */ + public String toString() { + return "AFPImageObjectInfo{" + super.toString() + + ", compression=" + compression + + ", color=" + color + + ", bitsPerPixel=" + bitsPerPixel + + "}"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/AFPLineDataInfo.java b/src/java/org/apache/fop/afp/AFPLineDataInfo.java new file mode 100644 index 000000000..f3acf4f71 --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPLineDataInfo.java @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +import java.awt.Color; + +/** Line data information */ +public class AFPLineDataInfo { + + /** the x1 coordinate */ + int x1; + + /** the y1 coordinate */ + int y1; + + /** the x2 coordinate */ + int x2; + + /** the y2 coordinate */ + int y2; + + /** the thickness */ + int thickness; + + /** the painting color */ + Color color; + + /** the rotation */ + int rotation = 0; + + /** + * Default constructor + */ + public AFPLineDataInfo() { + } + + /** + * Returns the X1 coordinate + * + * @return the X1 coordinate + */ + public int getX1() { + return x1; + } + + /** + * Sets the X1 coordinate + * + * @param x1 the X1 coordinate + */ + public void setX1(int x1) { + this.x1 = x1; + } + + /** + * Returns the Y1 coordinate + * + * @return the Y1 coordinate + */ + public int getY1() { + return y1; + } + + /** + * Sets the Y1 coordinate + * + * @param y1 the Y1 coordinate + */ + public void setY1(int y1) { + this.y1 = y1; + } + + /** + * Returns the X2 coordinate + * + * @return the X2 coordinate + */ + public int getX2() { + return x2; + } + + /** + * Sets the X2 coordinate + * + * @param x2 the X2 coordinate + */ + public void setX2(int x2) { + this.x2 = x2; + } + + /** + * Returns the Y2 coordinate + * + * @return the Y2 coordinate + */ + public int getY2() { + return y2; + } + + /** + * Sets the Y2 coordinate + * + * @param y2 the Y2 coordinate + */ + public void setY2(int y2) { + this.y2 = y2; + } + + /** + * Returns the line thickness + * + * @return the line thickness + */ + public int getThickness() { + return thickness; + } + + /** + * Sets the line thickness + * + * @param thickness the line thickness + */ + public void setThickness(int thickness) { + this.thickness = thickness; + } + + /** + * Returns line color + * + * @return the line color + */ + public Color getColor() { + return color; + } + + /** + * Sets the line color + * + * @param color the line color + */ + public void setColor(Color color) { + this.color = color; + } + + /** + * Returns line rotation + * + * @return the line rotation + */ + public int getRotation() { + return rotation; + } + + /** + * Sets the line rotation + * + * @param rotation the line rotation + */ + public void setRotation(int rotation) { + this.rotation = rotation; + } + + /** {@inheritDoc} */ + public String toString() { + return "AFPLineDataInfo{x1=" + x1 + + ", y1=" + y1 + + ", x2=" + x2 + + ", y2=" + y2 + + ", thickness=" + thickness + + ", color=" + color + + ", rotation=" + rotation + + "}"; + } + +} diff --git a/src/java/org/apache/fop/afp/AFPObjectAreaInfo.java b/src/java/org/apache/fop/afp/AFPObjectAreaInfo.java new file mode 100644 index 000000000..963424470 --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPObjectAreaInfo.java @@ -0,0 +1,172 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +/** + * A common class used to convey locations, + * dimensions and resolutions of data objects. + */ +public class AFPObjectAreaInfo { + private int x; + private int y; + private int width; + private int height; + private int widthRes; + private int heightRes; + private int rotation = 0; + + /** + * Sets the x position of the data object + * + * @param x the x position of the data object + */ + public void setX(int x) { + this.x = x; + } + + /** + * Sets the y position of the data object + * + * @param y the y position of the data object + */ + public void setY(int y) { + this.y = y; + } + + /** + * Sets the data object width + * + * @param width the width of the data object + */ + public void setWidth(int width) { + this.width = width; + } + + /** + * Sets the data object height + * + * @param height the height of the data object + */ + public void setHeight(int height) { + this.height = height; + } + + /** + * Sets the width resolution + * + * @param widthRes the width resolution + */ + public void setWidthRes(int widthRes) { + this.widthRes = widthRes; + } + + /** + * Sets the height resolution + * + * @param heightRes the height resolution + */ + public void setHeightRes(int heightRes) { + this.heightRes = heightRes; + } + + /** + * Returns the x coordinate of this data object + * + * @return the x coordinate of this data object + */ + public int getX() { + return x; + } + + /** + * Returns the y coordinate of this data object + * + * @return the y coordinate of this data object + */ + public int getY() { + return y; + } + + /** + * Returns the width of this data object + * + * @return the width of this data object + */ + public int getWidth() { + return width; + } + + /** + * Returns the height of this data object + * + * @return the height of this data object + */ + public int getHeight() { + return height; + } + + /** + * Returns the width resolution of this data object + * + * @return the width resolution of this data object + */ + public int getWidthRes() { + return widthRes; + } + + /** + * Returns the height resolution of this data object + * + * @return the height resolution of this data object + */ + public int getHeightRes() { + return heightRes; + } + + /** + * Returns the rotation of this data object + * + * @return the rotation of this data object + */ + public int getRotation() { + return rotation; + } + + /** + * Sets the data object rotation + * + * @param rotation the data object rotation + */ + public void setRotation(int rotation) { + this.rotation = rotation; + } + + /** {@inheritDoc} */ + public String toString() { + return "x=" + x + + ", y=" + y + + ", width=" + width + + ", height=" + height + + ", widthRes=" + widthRes + + ", heightRes=" + heightRes + + ", rotation=" + rotation; + } + +} diff --git a/src/java/org/apache/fop/afp/AFPPaintingState.java b/src/java/org/apache/fop/afp/AFPPaintingState.java new file mode 100644 index 000000000..95a310bcb --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPPaintingState.java @@ -0,0 +1,495 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.afp.fonts.AFPPageFonts; +import org.apache.fop.util.AbstractPaintingState; + +/** + * This keeps information about the current painting state when writing to an AFP datastream. + */ +public class AFPPaintingState extends org.apache.fop.util.AbstractPaintingState +implements Cloneable { + + private static final long serialVersionUID = 8206711712452344473L; + + private static Log log = LogFactory.getLog("org.apache.xmlgraphics.afp"); + + /** the portrait rotation */ + private int portraitRotation = 0; + + /** the landscape rotation */ + private int landscapeRotation = 270; + + /** color image support */ + private boolean colorImages = false; + + /** images are supported in this AFP environment */ + private boolean nativeImagesSupported = false; + + /** default value for image depth */ + private int bitsPerPixel = 8; + + /** the output resolution */ + private int resolution = 240; // 240 dpi + + /** the current page */ + private AFPPagePaintingState pagePaintingState = new AFPPagePaintingState(); + +// /** reference orientation */ +// private int orientation = 0; + + /** a unit converter */ + private final transient AFPUnitConverter unitConv = new AFPUnitConverter(this); + + /** + * Sets the rotation to be used for portrait pages, valid values are 0 + * (default), 90, 180, 270. + * + * @param rotation + * The rotation in degrees. + */ + public void setPortraitRotation(int rotation) { + if (rotation == 0 || rotation == 90 || rotation == 180 + || rotation == 270) { + portraitRotation = rotation; + } else { + throw new IllegalArgumentException( + "The portrait rotation must be one" + + " of the values 0, 90, 180, 270"); + + } + } + + /** + * Returns the rotation to be used for portrait pages + * + * @return the rotation to be used for portrait pages + */ + protected int getPortraitRotation() { + return this.portraitRotation; + } + + /** + * Sets the rotation to be used for landscape pages, valid values are 0, 90, + * 180, 270 (default). + * + * @param rotation + * The rotation in degrees. + */ + public void setLandscapeRotation(int rotation) { + if (rotation == 0 || rotation == 90 || rotation == 180 + || rotation == 270) { + landscapeRotation = rotation; + } else { + throw new IllegalArgumentException( + "The landscape rotation must be one" + + " of the values 0, 90, 180, 270"); + } + } + + /** + * Returns the landscape rotation + * + * @return the landscape rotation + */ + protected int getLandscapeRotation() { + return this.landscapeRotation; + } + + /** + * Sets the number of bits used per pixel + * + * @param bitsPerPixel + * number of bits per pixel + */ + public void setBitsPerPixel(int bitsPerPixel) { + switch (bitsPerPixel) { + case 1: + case 4: + case 8: + this.bitsPerPixel = bitsPerPixel; + break; + default: + log.warn("Invalid bits_per_pixel value, must be 1, 4 or 8."); + this.bitsPerPixel = 8; + break; + } + } + + /** + * Returns the number of bits per pixel + * + * @return the number of bits per pixel + */ + public int getBitsPerPixel() { + return this.bitsPerPixel; + } + + /** + * Sets whether images are color or not + * + * @param colorImages + * color image output + */ + public void setColorImages(boolean colorImages) { + this.colorImages = colorImages; + } + + /** + * Returns true if color images are to be used + * + * @return true if color images are to be used + */ + public boolean isColorImages() { + return this.colorImages; + } + + /** + * Sets whether images are natively supported or not in the AFP environment + * + * @param nativeImagesSupported true if images are natively supported in this AFP environment + */ + public void setNativeImagesSupported(boolean nativeImagesSupported) { + this.nativeImagesSupported = nativeImagesSupported; + } + + /** + * Returns true if images are supported natively in this AFP environment + * + * @return true if images are supported natively in this AFP environment + */ + public boolean isNativeImagesSupported() { + return this.nativeImagesSupported; + } + + /** + * Sets the output/device resolution + * + * @param resolution + * the output resolution (dpi) + */ + public void setResolution(int resolution) { + if (log.isDebugEnabled()) { + log.debug("renderer-resolution set to: " + resolution + "dpi"); + } + this.resolution = resolution; + } + + /** + * Returns the output/device resolution. + * + * @return the resolution in dpi + */ + public int getResolution() { + return this.resolution; + } + + /** {@inheritDoc} */ + protected AbstractData instantiateData() { + return new AFPData(); + } + + /** {@inheritDoc} */ + protected AbstractPaintingState instantiate() { + return new AFPPaintingState(); + } + + /** + * Returns the painting state of the current page + * + * @return the painting state of the current page + */ + protected AFPPagePaintingState getPagePaintingState() { + return this.pagePaintingState; + } + + /** + * Gets the current page fonts + * + * @return the current page fonts + */ + public AFPPageFonts getPageFonts() { + return pagePaintingState.getFonts(); + } + + /** + * Sets the page width + * + * @param pageWidth the page width + */ + public void setPageWidth(int pageWidth) { + pagePaintingState.setWidth(pageWidth); + } + + /** + * Returns the page width + * + * @return the page width + */ + public int getPageWidth() { + return pagePaintingState.getWidth(); + } + + /** + * Sets the page height + * + * @param pageHeight the page height + */ + public void setPageHeight(int pageHeight) { + pagePaintingState.setHeight(pageHeight); + } + + /** + * Returns the page height + * + * @return the page height + */ + public int getPageHeight() { + return pagePaintingState.getHeight(); + } + + /** + * Returns the page rotation + * + * @return the page rotation + */ + public int getPageRotation() { + return pagePaintingState.getOrientation(); + } + + /** + * Sets the uri of the current image + * + * @param uri the uri of the current image + */ + public void setImageUri(String uri) { + ((AFPData)getData()).imageUri = uri; + } + + /** + * Gets the uri of the current image + * + * @return the uri of the current image + */ + public String getImageUri() { + return ((AFPData)getData()).imageUri; + } + + /** + * Returns the currently derived rotation + * + * @return the currently derived rotation + */ + public int getRotation() { + return getData().getDerivedRotation(); + } + + /** + * Returns the unit converter + * + * @return the unit converter + */ + public AFPUnitConverter getUnitConverter() { + return this.unitConv; + } + + /** {@inheritDoc} */ + public Object clone() { + AFPPaintingState paintingState = (AFPPaintingState)super.clone(); + paintingState.pagePaintingState = (AFPPagePaintingState)this.pagePaintingState.clone(); + paintingState.portraitRotation = this.portraitRotation; + paintingState.landscapeRotation = this.landscapeRotation; + paintingState.bitsPerPixel = this.bitsPerPixel; + paintingState.colorImages = this.colorImages; + paintingState.resolution = this.resolution; + return paintingState; + } + + /** {@inheritDoc} */ + public String toString() { + return "AFPPaintingState{" + "portraitRotation=" + portraitRotation + + ", landscapeRotation=" + landscapeRotation + + ", colorImages=" + colorImages + + ", bitsPerPixel=" + bitsPerPixel + + ", resolution=" + resolution + + ", pageState=" + pagePaintingState + + super.toString() + + "}"; + } + + /** + * Page level state data + */ + private class AFPPagePaintingState implements Cloneable { + /** page width */ + private int width = 0; + + /** page height */ + private int height = 0; + + /** page fonts */ + private AFPPageFonts fonts = new AFPPageFonts(); + + /** page font count */ + private int fontCount = 0; + + /** page orientation */ + private int orientation = 0; + + /** + * Returns the page width + * + * @return the page width + */ + protected int getWidth() { + return width; + } + + /** + * Sets the page width + * + * @param width the page width + */ + protected void setWidth(int width) { + this.width = width; + } + + /** + * Returns the page height + * + * @return the page height + */ + protected int getHeight() { + return height; + } + + /** + * Sets the page height + * + * @param height the page height + */ + protected void setHeight(int height) { + this.height = height; + } + + /** + * Returns the page fonts + * + * @return the page fonts + */ + protected AFPPageFonts getFonts() { + return fonts; + } + + /** + * Sets the current page fonts + * + * @param fonts the current page fonts + */ + protected void setFonts(AFPPageFonts fonts) { + this.fonts = fonts; + } + + /** + * Increments and returns the current page font count + * + * @return increment and return the current page font count + */ + protected int incrementFontCount() { + return ++fontCount; + } + + /** + * Returns the current page orientation + * + * @return the current page orientation + */ + protected int getOrientation() { + return orientation; + } + + /** + * Sets the current page orientation + * + * @param orientation the current page orientation + */ + protected void setOrientation(int orientation) { + this.orientation = orientation; + } + + /** {@inheritDoc} */ + public Object clone() { + AFPPagePaintingState state = new AFPPagePaintingState(); + state.width = this.width; + state.height = this.height; + state.orientation = this.orientation; + state.fonts = new AFPPageFonts(this.fonts); + state.fontCount = this.fontCount; + return state; + } + + /** {@inheritDoc} */ + public String toString() { + return "AFPPagePaintingState{width=" + width + + ", height=" + height + + ", orientation=" + orientation + + ", fonts=" + fonts + + ", fontCount=" + fontCount + + "}"; + } + } + + /** + * Block level state data + */ + private class AFPData extends org.apache.fop.util.AbstractPaintingState.AbstractData { + private static final long serialVersionUID = -1789481244175275686L; + + /** The current fill status */ + private boolean filled = false; + + private String imageUri = null; + + /** {@inheritDoc} */ + public Object clone() { + AFPData obj = (AFPData)super.clone(); + obj.filled = this.filled; + obj.imageUri = this.imageUri; + return obj; + } + + /** {@inheritDoc} */ + public String toString() { + return "AFPData{" + super.toString() + + ", filled=" + filled + + ", imageUri=" + imageUri + + "}"; + } + + /** {@inheritDoc} */ + protected AbstractData instantiate() { + return new AFPData(); + } + } + +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/AFPRectanglePainter.java b/src/java/org/apache/fop/afp/AFPRectanglePainter.java new file mode 100644 index 000000000..e2bad6159 --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPRectanglePainter.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +import java.awt.geom.AffineTransform; + + +/** + * A painter of rectangles in AFP + */ +public class AFPRectanglePainter extends AbstractAFPPainter { + + /** + * Main constructor + * + * @param paintingState the AFP painting state + * @param dataStream the AFP datastream + */ + public AFPRectanglePainter(AFPPaintingState paintingState, DataStream dataStream) { + super(paintingState, dataStream); + } + + /** {@inheritDoc} */ + public void paint(PaintingInfo paintInfo) { + RectanglePaintingInfo rectanglePaintInfo = (RectanglePaintingInfo)paintInfo; + int pageWidth = dataStream.getCurrentPage().getWidth(); + int pageHeight = dataStream.getCurrentPage().getHeight(); + + AFPUnitConverter unitConv = paintingState.getUnitConverter(); + float width = unitConv.pt2units(rectanglePaintInfo.getWidth()); + float height = unitConv.pt2units(rectanglePaintInfo.getHeight()); + float x = unitConv.pt2units(rectanglePaintInfo.getX()); + float y = unitConv.pt2units(rectanglePaintInfo.getY()); + + AffineTransform at = paintingState.getData().getTransform(); + + AFPLineDataInfo lineDataInfo = new AFPLineDataInfo(); + lineDataInfo.color = paintingState.getColor(); + lineDataInfo.rotation = paintingState.getRotation(); + lineDataInfo.thickness = Math.round(height); + + switch (lineDataInfo.rotation) { + case 0: + lineDataInfo.x1 = Math.round((float)at.getTranslateX() + x); + lineDataInfo.y1 = lineDataInfo.y2 = Math.round((float)at.getTranslateY() + y); + lineDataInfo.x2 = Math.round((float)at.getTranslateX() + x + width); + break; + case 90: + lineDataInfo.x1 = Math.round((float)at.getTranslateY() + x); + lineDataInfo.y1 = lineDataInfo.y2 + = pageWidth - Math.round((float)at.getTranslateX()) + Math.round(y); + lineDataInfo.x2 = Math.round(width + (float)at.getTranslateY() + x); + break; + case 180: + lineDataInfo.x1 = pageWidth - Math.round((float)at.getTranslateX() - x); + lineDataInfo.y1 = lineDataInfo.y2 = pageHeight - Math.round((float)at.getTranslateY() - y); + lineDataInfo.x2 = pageWidth - Math.round((float)at.getTranslateX() - x - width); + break; + case 270: + lineDataInfo.x1 = pageHeight - Math.round((float)at.getTranslateY() - x); + lineDataInfo.y1 = lineDataInfo.y2 = Math.round((float)at.getTranslateX() + y); + lineDataInfo.x2 = lineDataInfo.x1 + Math.round(width - x); + break; + } + dataStream.createLine(lineDataInfo); + } +} diff --git a/src/java/org/apache/fop/afp/AFPResourceInfo.java b/src/java/org/apache/fop/afp/AFPResourceInfo.java new file mode 100644 index 000000000..729339fa4 --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPResourceInfo.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp; + + +/** + * The level at which a resource is to reside in the AFP output + */ +public class AFPResourceInfo { + private static final AFPResourceLevel DEFAULT_LEVEL + = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE); + + /** the uri of this resource */ + private String uri = null; + + /** the reference name of this resource */ + private String name = null; + + /** the resource level of this resource */ + private AFPResourceLevel level = DEFAULT_LEVEL; + + /** true when the resource level was changed */ + private boolean levelChanged = false; + + /** + * Sets the data object uri + * + * @param uri the data object uri + */ + public void setUri(String uri) { + this.uri = uri; + } + + /** + * Returns the uri of this data object + * + * @return the uri of this data object + */ + public String getUri() { + return uri; + } + + /** + * Sets the resource reference name + * + * @param resourceName the resource reference name + */ + public void setName(String resourceName) { + this.name = resourceName; + } + + /** + * Returns the resource reference name + * + * @return the resource reference name + */ + public String getName() { + return this.name; + } + + /** + * Returns the resource level + * + * @return the resource level + */ + public AFPResourceLevel getLevel() { + if (level == null) { + return DEFAULT_LEVEL; + } + return this.level; + } + + /** + * Sets the resource level + * + * @param resourceLevel the resource level + */ + public void setLevel(AFPResourceLevel resourceLevel) { + this.level = resourceLevel; + levelChanged = true; + } + + /** + * Returns true when the resource level was set + * + * @return true when the resource level was set + */ + public boolean levelChanged() { + return levelChanged; + } + + /** {@inheritDoc} */ + public String toString() { + return "AFPResourceInfo{uri=" + uri + + (name != null ? ", name=" + name : "") + + (level != null ? ", level=" + level : "") + + "}"; + + } + + /** {@inheritDoc} */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if ((obj == null) || !(obj instanceof AFPResourceInfo)) { + return false; + } + + AFPResourceInfo ri = (AFPResourceInfo)obj; + return (uri == ri.uri || uri != null && uri.equals(ri.uri)) + && (name == ri.name || name != null && name.equals(ri.name)) + && (level == ri.level || level != null && level.equals(ri.level)); + } + + /** {@inheritDoc} */ + public int hashCode() { + int hash = 7; + hash = 31 * hash + (null == uri ? 0 : uri.hashCode()); + hash = 31 * hash + (null == name ? 0 : name.hashCode()); + hash = 31 * hash + (null == level ? 0 : level.hashCode()); + return hash; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/AFPResourceLevel.java b/src/java/org/apache/fop/afp/AFPResourceLevel.java new file mode 100644 index 000000000..5e8d54aae --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPResourceLevel.java @@ -0,0 +1,201 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +/** + * A resource level + */ +public class AFPResourceLevel { + + /** directly in page **/ + public static final int INLINE = 0; + + /** page level **/ + public static final int PAGE = 1; + + /** page group level **/ + public static final int PAGE_GROUP = 2; + + /** document level **/ + public static final int DOCUMENT = 3; + + /** print file level **/ + public static final int PRINT_FILE = 4; + + /** external level **/ + public static final int EXTERNAL = 5; + + private static final String NAME_INLINE = "inline"; + private static final String NAME_PAGE = "page"; + private static final String NAME_PAGE_GROUP = "page-group"; + private static final String NAME_DOCUMENT = "document"; + private static final String NAME_PRINT_FILE = "print-file"; + private static final String NAME_EXTERNAL = "external"; + + private static final String[] NAMES = new String[] { + NAME_INLINE, NAME_PAGE, NAME_PAGE_GROUP, NAME_DOCUMENT, NAME_PRINT_FILE, NAME_EXTERNAL + }; + + + /** where the resource will reside in the AFP output */ + private int level = PRINT_FILE; // default is print-file level (images) + + /** the external resource group file path */ + private String extFilePath = null; + + /** + * Sets the resource placement level within the AFP output + * + * @param levelString the resource level (page, page-group, document, print-file or external) + * @return true if the resource level was successfully set + */ + public static AFPResourceLevel valueOf(String levelString) { + if (levelString != null) { + levelString = levelString.toLowerCase(); + AFPResourceLevel resourceLevel = null; + for (int i = 0; i < NAMES.length; i++) { + if (NAMES[i].equals(levelString)) { + resourceLevel = new AFPResourceLevel(i); + break; + } + } + return resourceLevel; + } + return null; + } + + /** + * Main constructor + * + * @param level the resource level + */ + public AFPResourceLevel(int level) { + setLevel(level); + } + + /** + * Sets the resource level + * + * @param level the resource level + */ + public void setLevel(int level) { + this.level = level; + } + + /** + * Returns true if this is at page level + * + * @return true if this is at page level + */ + public boolean isPage() { + return level == PAGE; + } + + /** + * Returns true if this is at page group level + * + * @return true if this is at page group level + */ + public boolean isPageGroup() { + return level == PAGE_GROUP; + } + + /** + * Returns true if this is at document level + * + * @return true if this is at document level + */ + public boolean isDocument() { + return level == DOCUMENT; + } + + /** + * Returns true if this is at external level + * + * @return true if this is at external level + */ + public boolean isExternal() { + return level == EXTERNAL; + } + + /** + * Returns true if this is at print-file level + * + * @return true if this is at print-file level + */ + public boolean isPrintFile() { + return level == PRINT_FILE; + } + + /** + * Returns true if this resource level is inline + * + * @return true if this resource level is inline + */ + public boolean isInline() { + return level == INLINE; + } + + /** + * Returns the destination file path of the external resource group file + * + * @return the destination file path of the external resource group file + */ + public String getExternalFilePath() { + return this.extFilePath; + } + + /** + * Sets the external destination of the resource + * + * @param filePath the external resource group file + */ + public void setExternalFilePath(String filePath) { + this.extFilePath = filePath; + } + + /** {@inheritDoc} */ + public String toString() { + return NAMES[level] + (isExternal() ? ", file=" + extFilePath : ""); + } + + /** {@inheritDoc} */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if ((obj == null) || !(obj instanceof AFPResourceLevel)) { + return false; + } + + AFPResourceLevel rl = (AFPResourceLevel)obj; + return (level == level) + && (extFilePath == rl.extFilePath + || extFilePath != null && extFilePath.equals(rl.extFilePath)); + } + + /** {@inheritDoc} */ + public int hashCode() { + int hash = 7; + hash = 31 * hash + level; + hash = 31 * hash + (null == extFilePath ? 0 : extFilePath.hashCode()); + return hash; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/AFPResourceManager.java b/src/java/org/apache/fop/afp/AFPResourceManager.java new file mode 100644 index 000000000..164ebfd2d --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPResourceManager.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.afp; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Map; + +import org.apache.fop.afp.modca.AbstractNamedAFPObject; +import org.apache.fop.afp.modca.IncludeObject; +import org.apache.fop.afp.modca.Registry; +import org.apache.fop.afp.modca.ResourceGroup; + +/** + * Manages the creation and storage of document resources + */ +public class AFPResourceManager { + /** The AFP datastream (document tree) */ + private DataStream dataStream; + + /** Resource creation factory */ + private final Factory factory; + + private final AFPStreamer streamer; + + private final AFPDataObjectFactory dataObjectFactory; + + /** Maintain a reference count of instream objects for referencing purposes */ + private int instreamObjectCount = 0; + + /** a mapping of resourceInfo --> include name */ + private final Map/*<AFPResourceInfo,String>*/ includeNameMap + = new java.util.HashMap()/*<AFPResourceInfo,String>*/; + + /** + * Main constructor + */ + public AFPResourceManager() { + this.factory = new Factory(); + this.streamer = new AFPStreamer(factory); + this.dataObjectFactory = new AFPDataObjectFactory(factory); + } + + /** + * Sets the outputstream + * + * @param paintingState the AFP painting state + * @param outputStream the outputstream + * @return a new AFP DataStream + * @throws IOException thrown if an I/O exception of some sort has occurred + */ + public DataStream createDataStream(AFPPaintingState paintingState, OutputStream outputStream) + throws IOException { + this.dataStream = streamer.createDataStream(paintingState); + streamer.setOutputStream(outputStream); + return this.dataStream; + } + + /** + * Returns the AFP DataStream + * + * @return the AFP DataStream + */ + public DataStream getDataStream() { + return this.dataStream; + } + + /** + * Tells the streamer to write + * + * @throws IOException thrown if an I/O exception of some sort has occurred. + */ + public void writeToStream() throws IOException { + streamer.close(); + } + + /** + * Sets the default resource group file path + * + * @param filePath the default resource group file path + */ + + public void setDefaultResourceGroupFilePath(String filePath) { + streamer.setDefaultResourceGroupFilePath(filePath); + } + + /** + * Creates a new data object in the AFP datastream + * + * @param dataObjectInfo the data object info + * + * @throws IOException thrown if an I/O exception of some sort has occurred. + */ + public void createObject(AFPDataObjectInfo dataObjectInfo) throws IOException { + AbstractNamedAFPObject namedObj = null; + + AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo(); + String uri = resourceInfo.getUri(); + if (uri == null) { + uri = "/"; + } + // if this is an instream data object adjust the uri to ensure that its unique + if (uri.endsWith("/")) { + uri += "#" + (++instreamObjectCount); + resourceInfo.setUri(uri); + } + + String objectName = (String)includeNameMap.get(resourceInfo); + if (objectName == null) { + boolean useInclude = true; + Registry.ObjectType objectType = null; + + // new resource so create + if (dataObjectInfo instanceof AFPImageObjectInfo) { + AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)dataObjectInfo; + namedObj = dataObjectFactory.createImage(imageObjectInfo); + } else if (dataObjectInfo instanceof AFPGraphicsObjectInfo) { + AFPGraphicsObjectInfo graphicsObjectInfo = (AFPGraphicsObjectInfo)dataObjectInfo; + namedObj = dataObjectFactory.createGraphic(graphicsObjectInfo); + } else { + // natively embedded data object + namedObj = dataObjectFactory.createObjectContainer(dataObjectInfo); + objectType = dataObjectInfo.getObjectType(); + useInclude = objectType != null && objectType.isIncludable(); + } + + AFPResourceLevel resourceLevel = resourceInfo.getLevel(); + ResourceGroup resourceGroup = streamer.getResourceGroup(resourceLevel); + useInclude &= resourceGroup != null; + if (useInclude) { + // if it is to reside within a resource group at print-file or external level + if (resourceLevel.isPrintFile() || resourceLevel.isExternal()) { + // wrap newly created data object in a resource object + namedObj = dataObjectFactory.createResource(namedObj, resourceInfo, objectType); + } + + // add data object into its resource group destination + resourceGroup.addObject(namedObj); + + // create the include object + objectName = namedObj.getName(); + IncludeObject includeObject + = dataObjectFactory.createInclude(objectName, dataObjectInfo); + + // add an include to the current page + dataStream.getCurrentPage().addObject(includeObject); + + // record mapping of resource info to data object resource name + includeNameMap.put(resourceInfo, objectName); + } else { + // not to be included so inline data object directly into the current page + dataStream.getCurrentPage().addObject(namedObj); + } + } else { + // an existing data resource so reference it by adding an include to the current page + IncludeObject includeObject + = dataObjectFactory.createInclude(objectName, dataObjectInfo); + dataStream.getCurrentPage().addObject(includeObject); + } + } + +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/AFPStreamer.java b/src/java/org/apache/fop/afp/AFPStreamer.java new file mode 100644 index 000000000..7e208bb6e --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPStreamer.java @@ -0,0 +1,215 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.util.Iterator; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.afp.modca.ResourceGroup; +import org.apache.fop.afp.modca.StreamedResourceGroup; + +/** + * Manages the streaming of the AFP output + */ +public class AFPStreamer implements Streamable { + /** Static logging instance */ + private static final Log log = LogFactory.getLog(AFPStreamer.class); + + private static final String AFPDATASTREAM_TEMP_FILE_PREFIX = "AFPDataStream_"; + + private static final int BUFFER_SIZE = 4096; // 4k writing buffer + + private static final String DEFAULT_EXTERNAL_RESOURCE_FILENAME = "resources.afp"; + + + private final Factory factory; + + /** A mapping of external resource destinations to resource groups */ + private final Map/*<String,AFPExternalResourceGroup>*/pathResourceGroupMap + = new java.util.HashMap/*<String,AFPExternalResourceGroup>*/(); + + private StreamedResourceGroup printFileResourceGroup; + + /** Sets the default resource group file path */ + private String defaultResourceGroupFilePath = DEFAULT_EXTERNAL_RESOURCE_FILENAME; + + private File tempFile; + + /** temporary document outputstream */ + private OutputStream documentOutputStream; + + /** the final outputstream */ + private OutputStream outputStream; + + private RandomAccessFile documentFile; + + private DataStream dataStream; + + /** + * Main constructor + * + * @param factory a factory + */ + public AFPStreamer(Factory factory) { + this.factory = factory; + } + + /** + * Creates a new DataStream + * + * @param paintingState the AFP painting state + * @return a new {@link DataStream} + * @throws IOException thrown if an I/O exception of some sort has occurred + */ + public DataStream createDataStream(AFPPaintingState paintingState) throws IOException { + this.tempFile = File.createTempFile(AFPDATASTREAM_TEMP_FILE_PREFIX, null); + this.documentFile = new RandomAccessFile(tempFile, "rw"); + this.documentOutputStream = new BufferedOutputStream( + new FileOutputStream(documentFile.getFD())); + this.dataStream = factory.createDataStream(paintingState, documentOutputStream); + return dataStream; + } + + /** + * Sets the default resource group file path + * + * @param filePath the default resource group file path + */ + public void setDefaultResourceGroupFilePath(String filePath) { + this.defaultResourceGroupFilePath = filePath; + } + + /** + * Returns the resource group for a given resource info + * + * @param level a resource level + * @return a resource group for the given resource info + */ + public ResourceGroup getResourceGroup(AFPResourceLevel level) { + ResourceGroup resourceGroup = null; + if (level.isInline()) { // no resource group for inline level + return null; + } + if (level.isExternal()) { + String filePath = level.getExternalFilePath(); + if (filePath == null) { + log.warn("No file path provided for external resource, using default."); + filePath = defaultResourceGroupFilePath; + } + resourceGroup = (ResourceGroup)pathResourceGroupMap.get(filePath); + if (resourceGroup == null) { + OutputStream os = null; + try { + os = new BufferedOutputStream(new FileOutputStream(filePath)); + } catch (FileNotFoundException fnfe) { + log.error("Failed to create/open external resource group file '" + + filePath + "'"); + } finally { + if (os != null) { + resourceGroup = factory.createStreamedResourceGroup(os); + pathResourceGroupMap.put(filePath, resourceGroup); + } + } + } + } else if (level.isPrintFile()) { + if (printFileResourceGroup == null) { + // use final outputstream for print-file resource group + printFileResourceGroup = factory.createStreamedResourceGroup(outputStream); + } + resourceGroup = printFileResourceGroup; + } else { + // resource group in afp document datastream + resourceGroup = dataStream.getResourceGroup(level); + } + return resourceGroup; + } + + /** + * Closes off the AFP stream writing the document stream + * + * @throws IOException if an an I/O exception of some sort has occurred + */ + // write out any external resource groups + public void close() throws IOException { + Iterator it = pathResourceGroupMap.entrySet().iterator(); + while (it.hasNext()) { + StreamedResourceGroup resourceGroup = (StreamedResourceGroup)it.next(); + resourceGroup.close(); + } + + // close any open print-file resource group + if (printFileResourceGroup != null) { + printFileResourceGroup.close(); + } + + // write out document + writeToStream(outputStream); + + outputStream.close(); + + // delete temporary file + tempFile.delete(); + } + + /** + * Sets the final outputstream + * + * @param outputStream an outputstream + */ + public void setOutputStream(OutputStream outputStream) { + this.outputStream = outputStream; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { +// long start = System.currentTimeMillis(); + int len = (int)documentFile.length(); + int numChunks = len / BUFFER_SIZE; + int remainingChunkSize = len % BUFFER_SIZE; + byte[] buffer; + + documentFile.seek(0); + if (numChunks > 0) { + buffer = new byte[BUFFER_SIZE]; + for (int i = 0; i < numChunks; i++) { + documentFile.read(buffer, 0, BUFFER_SIZE); + os.write(buffer, 0, BUFFER_SIZE); + } + } else { + buffer = new byte[remainingChunkSize]; + } + if (remainingChunkSize > 0) { + documentFile.read(buffer, 0, remainingChunkSize); + os.write(buffer, 0, remainingChunkSize); + } + os.flush(); +// long end = System.currentTimeMillis(); +// log.debug("writing time " + (end - start) + "ms"); + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/AFPTextDataInfo.java b/src/java/org/apache/fop/afp/AFPTextDataInfo.java new file mode 100644 index 000000000..8047c927c --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPTextDataInfo.java @@ -0,0 +1,232 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +import java.awt.Color; + +/** + * Text data information + */ +public class AFPTextDataInfo { + + /** the text font reference */ + private int fontReference; + + /** the text x coordinate position */ + private int x; + + /** the text y coordinate position */ + private int y; + + /** the text color */ + private Color color; + + /** the text variable space adjustment */ + private int variableSpaceCharacterIncrement; + + /** the text inter character adjustment */ + private int interCharacterAdjustment; + + /** the text orientation */ + private int rotation; + + /** the text encoding */ + private String textEncoding; + + /** the text string */ + private String textString; + + /** + * Returns the font reference + * + * @return the font reference + */ + public int getFontReference() { + return fontReference; + } + + /** + * Sets the font reference + * + * @param fontReference the font reference + */ + public void setFontReference(int fontReference) { + this.fontReference = fontReference; + } + + /** + * Returns the x coordinate + * + * @return the x coordinate + */ + public int getX() { + return x; + } + + /** + * Sets the X coordinate + * + * @param x the X coordinate + */ + public void setX(int x) { + this.x = x; + } + + /** + * Returns the y coordinate + * + * @return the y coordinate + */ + public int getY() { + return y; + } + + /** + * Sets the Y coordinate + * + * @param y the Y coordinate + */ + public void setY(int y) { + this.y = y; + } + + /** + * Returns the color + * + * @return the color + */ + public Color getColor() { + return color; + } + + /** + * Sets the color + * + * @param color the color + */ + public void setColor(Color color) { + this.color = color; + } + + /** + * Return the variable space character increment + * + * @return the variable space character increment + */ + public int getVariableSpaceCharacterIncrement() { + return variableSpaceCharacterIncrement; + } + + /** + * Sets the variable space character increment + * + * @param variableSpaceCharacterIncrement the variable space character increment + */ + public void setVariableSpaceCharacterIncrement( + int variableSpaceCharacterIncrement) { + this.variableSpaceCharacterIncrement = variableSpaceCharacterIncrement; + } + + /** + * Return the inter character adjustment + * + * @return the inter character adjustment + */ + public int getInterCharacterAdjustment() { + return interCharacterAdjustment; + } + + /** + * Sets the inter character adjustment + * + * @param interCharacterAdjustment the inter character adjustment + */ + public void setInterCharacterAdjustment(int interCharacterAdjustment) { + this.interCharacterAdjustment = interCharacterAdjustment; + } + + /** + * Sets the text orientation + * + * @param rotation the text rotation + */ + public void setRotation(int rotation) { + this.rotation = rotation; + } + + /** + * Returns the text rotation + * + * @return the text rotation + */ + public int getRotation() { + return this.rotation; + } + + /** + * Sets the text encoding + * + * @param textEncoding the text encoding + */ + public void setEncoding(String textEncoding) { + this.textEncoding = textEncoding; + } + + /** + * Returns the text encoding + * + * @return the text encoding + */ + public String getEncoding() { + return this.textEncoding; + } + + /** + * Sets the text string + * + * @param textString the text string + */ + public void setString(String textString) { + this.textString = textString; + } + + /** + * Returns the text string + * + * @return the text string + */ + public String getString() { + return this.textString; + } + + /** {@inheritDoc} */ + public String toString() { + return "TextDataInfo{fontReference=" + fontReference + + ", x=" + x + + ", y=" + y + + ", color=" + color + + ", vsci=" + variableSpaceCharacterIncrement + + ", ica=" + interCharacterAdjustment + + ", orientation=" + rotation + + ", textString=" + textString + + ", textEncoding=" + textEncoding + + "}"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/AFPUnitConverter.java b/src/java/org/apache/fop/afp/AFPUnitConverter.java new file mode 100644 index 000000000..3195ba70f --- /dev/null +++ b/src/java/org/apache/fop/afp/AFPUnitConverter.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +import java.awt.geom.AffineTransform; + + + +/** + * AFP Unit converter + */ +public class AFPUnitConverter { + + /** the AFP state */ + private final AFPPaintingState paintingState; + + /** + * Unit converter + * + * @param paintingState the AFP painting state + */ + public AFPUnitConverter(AFPPaintingState paintingState) { + this.paintingState = paintingState; + } + + /** + * Converts millipoints to units + * + * @param srcPts source points + * @param dstPts destination points + * @return transformed points + */ + public int[] mpts2units(float[] srcPts, float[] dstPts) { + return transformPoints(srcPts, dstPts, true); + } + + /** + * Converts points to units + * + * @param srcPts source points + * @param dstPts destination points + * @return transformed points + */ + public int[] pts2units(float[] srcPts, float[] dstPts) { + return transformPoints(srcPts, dstPts, false); + } + + /** + * Converts millipoints to units + * + * @param srcPts source points + * @return transformed points + */ + public int[] mpts2units(float[] srcPts) { + return transformPoints(srcPts, null, true); + } + + /** + * Converts points to units + * + * @param srcPts source points + * @return transformed points + */ + public int[] pts2units(float[] srcPts) { + return transformPoints(srcPts, null, false); + } + + /** + * Converts point to unit + * + * @param pt point + * @return transformed point + */ + public float pt2units(float pt) { + return pt / ((float)AFPConstants.DPI_72 / paintingState.getResolution()); + } + + /** + * Converts millipoint to unit + * + * @param mpt millipoint + * @return transformed point + */ + public float mpt2units(float mpt) { + return mpt / ((float)AFPConstants.DPI_72_MPTS / paintingState.getResolution()); + } + + private int[] transformPoints(float[] srcPts, float[] dstPts, boolean milli) { + if (dstPts == null) { + dstPts = new float[srcPts.length]; + } + AffineTransform at = paintingState.getData().getTransform(); + at.transform(srcPts, 0, dstPts, 0, srcPts.length / 2); + int[] coords = new int[srcPts.length]; + for (int i = 0; i < srcPts.length; i++) { + if (!milli) { + dstPts[i] *= 1000; + } + coords[i] = Math.round(dstPts[i]); + } + return coords; + } + +} diff --git a/src/java/org/apache/fop/afp/AbstractAFPPainter.java b/src/java/org/apache/fop/afp/AbstractAFPPainter.java new file mode 100644 index 000000000..576b8bb11 --- /dev/null +++ b/src/java/org/apache/fop/afp/AbstractAFPPainter.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.afp; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * A base AFP painter + */ +public abstract class AbstractAFPPainter { + + /** Static logging instance */ + protected static Log log = LogFactory.getLog("org.apache.xmlgraphics.afp"); + + protected final DataStream dataStream; + protected final AFPPaintingState paintingState; + + /** + * Main constructor + * + * @param paintingState the AFP painting state + * @param dataStream the AFP Datastream + */ + public AbstractAFPPainter(AFPPaintingState paintingState, DataStream dataStream) { + this.paintingState = paintingState; + this.dataStream = dataStream; + } + + /** + * Paints the painting item + * + * @param paintInfo the painting information + */ + public abstract void paint(PaintingInfo paintInfo); +} diff --git a/src/java/org/apache/fop/afp/BorderPaintingInfo.java b/src/java/org/apache/fop/afp/BorderPaintingInfo.java new file mode 100644 index 000000000..4917c7bc0 --- /dev/null +++ b/src/java/org/apache/fop/afp/BorderPaintingInfo.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +import java.awt.Color; + +/** + * Border painting information + */ +public class BorderPaintingInfo implements PaintingInfo { + + private final float x1; + private final float y1; + private final float x2; + private final float y2; + private final boolean isHorizontal; + private final int style; + private final Color color; + + /** + * Main constructor + * + * @param x1 the x1 coordinate + * @param y1 the y1 coordinate + * @param x2 the x2 coordinate + * @param y2 the y2 coordinate + * @param isHorizontal true when the border line is horizontal + * @param style the border style + * @param color the border color + */ + public BorderPaintingInfo(float x1, float y1, float x2, float y2, + boolean isHorizontal, int style, Color color) { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + this.isHorizontal = isHorizontal; + this.style = style; + this.color = color; + } + + /** + * Returns the x1 coordinate + * + * @return the x1 coordinate + */ + public float getX1() { + return x1; + } + + /** + * Returns the y1 coordinate + * + * @return the y1 coordinate + */ + public float getY1() { + return y1; + } + + /** + * Returns the x2 coordinate + * + * @return the x2 coordinate + */ + public float getX2() { + return x2; + } + + /** + * Returns the y2 coordinate + * + * @return the y2 coordinate + */ + public float getY2() { + return y2; + } + + /** + * Returns true when this is a horizontal line + * + * @return true when this is a horizontal line + */ + public boolean isHorizontal() { + return isHorizontal; + } + + /** + * Returns the style + * + * @return the style + */ + public int getStyle() { + return style; + } + + /** + * Returns the color + * + * @return the color + */ + public Color getColor() { + return color; + } +} diff --git a/src/java/org/apache/fop/afp/Completable.java b/src/java/org/apache/fop/afp/Completable.java new file mode 100644 index 000000000..e1fc764dd --- /dev/null +++ b/src/java/org/apache/fop/afp/Completable.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +/** + * Set and expose the internal completeness of an object. + */ +public interface Completable { + + /** + * Sets whether or not this object is complete or not + * + * @param complete true if this object is complete + */ + void setComplete(boolean complete); + + /** + * Returns true if this object is complete + * + * @return true if this object is complete + */ + boolean isComplete(); +} diff --git a/src/java/org/apache/fop/afp/DataStream.java b/src/java/org/apache/fop/afp/DataStream.java new file mode 100644 index 000000000..783c698ea --- /dev/null +++ b/src/java/org/apache/fop/afp/DataStream.java @@ -0,0 +1,602 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +import java.awt.Color; +import java.awt.Point; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.Iterator; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.afp.fonts.AFPFont; +import org.apache.fop.afp.fonts.AFPFontAttributes; +import org.apache.fop.afp.modca.AbstractPageObject; +import org.apache.fop.afp.modca.Document; +import org.apache.fop.afp.modca.InterchangeSet; +import org.apache.fop.afp.modca.Overlay; +import org.apache.fop.afp.modca.PageGroup; +import org.apache.fop.afp.modca.PageObject; +import org.apache.fop.afp.modca.ResourceGroup; +import org.apache.fop.afp.modca.TagLogicalElementBean; +import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet; + +/** + * A data stream is a continuous ordered stream of data elements and objects + * conforming to a given format. Application programs can generate data streams + * destined for a presentation service, archive library, presentation device or + * another application program. The strategic presentation data stream + * architectures used is Mixed Object Document Content Architecture (MO:DCA). + * + * The MO:DCA architecture defines the data stream used by applications to + * describe documents and object envelopes for interchange with other + * applications and application services. Documents defined in the MO:DCA format + * may be archived in a database, then later retrieved, viewed, annotated and + * printed in local or distributed systems environments. Presentation fidelity + * is accommodated by including resource objects in the documents that reference + * them. + */ +public class DataStream { + + /** Static logging instance */ + protected static final Log log = LogFactory.getLog("org.apache.xmlgraphics.afp"); + + /** Boolean completion indicator */ + private boolean complete = false; + + /** The AFP document object */ + private Document document = null; + + /** The current page group object */ + private PageGroup currentPageGroup = null; + + /** The current page object */ + private PageObject currentPageObject = null; + + /** The current overlay object */ + private Overlay currentOverlay = null; + + /** The current page */ + private AbstractPageObject currentPage = null; + + /** The MO:DCA interchange set in use (default to MO:DCA-P IS/2 set) */ + private InterchangeSet interchangeSet + = InterchangeSet.valueOf(InterchangeSet.MODCA_PRESENTATION_INTERCHANGE_SET_2); + + private final Factory factory; + + private OutputStream outputStream; + + /** the afp painting state */ + private final AFPPaintingState paintingState; + + /** + * Default constructor for the AFPDocumentStream. + * + * @param factory the resource factory + * @param paintingState the AFP painting state + * @param outputStream the outputstream to write to + */ + public DataStream(Factory factory, AFPPaintingState paintingState, OutputStream outputStream) { + this.paintingState = paintingState; + this.factory = factory; + this.outputStream = outputStream; + } + + /** + * Returns the outputstream + * + * @return the outputstream + */ + public OutputStream getOutputStream() { + return this.outputStream; + } + + /** + * Returns the document object + * + * @return the document object + */ + private Document getDocument() { + return this.document; + } + + /** + * Returns the current page + * + * @return the current page + */ + public AbstractPageObject getCurrentPage() { + return this.currentPage; + } + + /** + * The document is started by invoking this method which creates an instance + * of the AFP Document object. + * + * @param name + * the name of this document. + */ + public void setDocumentName(String name) { + if (name != null) { + getDocument().setFullyQualifiedName( + FullyQualifiedNameTriplet.TYPE_BEGIN_DOCUMENT_REF, + FullyQualifiedNameTriplet.FORMAT_CHARSTR, name); + } + } + + /** + * Helper method to mark the end of the current document. + * + * @throws IOException thrown if 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); + throw new IllegalStateException(msg); + } + + if (currentPageObject != null) { + // End the current page if necessary + endPage(); + } + + if (currentPageGroup != null) { + // End the current page group if necessary + endPageGroup(); + } + + // Write out document + if (document != null) { + document.endDocument(); + document.writeToStream(this.outputStream); + } + + this.outputStream.flush(); + + this.complete = true; + + this.document = null; + + this.outputStream = null; + } + + /** + * Start a new page. When processing has finished on the current page, the + * {@link #endPage()}method must be invoked to mark the page ending. + * + * @param pageWidth + * the width of the page + * @param pageHeight + * the height of the page + * @param pageRotation + * the rotation of the page + * @param pageWidthRes + * the width resolution of the page + * @param pageHeightRes + * the height resolution of the page + */ + public void startPage(int pageWidth, int pageHeight, int pageRotation, + int pageWidthRes, int pageHeightRes) { + currentPageObject = factory.createPage(pageWidth, pageHeight, + pageRotation, pageWidthRes, pageHeightRes); + currentPage = currentPageObject; + currentOverlay = null; + } + + /** + * Start a new overlay. When processing has finished on the current overlay, + * the {@link #endOverlay()}method must be invoked to mark the overlay + * ending. + * + * @param x + * the x position of the overlay on the page + * @param y + * the y position of the overlay on the page + * @param width + * the width of the overlay + * @param height + * the height of the overlay + * @param widthRes + * the width resolution of the overlay + * @param heightRes + * the height resolution of the overlay + * @param overlayRotation + * the rotation of the overlay + */ + public void startOverlay(int x, int y, int width, int height, int widthRes, + int heightRes, int overlayRotation) { + this.currentOverlay = factory.createOverlay( + width, height, widthRes, heightRes, overlayRotation); + + String overlayName = currentOverlay.getName(); + currentPageObject.createIncludePageOverlay(overlayName, x, y, 0); + currentPage = currentOverlay; + } + + /** + * Helper method to mark the end of the current overlay. + * + * @throws IOException thrown if an I/O exception of some sort has occurred + */ + public void endOverlay() throws IOException { + if (currentOverlay != null) { + currentOverlay.endPage(); + currentOverlay = null; + currentPage = currentPageObject; + } + } + + /** + * Helper method to save the current page. + * + * @return current page object that was saved + */ + public PageObject savePage() { + PageObject pageObject = currentPageObject; + if (currentPageGroup != null) { + currentPageGroup.addPage(currentPageObject); + } else { + document.addPage(currentPageObject); + } + currentPageObject = null; + currentPage = null; + return pageObject; + } + + /** + * Helper method to restore the current page. + * + * @param pageObject + * page object + */ + public void restorePage(PageObject pageObject) { + currentPageObject = pageObject; + currentPage = pageObject; + } + + /** + * Helper method to mark the end of the current page. + * + * @throws IOException thrown if an I/O exception of some sort has occurred + */ + public void endPage() throws IOException { + if (currentPageObject != null) { + currentPageObject.endPage(); + if (currentPageGroup != null) { + currentPageGroup.addPage(currentPageObject); + currentPageGroup.writeToStream(this.outputStream); + } else { + document.addPage(currentPageObject); + document.writeToStream(this.outputStream); + } + currentPageObject = null; + currentPage = null; + } + } + + /** + * 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. + * + * @param fontReference + * the font number used as the resource identifier + * @param font + * the font + * @param size + * the point size of the font + */ + public void createFont(int fontReference, AFPFont font, int size) { + currentPage.createFont(fontReference, font, size); + } + + /** + * Returns a point on the current page + * + * @param x the X-coordinate + * @param y the Y-coordinate + * @return a point on the current page + */ + private Point getPoint(int x, int y) { + Point p = new Point(); + int rotation = paintingState.getRotation(); + switch (rotation) { + case 90: + p.x = y; + p.y = currentPage.getWidth() - x; + break; + case 180: + p.x = currentPage.getWidth() - x; + p.y = currentPage.getHeight() - y; + break; + case 270: + p.x = currentPage.getHeight() - y; + p.y = x; + break; + default: + p.x = x; + p.y = y; + break; + } + return p; + } + + /** + * 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 textDataInfo + * the afp text data + * @throws UnsupportedEncodingException thrown if character encoding is not supported + */ + public void createText(AFPTextDataInfo textDataInfo) throws UnsupportedEncodingException { + int rotation = paintingState.getRotation(); + if (rotation != 0) { + textDataInfo.setRotation(rotation); + Point p = getPoint(textDataInfo.getX(), textDataInfo.getY()); + textDataInfo.setX(p.x); + textDataInfo.setY(p.y); + } + currentPage.createText(textDataInfo); + } + + /** + * Method to create a line on the current page. + * + * @param lineDataInfo the line data information. + */ + public void createLine(AFPLineDataInfo lineDataInfo) { + currentPage.createLine(lineDataInfo); + } + + /** + * This method will create shading on the page using the specified + * coordinates (the shading contrast is controlled via the red, green, blue + * parameters, by converting this to grey scale). + * + * @param x + * the x coordinate of the shading + * @param y + * the y coordinate of the shading + * @param w + * the width of the shaded area + * @param h + * the height of the shaded area + * @param col + * the shading color + */ + public void createShading(int x, int y, int w, int h, Color col) { + currentPageObject.createShading(x, y, w, h, col.getRed(), col.getGreen(), col.getBlue()); + } + + /** + * Helper method which allows creation of the MPO object, via the AEG. And + * the IPO via the Page. (See actual object for descriptions.) + * + * @param name + * the name of the static overlay + */ + public void createIncludePageOverlay(String name) { + currentPageObject.createIncludePageOverlay(name, 0, 0, paintingState.getRotation()); + currentPageObject.getActiveEnvironmentGroup().createOverlay(name); + } + + /** + * Helper method which allows creation of the IMM object. + * + * @param name + * the name of the medium map + */ + public void createInvokeMediumMap(String name) { + currentPageGroup.createInvokeMediumMap(name); + } + + /** + * Creates an IncludePageSegment on the current page. + * + * @param name + * the name of the include page segment + * @param x + * the x coordinate for the overlay + * @param y + * the y coordinate for the overlay + */ + public void createIncludePageSegment(String name, int x, int y) { + int xOrigin; + int yOrigin; + int orientation = paintingState.getRotation(); + switch (orientation) { + case 90: + xOrigin = currentPage.getWidth() - y; + yOrigin = x; + break; + case 180: + xOrigin = currentPage.getWidth() - x; + yOrigin = currentPage.getHeight() - y; + break; + case 270: + xOrigin = y; + yOrigin = currentPage.getHeight() - x; + break; + default: + xOrigin = x; + yOrigin = y; + break; + } + currentPage.createIncludePageSegment(name, xOrigin, yOrigin); + } + + /** + * Creates a TagLogicalElement on the current page. + * + * @param attributes + * the array of key value pairs. + */ + public void createPageTagLogicalElement(TagLogicalElementBean[] attributes) { + for (int i = 0; i < attributes.length; i++) { + String name = attributes[i].getKey(); + String value = attributes[i].getValue(); + currentPage.createTagLogicalElement(name, value); + } + } + + /** + * Creates a TagLogicalElement on the current page group. + * + * @param attributes + * the array of key value pairs. + */ + public void createPageGroupTagLogicalElement(TagLogicalElementBean[] attributes) { + for (int i = 0; i < attributes.length; i++) { + String name = attributes[i].getKey(); + String value = attributes[i].getValue(); + currentPageGroup.createTagLogicalElement(name, value); + } + } + + /** + * Creates a TagLogicalElement on the current page or page group + * + * @param name + * The tag name + * @param value + * The tag value + */ + public void createTagLogicalElement(String name, String value) { + if (currentPageGroup != null) { + currentPageGroup.createTagLogicalElement(name, value); + } else { + currentPage.createTagLogicalElement(name, value); + } + } + + /** + * Creates a NoOperation item + * + * @param content + * byte data + */ + public void createNoOperation(String content) { + currentPage.createNoOperation(content); + } + + /** + * Returns the current page group + * + * @return the current page group + */ + public PageGroup getCurrentPageGroup() { + return this.currentPageGroup; + } + + /** + * Start a new document. + * + * @throws IOException thrown if an I/O exception of some sort has occurred + */ + public void startDocument() throws IOException { + this.document = factory.createDocument(); + document.writeToStream(this.outputStream); + } + + /** + * Start a new page group. When processing has finished on the current page + * group the {@link #endPageGroup()}method must be invoked to mark the page + * group ending. + * + * @throws IOException thrown if an I/O exception of some sort has occurred + */ + public void startPageGroup() throws IOException { + endPageGroup(); + this.currentPageGroup = factory.createPageGroup(); + } + + /** + * Helper method to mark the end of the page group. + * + * @throws IOException thrown if an I/O exception of some sort has occurred + */ + public void endPageGroup() throws IOException { + if (currentPageGroup != null) { + currentPageGroup.endPageGroup(); + document.addPageGroup(currentPageGroup); + document.writeToStream(outputStream); + currentPageGroup = null; + } + } + + /** + * Sets the MO:DCA interchange set to use + * + * @param interchangeSet the MO:DCA interchange set + */ + public void setInterchangeSet(InterchangeSet interchangeSet) { + this.interchangeSet = interchangeSet; + } + + /** + * Returns the MO:DCA interchange set in use + * + * @return the MO:DCA interchange set in use + */ + public InterchangeSet getInterchangeSet() { + return this.interchangeSet; + } + + /** + * Returns the resource group for a given resource info + * + * @param level a resource level + * @return a resource group for the given resource info + */ + public ResourceGroup getResourceGroup(AFPResourceLevel level) { + ResourceGroup resourceGroup = null; + if (level.isDocument()) { + resourceGroup = document.getResourceGroup(); + } else if (level.isPageGroup()) { + resourceGroup = currentPageGroup.getResourceGroup(); + } else if (level.isPage()) { + resourceGroup = currentPageObject.getResourceGroup(); + } + return resourceGroup; + } + +} diff --git a/src/java/org/apache/fop/afp/Factory.java b/src/java/org/apache/fop/afp/Factory.java new file mode 100644 index 000000000..a278a5761 --- /dev/null +++ b/src/java/org/apache/fop/afp/Factory.java @@ -0,0 +1,635 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +import java.io.OutputStream; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.afp.goca.GraphicsData; +import org.apache.fop.afp.ioca.ImageContent; +import org.apache.fop.afp.ioca.ImageRasterData; +import org.apache.fop.afp.ioca.ImageSegment; +import org.apache.fop.afp.ioca.ImageSizeParameter; +import org.apache.fop.afp.modca.ActiveEnvironmentGroup; +import org.apache.fop.afp.modca.ContainerDataDescriptor; +import org.apache.fop.afp.modca.Document; +import org.apache.fop.afp.modca.GraphicsDataDescriptor; +import org.apache.fop.afp.modca.GraphicsObject; +import org.apache.fop.afp.modca.IMImageObject; +import org.apache.fop.afp.modca.ImageDataDescriptor; +import org.apache.fop.afp.modca.ImageObject; +import org.apache.fop.afp.modca.IncludeObject; +import org.apache.fop.afp.modca.IncludePageSegment; +import org.apache.fop.afp.modca.InvokeMediumMap; +import org.apache.fop.afp.modca.MapCodedFont; +import org.apache.fop.afp.modca.MapContainerData; +import org.apache.fop.afp.modca.MapDataResource; +import org.apache.fop.afp.modca.ObjectAreaDescriptor; +import org.apache.fop.afp.modca.ObjectAreaPosition; +import org.apache.fop.afp.modca.ObjectContainer; +import org.apache.fop.afp.modca.ObjectEnvironmentGroup; +import org.apache.fop.afp.modca.Overlay; +import org.apache.fop.afp.modca.PageDescriptor; +import org.apache.fop.afp.modca.PageGroup; +import org.apache.fop.afp.modca.PageObject; +import org.apache.fop.afp.modca.PresentationEnvironmentControl; +import org.apache.fop.afp.modca.PresentationTextDescriptor; +import org.apache.fop.afp.modca.PresentationTextObject; +import org.apache.fop.afp.modca.ResourceEnvironmentGroup; +import org.apache.fop.afp.modca.ResourceGroup; +import org.apache.fop.afp.modca.ResourceObject; +import org.apache.fop.afp.modca.StreamedResourceGroup; +import org.apache.fop.afp.modca.TagLogicalElement; +import org.apache.fop.afp.util.StringUtils; + +/** + * Creator of MO:DCA structured field objects + */ +public class Factory { + + /** Static logging instance */ + private static final Log log = LogFactory.getLog(Factory.class); + + private static final String OBJECT_ENVIRONMENT_GROUP_NAME_PREFIX = "OEG"; + + private static final String ACTIVE_ENVIRONMENT_GROUP_NAME_PREFIX = "AEG"; + + private static final String IMAGE_NAME_PREFIX = "IMG"; + + private static final String GRAPHIC_NAME_PREFIX = "GRA"; + + private static final String BARCODE_NAME_PREFIX = "BAR"; + +// private static final String OTHER_NAME_PREFIX = "OTH"; + + private static final String OBJECT_CONTAINER_NAME_PREFIX = "OC"; + + private static final String RESOURCE_NAME_PREFIX = "RES"; + + private static final String RESOURCE_GROUP_NAME_PREFIX = "RG"; + + private static final String PAGE_GROUP_NAME_PREFIX = "PGP"; + + private static final String PAGE_NAME_PREFIX = "PGN"; + + private static final String OVERLAY_NAME_PREFIX = "OVL"; + + private static final String PRESENTATION_TEXT_NAME_PREFIX = "PT"; + + private static final String DOCUMENT_NAME_PREFIX = "DOC"; + + private static final String IM_IMAGE_NAME_PREFIX = "IMIMG"; + + private static final String IMAGE_SEGMENT_NAME_PREFIX = "IS"; + + + /** the page group count */ + private int pageGroupCount = 0; + + /** the page count */ + private int pageCount = 0; + + /** the image count */ + private int imageCount = 0; + + /** the im image count */ + private int imImageCount = 0; + + /** the image segment count */ + private int imageSegmentCount = 0; + + /** the graphic count */ + private int graphicCount = 0; + + /** the object container count */ + private int objectContainerCount = 0; + + /** the resource count */ + private int resourceCount = 0; + + /** the resource group count */ + private int resourceGroupCount = 0; + + /** the overlay count */ + private int overlayCount = 0; + + /** the presentation text object count */ + private int textObjectCount = 0; + + /** the active environment group count */ + private int activeEnvironmentGroupCount = 0; + + /** the document count */ + private int documentCount = 0; + + /** the object environment group count */ + private int objectEnvironmentGroupCount = 0; + + /** + * Main constructor + */ + public Factory() { + } + + /** + * Creates a new IOCA {@link ImageObject} + * + * @return a new {@link ImageObject} + */ + public ImageObject createImageObject() { + String name = IMAGE_NAME_PREFIX + + StringUtils.lpad(String.valueOf(++imageCount), '0', 5); + ImageObject imageObject = new ImageObject(this, name); + return imageObject; + } + + /** + * Creates an IOCA {@link IMImageObject} + * + * @return a new {@link IMImageObject} + */ + public IMImageObject createIMImageObject() { + String name = IM_IMAGE_NAME_PREFIX + + StringUtils.lpad(String.valueOf(++imImageCount), '0', 3); + IMImageObject imImageObject = new IMImageObject(name); + return imImageObject; + } + + /** + * Creates a new GOCA {@link GraphicsObject} + * + * @return a new {@link GraphicsObject} + */ + public GraphicsObject createGraphicsObject() { + String name = GRAPHIC_NAME_PREFIX + + StringUtils.lpad(String.valueOf(++graphicCount), '0', 5); + GraphicsObject graphicsObj = new GraphicsObject(this, name); + return graphicsObj; + } + + /** + * Creates a new MO:DCA {@link ObjectContainer} + * + * @return a new {@link ObjectContainer} + */ + public ObjectContainer createObjectContainer() { + String name = OBJECT_CONTAINER_NAME_PREFIX + + StringUtils.lpad(String.valueOf(++objectContainerCount), '0', 6); + return new ObjectContainer(this, name); + } + + /** + * Creates a new MO:DCA {@link ResourceObject} + * + * @param resourceName the resource object name + * @return a new {@link ResourceObject} + */ + public ResourceObject createResource(String resourceName) { + return new ResourceObject(resourceName); + } + + /** + * Creates a new MO:DCA {@link ResourceObject} + * + * @return a new {@link ResourceObject} + */ + public ResourceObject createResource() { + String name = RESOURCE_NAME_PREFIX + + StringUtils.lpad(String.valueOf(++resourceCount), '0', 5); + return createResource(name); + } + + /** + * Creates a new MO:DCA {@link PageGroup} + * + * @return a new {@link PageGroup} + */ + public PageGroup createPageGroup() { + String name = PAGE_GROUP_NAME_PREFIX + + StringUtils.lpad(String.valueOf(++pageGroupCount), '0', 5); + return new PageGroup(this, name); + } + + /** + * Creates a new MO:DCA {@link ActiveEnvironmentGroup} + * + * @param width the page width + * @param height the page height + * @param widthRes the page width resolution + * @param heightRes the page height resolution + * @return a new {@link ActiveEnvironmentGroup} + */ + public ActiveEnvironmentGroup createActiveEnvironmentGroup( + int width, int height, int widthRes, int heightRes) { + String name = ACTIVE_ENVIRONMENT_GROUP_NAME_PREFIX + + StringUtils.lpad(String.valueOf(++activeEnvironmentGroupCount ), '0', 5); + return new ActiveEnvironmentGroup(this, name, width, height, widthRes, heightRes); + } + + /** + * Creates a new MO:DCA {@link ResourceGroup} + * + * @return a new {@link ResourceGroup} + */ + public ResourceGroup createResourceGroup() { + String name = RESOURCE_GROUP_NAME_PREFIX + + StringUtils.lpad(String.valueOf(++resourceGroupCount), '0', 6); + return new ResourceGroup(name); + } + + /** + * Creates a new MO:DCA {@link StreamedResourceGroup} + * + * @param os the outputstream of the streamed resource group + * @return a new {@link StreamedResourceGroup} + */ + public StreamedResourceGroup createStreamedResourceGroup(OutputStream os) { + String name = RESOURCE_GROUP_NAME_PREFIX + + StringUtils.lpad(String.valueOf(++resourceGroupCount), '0', 6); + return new StreamedResourceGroup(name, os); + } + + /** + * Creates a new MO:DCA {@link PageObject}. + * + * @param pageWidth + * the width of the page + * @param pageHeight + * the height of the page + * @param pageRotation + * the rotation of the page + * @param pageWidthRes + * the width resolution of the page + * @param pageHeightRes + * the height resolution of the page + * + * @return a new {@link PageObject} + */ + public PageObject createPage(int pageWidth, int pageHeight, int pageRotation, + int pageWidthRes, int pageHeightRes) { + String pageName = PAGE_NAME_PREFIX + + StringUtils.lpad(String.valueOf(++pageCount), '0', 5); + return new PageObject(this, pageName, pageWidth, pageHeight, + pageRotation, pageWidthRes, pageHeightRes); + } + + + /** + * Creates a new MO:DCA {@link PresentationTextObject}. + * + * @return a new {@link PresentationTextObject} + */ + public PresentationTextObject createPresentationTextObject() { + String textObjectName = PRESENTATION_TEXT_NAME_PREFIX + + StringUtils.lpad(String.valueOf(++textObjectCount), '0', 6); + return new PresentationTextObject(textObjectName); + } + + + /** + * Creates a new MO:DCA {@link Overlay}. + * + * @param width + * the width of the overlay + * @param height + * the height of the overlay + * @param widthRes + * the width resolution of the overlay + * @param heightRes + * the height resolution of the overlay + * @param overlayRotation + * the rotation of the overlay + * + * @return a new {@link Overlay}. + */ + public Overlay createOverlay(int width, int height, + int widthRes, int heightRes, int overlayRotation) { + String overlayName = OVERLAY_NAME_PREFIX + + StringUtils.lpad(String.valueOf(++overlayCount), '0', 5); + Overlay overlay = new Overlay(this, overlayName, width, height, + overlayRotation, widthRes, heightRes); + return overlay; + } + + /** + * Creates a MO:DCA {@link Document} + * + * @return a new {@link Document} + */ + public Document createDocument() { + String documentName = DOCUMENT_NAME_PREFIX + + StringUtils.lpad(String.valueOf(++documentCount), '0', 5); + Document document = new Document(this, documentName); + return document; + } + + /** + * Creates a MO:DCA {@link MapCodedFont} + * + * @return a new {@link MapCodedFont} + */ + public MapCodedFont createMapCodedFont() { + MapCodedFont mapCodedFont = new MapCodedFont(); + return mapCodedFont; + } + + /** + * Creates a MO:DCA {@link IncludePageSegment} + * + * @param name the page segment name + * @param x the x coordinate + * @param y the y coordinate + * + * @return a new {@link IncludePageSegment} + */ + public IncludePageSegment createIncludePageSegment(String name, int x, int y) { + IncludePageSegment includePageSegment = new IncludePageSegment(name, x, y); + return includePageSegment; + } + + /** + * Creates a MO:DCA {@link IncludeObject} + * + * @param name the name of this include object + * @return a new {@link IncludeObject} + */ + public IncludeObject createInclude(String name) { + IncludeObject includeObject = new IncludeObject(name); + return includeObject; + } + + /** + * Creates a MO:DCA {@link TagLogicalElement} + * + * @param name name of the element + * @param value value of the element + * @return a new {@link TagLogicalElement} + */ + public TagLogicalElement createTagLogicalElement(String name, String value) { + TagLogicalElement tle = new TagLogicalElement(name, value); + return tle; + } + + /** + * Creates a new {@link DataStream} + * + * @param paintingState the AFP painting state + * @param outputStream an outputstream to write to + * @return a new {@link DataStream} + */ + public DataStream createDataStream(AFPPaintingState paintingState, OutputStream outputStream) { + DataStream dataStream = new DataStream(this, paintingState, outputStream); + return dataStream; + } + + /** + * Creates a new MO:DCA {@link PageDescriptor} + * + * @param width the page width. + * @param height the page height. + * @param widthRes the page width resolution. + * @param heightRes the page height resolution. + * @return a new {@link PageDescriptor} + */ + public PageDescriptor createPageDescriptor(int width, int height, int widthRes, int heightRes) { + PageDescriptor pageDescriptor = new PageDescriptor(width, height, widthRes, heightRes); + return pageDescriptor; + } + + /** + * Returns a new MO:DCA {@link ObjectEnvironmentGroup} + * + * @return a new {@link ObjectEnvironmentGroup} + */ + public ObjectEnvironmentGroup createObjectEnvironmentGroup() { + String oegName = OBJECT_ENVIRONMENT_GROUP_NAME_PREFIX + + StringUtils.lpad(String.valueOf(++objectEnvironmentGroupCount), '0', 5); + ObjectEnvironmentGroup objectEnvironmentGroup = new ObjectEnvironmentGroup(oegName); + return objectEnvironmentGroup; + } + + /** + * Creates a new GOCA {@link GraphicsData} + * + * @return a new {@link GraphicsData} + */ + public GraphicsData createGraphicsData() { + GraphicsData graphicsData = new GraphicsData(); + return graphicsData; + } + + /** + * Creates a new {@link ObjectAreaDescriptor} + * + * @param width the object width. + * @param height the object height. + * @param widthRes the object width resolution. + * @param heightRes the object height resolution. + * @return a new {@link ObjectAreaDescriptor} + */ + public ObjectAreaDescriptor createObjectAreaDescriptor( + int width, int height, int widthRes, int heightRes) { + ObjectAreaDescriptor objectAreaDescriptor + = new ObjectAreaDescriptor(width, height, widthRes, heightRes); + return objectAreaDescriptor; + } + + /** + * Creates a new {@link ObjectAreaPosition} + * + * @param x the x coordinate. + * @param y the y coordinate. + * @param rotation the coordinate system rotation (must be 0, 90, 180, 270). + * @return a new {@link ObjectAreaPosition} + */ + public ObjectAreaPosition createObjectAreaPosition(int x, int y, + int rotation) { + ObjectAreaPosition objectAreaPosition = new ObjectAreaPosition( + x, y, rotation); + return objectAreaPosition; + } + + /** + * Creates a new {@link ImageDataDescriptor} + * + * @param width the image width + * @param height the image height + * @param widthRes the x resolution of the image + * @param heightRes the y resolution of the image + * @return a new {@link ImageDataDescriptor} + */ + public ImageDataDescriptor createImageDataDescriptor( + int width, int height, int widthRes, int heightRes) { + ImageDataDescriptor imageDataDescriptor = new ImageDataDescriptor( + width, height, widthRes, heightRes); + return imageDataDescriptor; + } + + /** + * Creates a new GOCA {@link GraphicsDataDescriptor} + * + * @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 + * @param widthRes the x resolution of the graphics window + * @param heightRes the y resolution of the graphics window + * @return a new {@link GraphicsDataDescriptor} + */ + public GraphicsDataDescriptor createGraphicsDataDescriptor( + int xlwind, int xrwind, int ybwind, int ytwind, int widthRes, int heightRes) { + GraphicsDataDescriptor graphicsDataDescriptor = new GraphicsDataDescriptor( + xlwind, xrwind, ybwind, ytwind, widthRes, heightRes); + return graphicsDataDescriptor; + } + + /** + * Creates a new MO:DCA {@link ContainerDataDescriptor} + * + * @param dataWidth the container data width + * @param dataHeight the container data height + * @param widthRes the container data width resolution + * @param heightRes the container data height resolution + * @return a new {@link ContainerDataDescriptor} + */ + public ContainerDataDescriptor createContainerDataDescriptor( + int dataWidth, int dataHeight, int widthRes, int heightRes) { + ContainerDataDescriptor containerDataDescriptor + = new ContainerDataDescriptor(dataWidth, dataHeight, widthRes, heightRes); + return containerDataDescriptor; + } + + /** + * Creates a new MO:DCA {@link MapContainerData} + * + * @param optionValue the option value + * @return a new {@link MapContainerData} + */ + public MapContainerData createMapContainerData(byte optionValue) { + MapContainerData mapContainerData = new MapContainerData(optionValue); + return mapContainerData; + } + + /** + * Creates a new MO:DCA {@link MapDataResource} + * + * @return a new {@link MapDataResource} + */ + public MapDataResource createMapDataResource() { + MapDataResource mapDataResource = new MapDataResource(); + return mapDataResource; + } + + /** + * Creates a new PTOCA {@link PresentationTextDescriptor} + * + * @return a new {@link PresentationTextDescriptor} + */ + public PresentationTextDescriptor createPresentationTextDataDescriptor( + int width, int height, int widthRes, int heightRes) { + PresentationTextDescriptor presentationTextDescriptor + = new PresentationTextDescriptor(width, height, + widthRes, heightRes); + return presentationTextDescriptor; + } + + /** + * Creates a new MO:DCA {@link PresentationEnvironmentControl} + * + * @return a new {@link PresentationEnvironmentControl} + */ + public PresentationEnvironmentControl createPresentationEnvironmentControl() { + PresentationEnvironmentControl presentationEnvironmentControl + = new PresentationEnvironmentControl(); + return presentationEnvironmentControl; + } + + /** + * Creates a new MO:DCA {@link InvokeMediumMap} + * + * @param name the object name + * @return a new {@link InvokeMediumMap} + */ + public InvokeMediumMap createInvokeMediumMap(String name) { + InvokeMediumMap invokeMediumMap = new InvokeMediumMap(name); + return invokeMediumMap; + } + + /** + * Creates a new MO:DCA {@link ResourceEnvironmentGroup} + * + * @return a new {@link ResourceEnvironmentGroup} + */ + public ResourceEnvironmentGroup createResourceEnvironmentGroup() { + ResourceEnvironmentGroup resourceEnvironmentGroup = new ResourceEnvironmentGroup(); + return resourceEnvironmentGroup; + } + + /** + * Creates a new IOCA {@link ImageSegment} + * + * @return a new {@link ImageSegment} + */ + public ImageSegment createImageSegment() { + String name = IMAGE_SEGMENT_NAME_PREFIX + + StringUtils.lpad(String.valueOf(++imageSegmentCount), '0', 2); + ImageSegment imageSegment = new ImageSegment(this, name); + return imageSegment; + } + + /** + * Creates an new IOCA {@link ImageContent} + * + * @return an {@link ImageContent} + */ + public ImageContent createImageContent() { + ImageContent imageContent = new ImageContent(); + return imageContent; + } + + /** + * Creates a new IOCA {@link ImageRasterData} + * + * @param rasterData raster data + * @return a new {@link ImageRasterData} + */ + public ImageRasterData createImageRasterData(byte[] rasterData) { + ImageRasterData imageRasterData = new ImageRasterData(rasterData); + return imageRasterData; + } + + /** + * Creates an new IOCA {@link ImageSizeParameter}. + * + * @param hsize The horizontal size of the image. + * @param vsize The vertical size of the image. + * @param hresol The horizontal resolution of the image. + * @param vresol The vertical resolution of the image. + * @return a new {@link ImageSizeParameter} + */ + public ImageSizeParameter createImageSizeParameter(int hsize, int vsize, + int hresol, int vresol) { + ImageSizeParameter imageSizeParameter + = new ImageSizeParameter(hsize, vsize, hresol, vresol); + return imageSizeParameter; + } + +} diff --git a/src/java/org/apache/fop/afp/PaintingInfo.java b/src/java/org/apache/fop/afp/PaintingInfo.java new file mode 100644 index 000000000..e53f28306 --- /dev/null +++ b/src/java/org/apache/fop/afp/PaintingInfo.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +/** + * Generic painting information interface + */ +public interface PaintingInfo { + +} diff --git a/src/java/org/apache/fop/afp/RectanglePaintingInfo.java b/src/java/org/apache/fop/afp/RectanglePaintingInfo.java new file mode 100644 index 000000000..64503d0b8 --- /dev/null +++ b/src/java/org/apache/fop/afp/RectanglePaintingInfo.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + + +/** + * Filled rectangle painting information + */ +public class RectanglePaintingInfo implements PaintingInfo { + + private final float x; + private final float y; + private final float width; + private final float height; + + /** + * Main constructor + * + * @param x the x coordinate + * @param y the y coordinate + * @param width the width + * @param height the height + */ + public RectanglePaintingInfo(float x, float y, float width, float height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + /** + * Returns the x coordinate + * + * @return the x coordinate + */ + protected float getX() { + return x; + } + + /** + * Returns the y coordinate + * + * @return the y coordinate + */ + protected float getY() { + return y; + } + + /** + * Returns the width + * + * @return the width + */ + protected float getWidth() { + return width; + } + + /** + * Returns the height + * + * @return the height + */ + protected float getHeight() { + return height; + } + +} diff --git a/src/java/org/apache/fop/afp/Startable.java b/src/java/org/apache/fop/afp/Startable.java new file mode 100644 index 000000000..fd05b8455 --- /dev/null +++ b/src/java/org/apache/fop/afp/Startable.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +/** + * Set and expose whether an object has started or not. + */ +public interface Startable { + + /** + * Sets whether or not this object has started or not + * + * @param complete true if this object has started + */ + void setStarted(boolean started); + + /** + * Returns true if this object has started + * + * @return true if this object has started + */ + boolean isStarted(); +} diff --git a/src/java/org/apache/fop/afp/Streamable.java b/src/java/org/apache/fop/afp/Streamable.java new file mode 100644 index 000000000..cd731ab47 --- /dev/null +++ b/src/java/org/apache/fop/afp/Streamable.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Implementing object is able to write to an OutputStream + */ +public interface Streamable { + + /** + * DataStream objects must implement the writeToStream() + * method to write its data to the given OutputStream + * + * @param os the outputsteam stream + * @throws java.io.IOException an I/O exception of some sort has occurred. + */ + void writeToStream(OutputStream os) throws IOException; +} diff --git a/src/java/org/apache/fop/afp/StructuredData.java b/src/java/org/apache/fop/afp/StructuredData.java new file mode 100644 index 000000000..99555b39b --- /dev/null +++ b/src/java/org/apache/fop/afp/StructuredData.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp; + +/** + * An AFP object which is able to know its own data length prior to writeToStream() + */ +public interface StructuredData { + + /** + * Returns the data length of this structured field + * + * @return the data length of this structured field + */ + int getDataLength(); +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java b/src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java new file mode 100644 index 000000000..e607bef5f --- /dev/null +++ b/src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.fonts; + +import org.apache.fop.fonts.Base14Font; +import org.apache.fop.fonts.Font; +import org.apache.fop.fonts.FontCollection; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.base14.Courier; +import org.apache.fop.fonts.base14.CourierBold; +import org.apache.fop.fonts.base14.CourierBoldOblique; +import org.apache.fop.fonts.base14.CourierOblique; +import org.apache.fop.fonts.base14.Helvetica; +import org.apache.fop.fonts.base14.HelveticaBold; +import org.apache.fop.fonts.base14.HelveticaOblique; +import org.apache.fop.fonts.base14.TimesBold; +import org.apache.fop.fonts.base14.TimesBoldItalic; +import org.apache.fop.fonts.base14.TimesItalic; +import org.apache.fop.fonts.base14.TimesRoman; + +/** + * Sets up a typical Base 12 font configuration for AFP + */ +public class AFPBase12FontCollection implements FontCollection { + + /** standard raster font sizes */ + private static final int[] RASTER_SIZES = {6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 24, 30, 36}; + + /** standard raster font charset references */ + private static final String[] CHARSET_REF = { + "60", "70", "80", "90", "00", "A0", "B0", "D0", "F0", "H0", "J0", "N0", "T0", "Z0"}; + + private void addCharacterSet(RasterFont font, String charsetName, Base14Font base14) { + for (int i = 0; i < RASTER_SIZES.length; i++) { + int size = RASTER_SIZES[i]; + FopCharacterSet characterSet = new FopCharacterSet( + CharacterSet.DEFAULT_CODEPAGE, CharacterSet.DEFAULT_ENCODING, + charsetName + CHARSET_REF[i], base14); + font.addCharacterSet(size, characterSet); + } + } + + private int addFontProperties(FontInfo fontInfo, AFPFont font, + String[] names, String style, int weight, int num) { + String internalFontKey = "F" + num; + fontInfo.addMetrics(internalFontKey, font); + fontInfo.addFontProperties(internalFontKey, names, style, weight); + num++; + return num; + } + + /** {@inheritDoc} */ + public int setup(int start, FontInfo fontInfo) { + + /** + * Add the base 12 fonts (Helvetica, Times and Courier) + * + * Note: this default font configuration may not be available + * on your AFP environment. + */ + int num = start; + RasterFont font = null; + + /** standard font family reference names for Helvetica font */ + final String[] helveticaNames = {"Helvetica", "Arial", "sans-serif"}; + font = new RasterFont("Helvetica"); + addCharacterSet(font, "C0H200", new Helvetica()); + num = addFontProperties(fontInfo, font, helveticaNames, + Font.STYLE_NORMAL, Font.WEIGHT_NORMAL, num); + + font = new RasterFont("Helvetica Italic"); + addCharacterSet(font, "C0H300", new HelveticaOblique()); + num = addFontProperties(fontInfo, font, helveticaNames, + Font.STYLE_ITALIC, Font.WEIGHT_NORMAL, num); + + font = new RasterFont("Helvetica (Semi) Bold"); + addCharacterSet(font, "C0H400", new HelveticaBold()); + num = addFontProperties(fontInfo, font, helveticaNames, + Font.STYLE_NORMAL, Font.WEIGHT_BOLD, num); + + font = new RasterFont("Helvetica Italic (Semi) Bold"); + addCharacterSet(font, "C0H500", new HelveticaOblique()); + num = addFontProperties(fontInfo, font, helveticaNames, + Font.STYLE_ITALIC, Font.WEIGHT_BOLD, num); + + + /** standard font family reference names for Times font */ + + /** any is treated as serif */ + final String[] timesNames = {"Times", "TimesRoman", "Times Roman", "Times-Roman", + "Times New Roman", "TimesNewRoman", "serif", "any"}; + + font = new RasterFont("Times Roman"); + addCharacterSet(font, "CON200", new TimesRoman()); + num = addFontProperties(fontInfo, font, timesNames, + Font.STYLE_NORMAL, Font.WEIGHT_NORMAL, num); + + font = new RasterFont("Times Roman Italic"); + addCharacterSet(font, "CON300", new TimesItalic()); + num = addFontProperties(fontInfo, font, timesNames, + Font.STYLE_ITALIC, Font.WEIGHT_NORMAL, num); + + font = new RasterFont("Times Roman Bold"); + addCharacterSet(font, "CON400", new TimesBold()); + num = addFontProperties(fontInfo, font, timesNames, + Font.STYLE_NORMAL, Font.WEIGHT_BOLD, num); + + font = new RasterFont("Times Roman Italic Bold"); + addCharacterSet(font, "CON500", new TimesBoldItalic()); + num = addFontProperties(fontInfo, font, timesNames, + Font.STYLE_ITALIC, Font.WEIGHT_BOLD, num); + + + /** standard font family reference names for Courier font */ + final String[] courierNames = {"Courier", "monospace"}; + + font = new RasterFont("Courier"); + addCharacterSet(font, "C04200", new Courier()); + num = addFontProperties(fontInfo, font, courierNames, + Font.STYLE_NORMAL, Font.WEIGHT_NORMAL, num); + + font = new RasterFont("Courier Italic"); + addCharacterSet(font, "C04300", new CourierOblique()); + num = addFontProperties(fontInfo, font, courierNames, + Font.STYLE_ITALIC, Font.WEIGHT_NORMAL, num); + + font = new RasterFont("Courier Bold"); + addCharacterSet(font, "C04400", new CourierBold()); + num = addFontProperties(fontInfo, font, courierNames, + Font.STYLE_NORMAL, Font.WEIGHT_BOLD, num); + + font = new RasterFont("Courier Italic Bold"); + addCharacterSet(font, "C04500", new CourierBoldOblique()); + num = addFontProperties(fontInfo, font, courierNames, + Font.STYLE_ITALIC, Font.WEIGHT_BOLD, num); + + return num; + } + +} diff --git a/src/java/org/apache/fop/render/afp/fonts/AFPFont.java b/src/java/org/apache/fop/afp/fonts/AFPFont.java index 2819cf12c..dc8f9c315 100644 --- a/src/java/org/apache/fop/render/afp/fonts/AFPFont.java +++ b/src/java/org/apache/fop/afp/fonts/AFPFont.java @@ -17,7 +17,8 @@ /* $Id$ */ -package org.apache.fop.render.afp.fonts; +package org.apache.fop.afp.fonts; + import java.util.Map; import java.util.Set; @@ -41,7 +42,6 @@ public abstract class AFPFont extends Typeface { */ public AFPFont(String name) { this.name = name; - } /** {@inheritDoc} */ @@ -106,4 +106,8 @@ public abstract class AFPFont extends Typeface { return true; } + /** {@inheritDoc} */ + public String toString() { + return "name=" + name; + } }
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/AFPFontAttributes.java b/src/java/org/apache/fop/afp/fonts/AFPFontAttributes.java index fb6f82463..de7f7f5be 100644 --- a/src/java/org/apache/fop/render/afp/AFPFontAttributes.java +++ b/src/java/org/apache/fop/afp/fonts/AFPFontAttributes.java @@ -17,40 +17,30 @@ /* $Id$ */ -package org.apache.fop.render.afp; - -import org.apache.fop.render.afp.fonts.AFPFont; +package org.apache.fop.afp.fonts; /** * This class encapsulates the font attributes that need to be included * in the AFP data stream. This class does not assist in converting the * font attributes to AFP code pages and character set values. - * */ public class AFPFontAttributes { - /** - * The font reference - */ + /** the font reference */ private int fontReference; - /** - * The font key - */ - private String fontKey; + /** the font key */ + private final String fontKey; - /** - * The font - */ - private AFPFont font; + /** the font */ + private final AFPFont font; - /** - * The point size - */ - private int pointSize; + /** the point size */ + private final int pointSize; /** * Constructor for the AFPFontAttributes + * * @param fontKey the font key * @param font the font * @param pointSize the point size @@ -62,6 +52,8 @@ public class AFPFontAttributes { } /** + * Return the font + * * @return the font */ public AFPFont getFont() { @@ -69,6 +61,8 @@ public class AFPFontAttributes { } /** + * Return the FontKey attribute + * * @return the FontKey attribute */ public String getFontKey() { @@ -76,6 +70,8 @@ public class AFPFontAttributes { } /** + * Return the point size attribute + * * @return the point size attribute */ public int getPointSize() { @@ -83,6 +79,8 @@ public class AFPFontAttributes { } /** + * Return the FontReference attribute + * * @return the FontReference attribute */ public int getFontReference() { @@ -91,10 +89,18 @@ public class AFPFontAttributes { /** * Sets the FontReference attribute + * * @param fontReference the FontReference to set */ public void setFontReference(int fontReference) { this.fontReference = fontReference; } + /** {@inheritDoc} */ + public String toString() { + return "fontReference=" + fontReference + + ", fontKey=" + fontKey + + ", font=" + font + + ", pointSize=" + pointSize; + } } diff --git a/src/java/org/apache/fop/afp/fonts/AFPFontCollection.java b/src/java/org/apache/fop/afp/fonts/AFPFontCollection.java new file mode 100644 index 000000000..670373fbf --- /dev/null +++ b/src/java/org/apache/fop/afp/fonts/AFPFontCollection.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.afp.fonts; + +import java.util.Iterator; +import java.util.List; + +import org.apache.fop.afp.AFPEventProducer; +import org.apache.fop.events.EventBroadcaster; +import org.apache.fop.fonts.Font; +import org.apache.fop.fonts.FontCollection; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontTriplet; + +/** + * A base collection of AFP fonts + */ +public class AFPFontCollection implements FontCollection { + + private final EventBroadcaster eventBroadcaster; + + private final List/*<AFPFontInfo>*/ fontInfoList; + + /** + * Main constructor + * + * @param eventBroadcaster the event broadcaster + * @param fontInfoList the font info list + */ + public AFPFontCollection(EventBroadcaster eventBroadcaster, + List/*<AFPFontInfo>*/ fontInfoList) { + this.eventBroadcaster = eventBroadcaster; + this.fontInfoList = fontInfoList; + } + + /** {@inheritDoc} */ + public int setup(int start, FontInfo fontInfo) { + int num = 1; + AFPEventProducer eventProducer = AFPEventProducer.Provider.get(eventBroadcaster); + if (fontInfoList != null && fontInfoList.size() > 0) { + for (Iterator it = fontInfoList.iterator(); it.hasNext();) { + AFPFontInfo afpFontInfo = (AFPFontInfo)it.next(); + AFPFont afpFont = afpFontInfo.getAFPFont(); + List/*<FontTriplet>*/ tripletList = afpFontInfo.getFontTriplets(); + for (Iterator it2 = tripletList.iterator(); it2.hasNext();) { + FontTriplet triplet = (FontTriplet)it2.next(); + fontInfo.addFontProperties("F" + num, + triplet.getName(), triplet.getStyle(), triplet.getWeight()); + fontInfo.addMetrics("F" + num, afpFont); + num++; + } + } + if (!fontInfo.hasFont("any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL)) { + eventProducer.warnMissingDefaultFont(this, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); + } + if (!fontInfo.hasFont("any", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL)) { + eventProducer.warnMissingDefaultFont(this, Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); + } + if (!fontInfo.hasFont("any", Font.STYLE_NORMAL, Font.WEIGHT_BOLD)) { + eventProducer.warnMissingDefaultFont(this, Font.STYLE_ITALIC, Font.WEIGHT_BOLD); + } + if (!fontInfo.hasFont("any", Font.STYLE_ITALIC, Font.WEIGHT_BOLD)) { + eventProducer.warnMissingDefaultFont(this, Font.STYLE_ITALIC, Font.WEIGHT_BOLD); + } + } else { + eventProducer.warnDefaultFontSetup(this); + + // Go with a default base 12 configuration for AFP environments + FontCollection base12FontCollection = new AFPBase12FontCollection(); + num = base12FontCollection.setup(num, fontInfo); + } + return num; + } + +} diff --git a/src/java/org/apache/fop/render/afp/fonts/AFPFontInfo.java b/src/java/org/apache/fop/afp/fonts/AFPFontInfo.java index 42f333a66..0259435c6 100644 --- a/src/java/org/apache/fop/render/afp/fonts/AFPFontInfo.java +++ b/src/java/org/apache/fop/afp/fonts/AFPFontInfo.java @@ -17,30 +17,33 @@ /* $Id$ */ -package org.apache.fop.render.afp.fonts; +package org.apache.fop.afp.fonts; import java.util.List; + /** * FontInfo contains meta information on fonts */ public class AFPFontInfo { private AFPFont font; - private List fontTriplets; + private List/*<FontTriplet>*/ tripletList; /** * Main constructor + * * @param afpFont The AFP Font - * @param fontTriplets List of font triplets to associate with this font + * @param tripletList List of font triplets to associate with this font */ - public AFPFontInfo(AFPFont afpFont, List fontTriplets) { + public AFPFontInfo(AFPFont afpFont, List/*<FontTriplet>*/ tripletList) { this.font = afpFont; - this.fontTriplets = fontTriplets; + this.tripletList = tripletList; } /** * Returns the afp font + * * @return the afp font */ public AFPFont getAFPFont() { @@ -49,10 +52,11 @@ public class AFPFontInfo { /** * Returns the list of font triplets associated with this font. + * * @return List of font triplets */ - public List getFontTriplets() { - return fontTriplets; + public List/*<FontTriplet>*/ getFontTriplets() { + return tripletList; } } diff --git a/src/java/org/apache/fop/render/afp/fonts/AFPFontReader.java b/src/java/org/apache/fop/afp/fonts/AFPFontReader.java index 0c190738c..16c341ac4 100644 --- a/src/java/org/apache/fop/render/afp/fonts/AFPFontReader.java +++ b/src/java/org/apache/fop/afp/fonts/AFPFontReader.java @@ -17,7 +17,7 @@ /* $Id$ */ -package org.apache.fop.render.afp.fonts; +package org.apache.fop.afp.fonts; import java.io.File; import java.io.FileNotFoundException; @@ -31,8 +31,8 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.fop.render.afp.modca.AFPConstants; -import org.apache.fop.render.afp.tools.StructuredFieldReader; +import org.apache.fop.afp.AFPConstants; +import org.apache.fop.afp.util.StructuredFieldReader; /** * The AFPFontReader is responsible for reading the font attributes from binary @@ -56,7 +56,7 @@ public final class AFPFontReader { /** * Static logging instance */ - protected static final Log log = LogFactory.getLog("org.apache.fop.render.afp.fonts"); + protected static final Log log = LogFactory.getLog("org.apache.xmlgraphics.afp.fonts"); /** * Template used to convert lists to arrays. diff --git a/src/java/org/apache/fop/afp/fonts/AFPPageFonts.java b/src/java/org/apache/fop/afp/fonts/AFPPageFonts.java new file mode 100644 index 000000000..ee7a3c0eb --- /dev/null +++ b/src/java/org/apache/fop/afp/fonts/AFPPageFonts.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.fonts; + +/** + * Holds the current page fonts + */ +public class AFPPageFonts extends java.util.HashMap { + private static final long serialVersionUID = -4991896259427109041L; + + /** + * Default constructor + */ + public AFPPageFonts() { + super(); + } + + /** + * Parameterized constructor + * + * @param fonts an existing set of afp page fonts + */ + public AFPPageFonts(AFPPageFonts fonts) { + super(fonts); + } + + /** + * 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); + int fontRef = super.size(); + afpFontAttributes.setFontReference(fontRef); + } + return afpFontAttributes; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/fonts/CharacterSet.java b/src/java/org/apache/fop/afp/fonts/CharacterSet.java index f7680b15c..31b53bf08 100644 --- a/src/java/org/apache/fop/render/afp/fonts/CharacterSet.java +++ b/src/java/org/apache/fop/afp/fonts/CharacterSet.java @@ -17,7 +17,7 @@ /* $Id$ */ -package org.apache.fop.render.afp.fonts; +package org.apache.fop.afp.fonts; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -25,8 +25,8 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.fop.render.afp.modca.AFPConstants; -import org.apache.fop.render.afp.tools.StringUtils; +import org.apache.fop.afp.AFPConstants; +import org.apache.fop.afp.util.StringUtils; /** * The IBM Font Object Content Architecture (FOCA) supports presentation @@ -51,10 +51,10 @@ public class CharacterSet { protected static final Log log = LogFactory.getLog(CharacterSet.class.getName()); /** default codepage */ - protected static final String DEFAULT_CODEPAGE = "T1V10500"; + public static final String DEFAULT_CODEPAGE = "T1V10500"; /** default encoding */ - protected static final String DEFAULT_ENCODING = "Cp500"; + public static final String DEFAULT_ENCODING = "Cp500"; private static final int MAX_NAME_LEN = 8; diff --git a/src/java/org/apache/fop/render/afp/fonts/CharacterSetOrientation.java b/src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java index e13029717..88e99eccf 100644 --- a/src/java/org/apache/fop/render/afp/fonts/CharacterSetOrientation.java +++ b/src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java @@ -17,7 +17,7 @@ /* $Id$ */ -package org.apache.fop.render.afp.fonts; +package org.apache.fop.afp.fonts; /** * The IBM Font Object Content Architecture (FOCA) supports presentation diff --git a/src/java/org/apache/fop/render/afp/exceptions/FontRuntimeException.java b/src/java/org/apache/fop/afp/fonts/FontRuntimeException.java index a54e4ad67..86e41707f 100644 --- a/src/java/org/apache/fop/render/afp/exceptions/FontRuntimeException.java +++ b/src/java/org/apache/fop/afp/fonts/FontRuntimeException.java @@ -17,13 +17,15 @@ /* $Id$ */ -package org.apache.fop.render.afp.exceptions; +package org.apache.fop.afp.fonts; /** * A runtime exception for handling fatal errors in processing fonts. * <p/> */ -public class FontRuntimeException extends NestedRuntimeException { +public class FontRuntimeException extends RuntimeException { + + private static final long serialVersionUID = -2217420523816384707L; /** * Constructs a FontRuntimeException with the specified message. diff --git a/src/java/org/apache/fop/render/afp/fonts/FopCharacterSet.java b/src/java/org/apache/fop/afp/fonts/FopCharacterSet.java index d5beb5a33..aec220b40 100644 --- a/src/java/org/apache/fop/render/afp/fonts/FopCharacterSet.java +++ b/src/java/org/apache/fop/afp/fonts/FopCharacterSet.java @@ -17,7 +17,7 @@ /* $Id$ */ -package org.apache.fop.render.afp.fonts; +package org.apache.fop.afp.fonts; import org.apache.fop.fonts.Typeface; @@ -28,7 +28,6 @@ public class FopCharacterSet extends CharacterSet { /** The character set for this font */ private Typeface charSet = null; - private int size = 0; /** * Constructor for the CharacterSetMetric object, the character set is used @@ -36,19 +35,16 @@ public class FopCharacterSet extends CharacterSet { * @param codePage the code page identifier * @param encoding the encoding of the font * @param name the character set name - * @param size the font size * @param charSet the fop character set */ public FopCharacterSet( String codePage, String encoding, String name, - int size, Typeface charSet) { super(codePage, encoding, name, null); this.charSet = charSet; - this.size = size * 1000; } /** @@ -64,7 +60,7 @@ public class FopCharacterSet extends CharacterSet { * @return the ascender value in millipoints */ public int getAscender() { - return charSet.getAscender(size); + return charSet.getAscender(1); } /** @@ -74,7 +70,7 @@ public class FopCharacterSet extends CharacterSet { * @return the cap height value in millipoints */ public int getCapHeight() { - return charSet.getCapHeight(size); + return charSet.getCapHeight(1); } /** @@ -84,7 +80,7 @@ public class FopCharacterSet extends CharacterSet { * @return the descender value in millipoints */ public int getDescender() { - return charSet.getDescender(size); + return charSet.getDescender(1); } /** @@ -116,7 +112,7 @@ public class FopCharacterSet extends CharacterSet { * @return the typical height of characters */ public int getXHeight() { - return charSet.getXHeight(size); + return charSet.getXHeight(1); } /** @@ -126,7 +122,7 @@ public class FopCharacterSet extends CharacterSet { * @return the width of the character */ public int getWidth(int character) { - return charSet.getWidth(character, size); + return charSet.getWidth(character, 1); } /** diff --git a/src/java/org/apache/fop/render/afp/fonts/OutlineFont.java b/src/java/org/apache/fop/afp/fonts/OutlineFont.java index 71c5dfb6f..ac45a2467 100644 --- a/src/java/org/apache/fop/render/afp/fonts/OutlineFont.java +++ b/src/java/org/apache/fop/afp/fonts/OutlineFont.java @@ -17,7 +17,8 @@ /* $Id$ */ -package org.apache.fop.render.afp.fonts; +package org.apache.fop.afp.fonts; + /** * A font defined as a set of lines and curves as opposed to a bitmap font. An @@ -91,7 +92,7 @@ public class OutlineFont extends AFPFont { * @return the ascender for the given size */ public int getAscender(int size) { - return charSet.getAscender() / 1000 * size; + return charSet.getAscender() * size; } /** @@ -102,7 +103,7 @@ public class OutlineFont extends AFPFont { * @return the cap height for the given size */ public int getCapHeight(int size) { - return charSet.getCapHeight() / 1000 * size; + return charSet.getCapHeight() * size; } /** @@ -115,7 +116,7 @@ public class OutlineFont extends AFPFont { * @return the descender for the given size */ public int getDescender(int size) { - return charSet.getDescender() / 1000 * size; + return charSet.getDescender() * size; } /** @@ -126,7 +127,7 @@ public class OutlineFont extends AFPFont { * @return the x height for the given size */ public int getXHeight(int size) { - return charSet.getXHeight() / 1000 * size; + return charSet.getXHeight() * size; } /** @@ -136,7 +137,7 @@ public class OutlineFont extends AFPFont { * @return the width of the character for the specified point size */ public int getWidth(int character, int size) { - return charSet.getWidth(character) / 1000 * size; + return charSet.getWidth(character) * size; } /** @@ -150,7 +151,7 @@ public class OutlineFont extends AFPFont { public int[] getWidths(int size) { int[] widths = charSet.getWidths(); for (int i = 0; i < widths.length; i++) { - widths[i] = widths[i] / 1000 * size; + widths[i] = widths[i] * size; } return widths; } diff --git a/src/java/org/apache/fop/render/afp/fonts/RasterFont.java b/src/java/org/apache/fop/afp/fonts/RasterFont.java index 5c1696aa4..ddce2d4d5 100644 --- a/src/java/org/apache/fop/render/afp/fonts/RasterFont.java +++ b/src/java/org/apache/fop/afp/fonts/RasterFont.java @@ -17,18 +17,14 @@ /* $Id$ */ -package org.apache.fop.render.afp.fonts; +package org.apache.fop.afp.fonts; -import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.fop.fo.properties.FixedLength; -import org.apache.fop.render.afp.exceptions.FontRuntimeException; - /** * A font where each character is stored as an array of pixels (a bitmap). Such * fonts are not easily scalable, in contrast to vectored fonts. With this type @@ -39,9 +35,10 @@ import org.apache.fop.render.afp.exceptions.FontRuntimeException; public class RasterFont extends AFPFont { /** Static logging instance */ - protected static final Log log = LogFactory.getLog("org.apache.fop.render.afp.fonts"); + protected static final Log log = LogFactory.getLog("org.apache.fop.afp.fonts"); - private Map charSets = new HashMap(); + private final Map/*<String,CharacterSet>*/ charSets + = new java.util.HashMap/*<String,CharacterSet>*/(); private CharacterSet charSet = null; @@ -66,6 +63,9 @@ public class RasterFont extends AFPFont { this.charSet = characterSet; } + /** Describes the unit millipoint. */ + public static final String MPT = "mpt"; + /** * Get the character set metrics for the specified point size. * @@ -77,7 +77,7 @@ public class RasterFont extends AFPFont { String pointsize = String.valueOf(size / 1000); CharacterSet csm = (CharacterSet) charSets.get(pointsize); if (csm == null) { - csm = (CharacterSet) charSets.get(size + FixedLength.MPT); + csm = (CharacterSet) charSets.get(size + MPT); } if (csm == null) { // Get char set with nearest font size @@ -85,7 +85,7 @@ public class RasterFont extends AFPFont { for (Iterator it = charSets.entrySet().iterator(); it.hasNext();) { Map.Entry me = (Map.Entry)it.next(); String key = (String)me.getKey(); - if (!key.endsWith(FixedLength.MPT)) { + if (!key.endsWith(MPT)) { int mpt = Integer.parseInt(key) * 1000; if (Math.abs(size - mpt) < distance) { distance = Math.abs(size - mpt); @@ -95,7 +95,7 @@ public class RasterFont extends AFPFont { } } if (csm != null) { - charSets.put(size + FixedLength.MPT, csm); + charSets.put(size + MPT, csm); String msg = "No " + (size / 1000) + "pt font " + getFontName() + " found, substituted with " + pointsize + "pt font"; log.warn(msg); @@ -154,7 +154,7 @@ public class RasterFont extends AFPFont { * @return the ascender for the given point size */ public int getAscender(int size) { - return getCharacterSet(size).getAscender(); + return getCharacterSet(size).getAscender() * size; } /** @@ -164,7 +164,7 @@ public class RasterFont extends AFPFont { * @return the cap height for the specified point size */ public int getCapHeight(int size) { - return getCharacterSet(size).getCapHeight(); + return getCharacterSet(size).getCapHeight() * size; } /** @@ -176,7 +176,7 @@ public class RasterFont extends AFPFont { * @return the descender for the specified point size */ public int getDescender(int size) { - return getCharacterSet(size).getDescender(); + return getCharacterSet(size).getDescender() * size; } /** @@ -186,7 +186,7 @@ public class RasterFont extends AFPFont { * @return the x height for the given point size */ public int getXHeight(int size) { - return getCharacterSet(size).getXHeight(); + return getCharacterSet(size).getXHeight() * size; } /** @@ -196,7 +196,7 @@ public class RasterFont extends AFPFont { * @return the width for the given point size */ public int getWidth(int character, int size) { - return getCharacterSet(size).getWidth(character); + return getCharacterSet(size).getWidth(character) * size; } /** diff --git a/src/java/org/apache/fop/afp/fonts/package.html b/src/java/org/apache/fop/afp/fonts/package.html new file mode 100644 index 000000000..74f8bf450 --- /dev/null +++ b/src/java/org/apache/fop/afp/fonts/package.html @@ -0,0 +1,23 @@ +<!-- + 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.html 643433 2008-04-01 15:08:24Z acumiskey $ --> +<HTML> +<TITLE>org.apache.fop.afp.goca Package</TITLE> +<BODY> +<P>Contains a collection of AFP Graphics Object Content Architecture (GOCA) structured objects.</P> +</BODY> +</HTML>
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/goca/AbstractGraphicsCoord.java b/src/java/org/apache/fop/afp/goca/AbstractGraphicsCoord.java new file mode 100644 index 000000000..3d8495667 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/AbstractGraphicsCoord.java @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * A base class encapsulating the structure of coordinate based GOCA objects + */ +public abstract class AbstractGraphicsCoord extends AbstractGraphicsDrawingOrder { + + /** array of x/y coordinates */ + protected int[] coords = null; + + protected boolean relative = false; + + /** + * Constructor + * + * @param coords the x/y coordinates for this object + */ + public AbstractGraphicsCoord(int[] coords) { + if (coords == null) { + relative = true; + } else { + this.coords = coords; + } + } + + /** + * Constructor + * + * @param coords the x/y coordinates for this object + * @param relative + */ + public AbstractGraphicsCoord(int[] coords, boolean relative) { + this(coords); + this.relative = relative; + } + + /** + * Constructor + * + * @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}); + } + + /** + * Constructor + * + * @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}); + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 2 + (coords != null ? coords.length * 2 : 0); + } + + /** + * Returns the coordinate data start index + * + * @return the coordinate data start index + */ + int getCoordinateDataStartIndex() { + return 2; + } + + /** + * Returns the coordinate data + * + * @return the coordinate data + */ + byte[] getData() { + byte[] data = super.getData(); + if (coords != null) { + addCoords(data, getCoordinateDataStartIndex()); + } + return data; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + os.write(getData()); + } + + /** + * 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]; + } + } + + /** {@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 + "}"; + } + + /** + * Returns true if this is a relative drawing order + * + * @return true if this is a relative drawing order + */ + protected boolean isRelative() { + return this.relative; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/goca/AbstractGraphicsDrawingOrder.java b/src/java/org/apache/fop/afp/goca/AbstractGraphicsDrawingOrder.java new file mode 100644 index 000000000..0d8f793c0 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/AbstractGraphicsDrawingOrder.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.goca; + +import org.apache.fop.afp.StructuredData; +import org.apache.fop.afp.modca.AbstractAFPObject; + +/** + * A base GOCA drawing order + */ +public abstract class AbstractGraphicsDrawingOrder extends AbstractAFPObject + implements StructuredData { + + /** + * Returns the order code of this structured field + * + * @return the order code of this structured field + */ + abstract byte getOrderCode(); + + /** + * Returns the coordinate data + * + * @return the coordinate data + */ + byte[] getData() { + int len = getDataLength(); + byte[] data = new byte[len]; + data[0] = getOrderCode(); + data[1] = (byte)(len - 2); + return data; + } + + /** + * Returns the short name of this GOCA object + * + * @return the short name of this GOCA object + */ + public String getName() { + String className = getClass().getName(); + return className.substring(className.lastIndexOf(".") + 1); + } +} diff --git a/src/java/org/apache/fop/afp/goca/AbstractGraphicsDrawingOrderContainer.java b/src/java/org/apache/fop/afp/goca/AbstractGraphicsDrawingOrderContainer.java new file mode 100644 index 000000000..34398b094 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/AbstractGraphicsDrawingOrderContainer.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.apache.fop.afp.Completable; +import org.apache.fop.afp.Startable; +import org.apache.fop.afp.StructuredData; +import org.apache.fop.afp.modca.AbstractNamedAFPObject; + +/** + * A base container of prepared structured AFP objects + */ +public abstract class AbstractGraphicsDrawingOrderContainer extends AbstractNamedAFPObject +implements StructuredData, Completable, Startable { + + /** list of objects contained within this container */ + protected List/*<StructuredDataObject>*/ objects + = new java.util.ArrayList/*<StructuredDataObject>*/(); + + /** object is complete */ + private boolean complete = false; + + /** object has started */ + private boolean started = false; + + /** + * Default constructor + */ + protected AbstractGraphicsDrawingOrderContainer() { + } + + /** + * Named constructor + * + * @param name the name of the container + */ + protected AbstractGraphicsDrawingOrderContainer(String name) { + super(name); + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + setStarted(true); + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + writeObjects(objects, os); + } + + /** + * Adds a given graphics object to this container + * + * @param object the structured data object + */ + public void addObject(StructuredData object) { + objects.add(object); + } + + /** + * Adds all the contents of a given graphics container to this container + * + * @param graphicsContainer a graphics container + */ + public void addAll(AbstractGraphicsDrawingOrderContainer graphicsContainer) { + Collection/*<StructuredDataObject>*/ objects = graphicsContainer.getObjects(); + objects.addAll(objects); + } + + /** + * Returns all the objects in this container + * + * @return all the objects in this container + */ + private Collection getObjects() { + return this.objects; + } + + /** + * Removes the last drawing order from this container and returns it + * + * @return the last drawing order from this container or null if empty + */ + public StructuredData removeLast() { + int lastIndex = objects.size() - 1; + StructuredData object = null; + if (lastIndex > -1) { + object = (StructuredData)objects.get(lastIndex); + objects.remove(lastIndex); + } + return object; + } + + /** + * Returns the current data length + * + * @return the current data length of this container including + * all enclosed objects (and their containers) + */ + public int getDataLength() { + int dataLen = 0; + Iterator it = objects.iterator(); + while (it.hasNext()) { + dataLen += ((StructuredData)it.next()).getDataLength(); + } + return dataLen; + } + + /** {@inheritDoc} */ + public void setComplete(boolean complete) { + Iterator it = objects.iterator(); + while (it.hasNext()) { + Object object = it.next(); + if (object instanceof Completable) { + ((Completable)object).setComplete(true); + } + } + this.complete = true; + } + + /** {@inheritDoc} */ + public boolean isComplete() { + return this.complete; + } + + /** {@inheritDoc} */ + public boolean isStarted() { + return this.started; + } + + /** {@inheritDoc} */ + public void setStarted(boolean started) { + this.started = started; + } +} diff --git a/src/java/org/apache/fop/afp/goca/GraphicsAreaBegin.java b/src/java/org/apache/fop/afp/goca/GraphicsAreaBegin.java new file mode 100644 index 000000000..fc66fa8cd --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsAreaBegin.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * The beginning of a filled region (graphics area). + */ +public class GraphicsAreaBegin extends AbstractGraphicsDrawingOrder { + + private static final int RES1 = 1; + private static final int BOUNDARY = 2; + private static final int NO_BOUNDARY = 0; + + /** 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; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[] { + getOrderCode(), // GBAR order code + (byte)(RES1 + (drawBoundary ? BOUNDARY : NO_BOUNDARY)) + }; + os.write(data); + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 2; + } + + /** {@inheritDoc} */ + public String toString() { + return "GraphicsAreaBegin{drawBoundary=" + drawBoundary + "}"; + } + + /** {@inheritDoc} */ + byte getOrderCode() { + return 0x68; + } +} diff --git a/src/java/org/apache/fop/afp/goca/GraphicsAreaEnd.java b/src/java/org/apache/fop/afp/goca/GraphicsAreaEnd.java new file mode 100644 index 000000000..12f14bfa4 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsAreaEnd.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.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * The end of a filled region (graphics area). + */ +public class GraphicsAreaEnd extends AbstractGraphicsDrawingOrder { + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[] { + getOrderCode(), // GEAR order code + 0x00, // LENGTH + }; + os.write(data); + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 2; + } + + /** {@inheritDoc} */ + public String toString() { + return "GraphicsAreaEnd"; + } + + /** {@inheritDoc} */ + byte getOrderCode() { + return 0x60; + } +} diff --git a/src/java/org/apache/fop/afp/goca/GraphicsBox.java b/src/java/org/apache/fop/afp/goca/GraphicsBox.java new file mode 100644 index 000000000..945697ec2 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsBox.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * A GOCA graphics rectangular box + */ +public final class GraphicsBox extends AbstractGraphicsCoord { + + /** + * Constructor + * + * @param coords the x/y coordinates for this object + */ + public GraphicsBox(int[] coords) { + super(coords); + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 12; + } + + /** {@inheritDoc} */ + int getCoordinateDataStartIndex() { + return 4; + } + + /** {@inheritDoc} */ + byte getOrderCode() { + return (byte)0xC0; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + data[2] = (byte)0x20; // CONTROL draw control flags + data[3] = 0x00; // reserved + + os.write(data); + } + +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/goca/GraphicsChainedSegment.java b/src/java/org/apache/fop/afp/goca/GraphicsChainedSegment.java new file mode 100644 index 000000000..8a92db296 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsChainedSegment.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * A GOCA graphics segment + */ +public final class GraphicsChainedSegment extends AbstractGraphicsDrawingOrderContainer { + + /** The maximum segment data length */ + protected static final int MAX_DATA_LEN = 8192; + + private byte[] predecessorNameBytes; + + /** + * 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 predecessorNameBytes + * the name of the predecessor in this chain + */ + public GraphicsChainedSegment(String name, byte[] predecessorNameBytes) { + super(name); + this.predecessorNameBytes = predecessorNameBytes; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 14 + super.getDataLength(); + } + + private static final byte APPEND_NEW_SEGMENT = 0; +// private static final byte PROLOG = 4; +// private static final byte APPEND_TO_EXISING = 48; + + private static final int NAME_LENGTH = 4; + + /** {@inheritDoc} */ + protected int getNameLength() { + return NAME_LENGTH; + } + + /** {@inheritDoc} */ + byte getOrderCode() { + return 0x70; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[14]; + data[0] = getOrderCode(); // BEGIN_SEGMENT + data[1] = 0x0C; // Length of following parameters + + // segment name + byte[] nameBytes = getNameBytes(); + System.arraycopy(nameBytes, 0, data, 2, NAME_LENGTH); + + data[6] = 0x00; // FLAG1 (ignored) + data[7] = APPEND_NEW_SEGMENT; + + int dataLength = super.getDataLength(); + byte[] len = BinaryUtils.convert(dataLength, 2); + data[8] = len[0]; // SEGL + data[9] = len[1]; + + // P/S NAME (predecessor name) + if (predecessorNameBytes != null) { + System.arraycopy(predecessorNameBytes, 0, data, 10, NAME_LENGTH); + } + os.write(data); + + writeObjects(objects, os); + } + + /** {@inheritDoc} */ + public String toString() { + return "GraphicsChainedSegment(name=" + super.getName() + ")"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/goca/GraphicsCharacterString.java b/src/java/org/apache/fop/afp/goca/GraphicsCharacterString.java new file mode 100644 index 000000000..70039d167 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsCharacterString.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import org.apache.fop.afp.AFPConstants; + +/** + * A GOCA graphics string + */ +public class GraphicsCharacterString extends AbstractGraphicsCoord { + + /** Up to 255 bytes of character data */ + protected static final int MAX_STR_LEN = 255; + + /** the string to draw */ + protected final String str; + + /** + * Constructor (absolute positioning) + * + * @param str the character string + * @param x the x coordinate + * @param y the y coordinate + */ + public GraphicsCharacterString(String str, int x, int y) { + super(x, y); + this.str = truncate(str); + } + + /** + * Constructor (relative positioning) + * + * @param str the character string + * @param x the x coordinate + * @param y the y coordinate + */ + public GraphicsCharacterString(String str) { + super(null); + this.str = truncate(str); + } + + /** {@inheritDoc} */ + byte getOrderCode() { + if (isRelative()) { + return (byte)0x83; + } else { + return (byte)0xC3; + } + } + + /** {@inheritDoc} */ + public int getDataLength() { + return super.getDataLength() + str.length(); + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + byte[] strData = getStringAsBytes(); + System.arraycopy(strData, 0, data, 6, strData.length); + os.write(data); + } + + /** + * Truncates the string as necessary + * + * @param str a character string + * @return a possibly truncated string + */ + private String truncate(String str) { + if (str.length() > MAX_STR_LEN) { + str = str.substring(0, MAX_STR_LEN); + log.warn("truncated character string, longer than " + MAX_STR_LEN + " chars"); + } + return str; + } + + /** + * Returns the text string as an encoded byte array + * + * @return the text string as an encoded byte array + */ + private byte[] getStringAsBytes() throws UnsupportedEncodingException { + return str.getBytes(AFPConstants.EBCIDIC_ENCODING); + } + + /** {@inheritDoc} */ + public String toString() { + return "GraphicsCharacterString{" + + (coords != null ? "x=" + coords[0] + ", y=" + coords[1] : "") + + "str='" + str + "'" + "}"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/goca/GraphicsData.java b/src/java/org/apache/fop/afp/goca/GraphicsData.java new file mode 100644 index 000000000..89be8dd94 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsData.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.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.StructuredData; +import org.apache.fop.afp.util.BinaryUtils; +import org.apache.fop.afp.util.StringUtils; + +/** + * A GOCA graphics data + */ +public final class GraphicsData extends AbstractGraphicsDrawingOrderContainer { + + /** the maximum graphics data length */ + public static final int MAX_DATA_LEN = 32767; + + /** the graphics segment */ + private GraphicsChainedSegment currentSegment = null; + + /** + * Main constructor + */ + public GraphicsData() { + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 8 + super.getDataLength(); + } + + /** + * Returns a new segment name + * + * @return a new segment name + */ + public String createSegmentName() { + return StringUtils.lpad(String.valueOf( + (super.objects != null ? super.objects.size() : 0) + 1), + '0', 4); + } + + /** + * Creates a new graphics segment + * + * @return a newly created graphics segment + */ + public GraphicsChainedSegment newSegment() { + String segmentName = createSegmentName(); + if (currentSegment == null) { + currentSegment = new GraphicsChainedSegment(segmentName); + } else { + currentSegment.setComplete(true); + currentSegment = new GraphicsChainedSegment(segmentName, currentSegment.getNameBytes()); + } + super.addObject(currentSegment); + return currentSegment; + } + + /** {@inheritDoc} */ + public void addObject(StructuredData object) { + if (currentSegment == null + || (currentSegment.getDataLength() + object.getDataLength()) + >= GraphicsChainedSegment.MAX_DATA_LEN) { + newSegment(); + } + currentSegment.addObject(object); + } + + /** + * Removes the current segment from this graphics data + * + * @return the current segment from this graphics data + */ + public StructuredData removeCurrentSegment() { + this.currentSegment = null; + return super.removeLast(); + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[9]; + copySF(data, SF_CLASS, Type.DATA, Category.GRAPHICS); + int dataLength = getDataLength(); + byte[] len = BinaryUtils.convert(dataLength, 2); + data[1] = len[0]; // Length byte 1 + data[2] = len[1]; // Length byte 2 + os.write(data); + + writeObjects(objects, os); + } + + /** {@inheritDoc} */ + public String toString() { + return "GraphicsData"; + } + + /** + * Adds the given segment to this graphics data + * + * @param segment a graphics chained segment + */ + public void addSegment(GraphicsChainedSegment segment) { + currentSegment = segment; + super.addObject(currentSegment); + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/goca/GraphicsFillet.java b/src/java/org/apache/fop/afp/goca/GraphicsFillet.java new file mode 100644 index 000000000..294be6d9b --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsFillet.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.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 { + + /** + * Constructor + * + * @param coords the x/y coordinates for this object + */ + public GraphicsFillet(int[] coords, boolean relative) { + super(coords, relative); + } + + /** {@inheritDoc} */ + byte getOrderCode() { + if (isRelative()) { + return (byte)0x85; + } else { + return (byte)0xC5; + } + } + +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/goca/GraphicsFullArc.java b/src/java/org/apache/fop/afp/goca/GraphicsFullArc.java new file mode 100644 index 000000000..a4b6916ae --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsFullArc.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.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * A GOCA graphics arc (circle/ellipse) + */ +public class GraphicsFullArc extends AbstractGraphicsCoord { + + /** the integer portion of the multiplier */ + private final int mh; + + /** the fractional portion of the multiplier */ + private final int mhr; + + /** + * Constructor + * + * @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; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 8; + } + + /** {@inheritDoc} */ + byte getOrderCode() { + return (byte)0xC7; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + + // integer portion of multiplier + data[6] = BinaryUtils.convert(mh, 1)[0]; + + // fractional portion of multiplier + data[7] = BinaryUtils.convert(mhr, 1)[0]; + + os.write(data); + } + + /** {@inheritDoc} */ + public String toString() { + return "GraphicsFullArc{" + + ", centerx=" + coords[0] + + ", centery=" + coords[1] + + ", mh=" + mh + + ", mhr=" + mhr + + "}"; + } + +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/goca/GraphicsImage.java b/src/java/org/apache/fop/afp/goca/GraphicsImage.java new file mode 100644 index 000000000..3b1dafeea --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsImage.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.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * A GOCA Image + */ +public class GraphicsImage extends AbstractGraphicsDrawingOrder { + + /** the maximum image data length */ + public static final short MAX_DATA_LEN = 255; + + /** x coordinate */ + private final int x; + + /** y coordinate */ + private final int y; + + /** width */ + private final int width; + + /** height */ + private final int height; + + /** image data */ + private final byte[] imageData; + + /** + * Main constructor + * + * @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 + * @param imageData the image data + */ + public GraphicsImage(int x, int y, int width, int height, byte[] imageData) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.imageData = imageData; + } + + /** {@inheritDoc} */ + public int getDataLength() { + //TODO: + return 0; + } + + byte getOrderCode() { + return (byte)0xD1; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] xcoord = BinaryUtils.convert(x, 2); + byte[] ycoord = BinaryUtils.convert(y, 2); + byte[] w = BinaryUtils.convert(width, 2); + byte[] h = BinaryUtils.convert(height, 2); + byte[] startData = new byte[] { + getOrderCode(), // 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] // + }; + os.write(startData); + + byte[] dataHeader = new byte[] { + (byte) 0x92 // GIMD + }; + final int lengthOffset = 1; + writeChunksToStream(imageData, dataHeader, lengthOffset, MAX_DATA_LEN, os); + + byte[] endData = new byte[] { + (byte) 0x93, // GEIMG order code + 0x00 // LENGTH + }; + os.write(endData); + } + + /** {@inheritDoc} */ + public String toString() { + return "GraphicsImage{x=" + x + + ", y=" + y + + ", width=" + width + + ", height=" + height + + "}"; + } +} diff --git a/src/java/org/apache/fop/afp/goca/GraphicsLine.java b/src/java/org/apache/fop/afp/goca/GraphicsLine.java new file mode 100644 index 000000000..17bd43ce0 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsLine.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.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * A GOCA graphics straight line drawn from the + * given absolute position + */ +public class GraphicsLine extends AbstractGraphicsCoord { + + /** + * Constructor + * + * @param coords the x/y coordinates for this object + * + * @param relative is this a relative drawing order + */ + public GraphicsLine(int[] coords, boolean relative) { + super(coords, relative); + } + + /** {@inheritDoc} */ + byte getOrderCode() { + if (isRelative()) { + return (byte)0x81; + } else { + return (byte)0xC1; + } + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + os.write(data); + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/goca/GraphicsSetArcParameters.java b/src/java/org/apache/fop/afp/goca/GraphicsSetArcParameters.java new file mode 100644 index 000000000..693cf21a9 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsSetArcParameters.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.goca; + +/** + * Sets the arc parameters for a GOCA graphics arc (circle/ellipse) + */ +public class GraphicsSetArcParameters extends AbstractGraphicsCoord { + + /** + * Constructor + * + * @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/afp/goca/GraphicsSetCharacterSet.java b/src/java/org/apache/fop/afp/goca/GraphicsSetCharacterSet.java new file mode 100644 index 000000000..b3d1158fe --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsSetCharacterSet.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.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * Sets the current character set (font) to be used for following graphics strings + */ +public class GraphicsSetCharacterSet extends AbstractGraphicsDrawingOrder { + + /** font character set reference */ + private final int fontReference; + + /** + * @param fontReference character set font reference + */ + public GraphicsSetCharacterSet(int fontReference) { + this.fontReference = fontReference; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[] { + getOrderCode(), // GSCS order code + BinaryUtils.convert(fontReference)[0] + }; + os.write(data); + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 2; + } + + /** {@inheritDoc} */ + public String toString() { + return "GraphicsSetCharacterSet(" + fontReference + ")"; + } + + /** {@inheritDoc} */ + byte getOrderCode() { + return 0x38; + } + +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/goca/GraphicsSetCurrentPosition.java b/src/java/org/apache/fop/afp/goca/GraphicsSetCurrentPosition.java new file mode 100644 index 000000000..675c2f034 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsSetCurrentPosition.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.goca; + +/** + * Sets the current painting position of the graphics object + */ +public class GraphicsSetCurrentPosition extends AbstractGraphicsCoord { + + /** + * Constructor + * + * @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/afp/goca/GraphicsSetLineType.java b/src/java/org/apache/fop/afp/goca/GraphicsSetLineType.java new file mode 100644 index 000000000..b6512f57c --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsSetLineType.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Sets the value of the current line type attribute when stroking GOCA shapes (structured fields) + */ +public class GraphicsSetLineType extends AbstractGraphicsDrawingOrder { + + /** 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; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 2; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[] { + getOrderCode(), // GSLW order code + type // line type + }; + os.write(data); + } + + private static final String[] TYPES = { + "default (solid)", "dotted", "short dashed", "dash dotted", "double dotted", + "long dashed", "dash double dotted", "solid", "invisible" + }; + + /** {@inheritDoc} */ + public String toString() { + return "GraphicsSetLineType{type=" + TYPES[type] + "}"; + } + + /** {@inheritDoc} */ + byte getOrderCode() { + return 0x18; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/goca/GraphicsSetLineWidth.java b/src/java/org/apache/fop/afp/goca/GraphicsSetLineWidth.java new file mode 100644 index 000000000..96eac0677 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsSetLineWidth.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Sets the line width to use when stroking GOCA shapes (structured fields) + */ +public class GraphicsSetLineWidth extends AbstractGraphicsDrawingOrder { + + /** line width multiplier */ + private int multiplier = 1; + + /** + * Main constructor + * + * @param multiplier the line width multiplier + */ + public GraphicsSetLineWidth(int multiplier) { + this.multiplier = multiplier; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 2; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[] { + getOrderCode(), // GSLW order code + (byte)multiplier // MH (line-width) + }; + os.write(data); + } + + /** {@inheritDoc} */ + public String toString() { + return "GraphicsSetLineWidth{multiplier=" + multiplier + "}"; + } + + /** {@inheritDoc} */ + byte getOrderCode() { + return 0x19; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/goca/GraphicsSetMix.java b/src/java/org/apache/fop/afp/goca/GraphicsSetMix.java new file mode 100644 index 000000000..dfb5ae0d2 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsSetMix.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Sets the foreground mix mode. + */ +public class GraphicsSetMix extends AbstractGraphicsDrawingOrder { + + public static final byte MODE_DEFAULT = 0x00; + public static final byte MODE_OVERPAINT = 0x02; + + /** the mix mode value */ + private final byte mode; + + /** + * Main constructor + * + * @param mode the mix mode value + */ + public GraphicsSetMix(byte mode) { + this.mode = mode; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[] { + 0x0C, // GSMX order code + mode // MODE (mix mode value) + }; + os.write(data); + } + + /** {@inheritDoc} */ + public String toString() { + return "GraphicsSetMix{mode=" + mode + "}"; + } + + /** {@inheritDoc} */ + byte getOrderCode() { + return 0x0C; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 2; + } + +} diff --git a/src/java/org/apache/fop/afp/goca/GraphicsSetPatternSymbol.java b/src/java/org/apache/fop/afp/goca/GraphicsSetPatternSymbol.java new file mode 100644 index 000000000..3d6cf7cd6 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsSetPatternSymbol.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.goca; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Sets the pattern symbol to use when filling following GOCA structured fields + */ +public class GraphicsSetPatternSymbol extends AbstractGraphicsDrawingOrder { + + /** 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 final byte pattern; + + /** + * Main constructor + * + * @param symb the pattern symbol to use + */ + public GraphicsSetPatternSymbol(byte pattern) { + this.pattern = pattern; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 2; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[] { + getOrderCode(), // GSPT order code + pattern + }; + os.write(data); + } + + /** {@inheritDoc} */ + public String toString() { + return "GraphicsSetPatternSymbol(fill=" + + (pattern == SOLID_FILL ? true : false) + ")"; + } + + /** {@inheritDoc} */ + byte getOrderCode() { + return 0x28; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/goca/GraphicsSetProcessColor.java b/src/java/org/apache/fop/afp/goca/GraphicsSetProcessColor.java new file mode 100644 index 000000000..05a6ee5d1 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/GraphicsSetProcessColor.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.goca; + +import java.awt.Color; +import java.awt.color.ColorSpace; +import java.io.IOException; +import java.io.OutputStream; + +/** + * Sets the current processing color for the following GOCA structured fields + */ +public class GraphicsSetProcessColor extends AbstractGraphicsDrawingOrder { + + private final Color color; + + private final float[] colorComponents; + + /** + * Main constructor + * + * @param color the color to set + */ + public GraphicsSetProcessColor(Color color) { + this.color = color; + this.colorComponents = color.getColorComponents(null); + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 12 + colorComponents.length; + } + + /** {@inheritDoc} */ + byte getOrderCode() { + return (byte)0xB2; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + + // COLSPCE + byte colspace; + int colSpaceType = color.getColorSpace().getType(); + if (colSpaceType == ColorSpace.TYPE_CMYK) { + colspace = 0x04; + } else if (colSpaceType == ColorSpace.TYPE_RGB) { + colspace = 0x01; + } else { + log.error("unsupported colorspace " + colSpaceType); + colspace = 0x01; + } + + // COLSIZE(S) + byte[] colsizes = new byte[] {0x00, 0x00, 0x00, 0x00}; + for (int i = 0; i < colorComponents.length; i++) { + colsizes[i] = (byte)8; + } + + int len = getDataLength(); + byte[] data = new byte[len]; + data[0] = getOrderCode(); // GSPCOL order code + data[1] = (byte)(len - 2); // 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 < colorComponents.length; i++) { + data[i + 12] = (byte)(colorComponents[i] * 255); + } + + os.write(data); + } + + /** {@inheritDoc} */ + public String toString() { + return "GraphicsSetProcessColor(col=" + color + ")"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/goca/package.html b/src/java/org/apache/fop/afp/goca/package.html new file mode 100644 index 000000000..539be8d13 --- /dev/null +++ b/src/java/org/apache/fop/afp/goca/package.html @@ -0,0 +1,23 @@ +<!-- + 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.html 643433 2008-04-01 15:08:24Z acumiskey $ --> +<HTML> +<TITLE>org.apache.fop.afp.fonts Package</TITLE> +<BODY> +<P>Contains a collection of AFP font related classes.</P> +</BODY> +</HTML>
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/ImageCellPosition.java b/src/java/org/apache/fop/afp/ioca/ImageCellPosition.java index c0b28904d..97489a9b1 100644 --- a/src/java/org/apache/fop/render/afp/modca/ImageCellPosition.java +++ b/src/java/org/apache/fop/afp/ioca/ImageCellPosition.java @@ -17,11 +17,13 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.ioca; import java.io.IOException; import java.io.OutputStream; -import org.apache.fop.render.afp.tools.BinaryUtils; + +import org.apache.fop.afp.modca.AbstractAFPObject; +import org.apache.fop.afp.util.BinaryUtils; /** * The IM Image Cell Position structured field specifies the placement, @@ -29,38 +31,27 @@ import org.apache.fop.render.afp.tools.BinaryUtils; */ public class ImageCellPosition extends AbstractAFPObject { - /** - * Offset of image cell in X direction - */ + /** offset of image cell in X direction */ private int xOffset = 0; - /** - * Offset of image cell in Y direction - */ + /** offset of image cell in Y direction */ private int yOffset = 0; - /** - * Size of image cell in X direction - */ - private byte[] xSize = new byte[] {(byte)0xFF, (byte)0xFF}; + /** size of image cell in X direction */ + private final byte[] xSize = new byte[] {(byte)0xFF, (byte)0xFF}; - /** - * Size of image cell in Y direction - */ - private byte[] ySize = new byte[] {(byte)0xFF, (byte)0xFF}; + /** size of image cell in Y direction */ + private final byte[] ySize = new byte[] {(byte)0xFF, (byte)0xFF}; - /** - * Size of fill rectangle in X direction - */ - private byte[] xFillSize = new byte[] {(byte)0xFF, (byte)0xFF}; + /** size of fill rectangle in X direction */ + private final byte[] xFillSize = new byte[] {(byte)0xFF, (byte)0xFF}; - /** - * Size of fill rectangle in Y direction - */ - private byte[] yFillSize = new byte[] {(byte)0xFF, (byte)0xFF}; + /** size of fill rectangle in Y direction */ + private final byte[] yFillSize = new byte[] {(byte)0xFF, (byte)0xFF}; /** - * Constructor for the ImageCellPosition + * Main Constructor + * * @param x The offset of image cell in X direction * @param y The offset of image cell in Y direction */ @@ -69,26 +60,14 @@ public class ImageCellPosition extends AbstractAFPObject { yOffset = y; } - /** - * Accessor method to write the AFP datastream for the Image Cell Position - * @param os The stream to write to - * @throws java.io.IOException if an I/O exception occurred - */ - public void writeDataStream(OutputStream os) throws IOException { + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { byte[] data = new byte[21]; + copySF(data, Type.POSITION, Category.IM_IMAGE); - data[0] = 0x5A; - - data[1] = 0x00; + data[1] = 0x00; // length data[2] = 0x14; - data[3] = (byte) 0xD3; - data[4] = (byte) 0xAC; - data[5] = (byte) 0x7B; - data[6] = 0x00; - data[7] = 0x00; - data[8] = 0x00; - /** * Specifies the offset along the Xp direction, in image points, * of this image cell from the IM image object area origin. @@ -125,6 +104,7 @@ public class ImageCellPosition extends AbstractAFPObject { * of this image cell. A value of X'FFFF' indicates that the * default extent specified in bytes 28 and 29 of the Image * Input Descriptor (IID) is to be used. + * * @param xcSize The size to set. */ public void setXSize(int xcSize) { @@ -141,6 +121,7 @@ public class ImageCellPosition extends AbstractAFPObject { * be used as the fill rectangle X-extent. The fill rectangle is * filled in the X direction by repeating the image cell in the * X direction. The image cell can be truncated to fit the rectangle. + * * @param size The size to set. */ public void setXFillSize(int size) { @@ -154,6 +135,7 @@ public class ImageCellPosition extends AbstractAFPObject { * of this image cell. A value of X'FFFF' indicates that the * default extent specified in bytes 30 and 31 of the Image * Input Descriptor (IID) is to be used. + * * @param size The size to set. */ public void setYSize(int size) { @@ -170,6 +152,7 @@ public class ImageCellPosition extends AbstractAFPObject { * be used as the fill rectangle Y-extent. The fill rectangle is * filled in the Y direction by repeating the image cell in the * Y direction. The image cell can be truncated to fit the rectangle. + * * @param size The size to set. */ public void setYFillSize(int size) { diff --git a/src/java/org/apache/fop/afp/ioca/ImageContent.java b/src/java/org/apache/fop/afp/ioca/ImageContent.java new file mode 100644 index 000000000..40e51578b --- /dev/null +++ b/src/java/org/apache/fop/afp/ioca/ImageContent.java @@ -0,0 +1,267 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.ioca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.modca.AbstractStructuredObject; + +/** + * An IOCA Image Content + */ +public class ImageContent extends AbstractStructuredObject { + + /** + * The CCITT T.4 Group 3 Coding Standard (G3 MH-Modified Huffman) is a + * compression method standardized by the International Telegraph and + * Telephone Consultative Committee (CCITT) for facsimile. It enables + * one-dimensional compression. + */ + public static final byte COMPID_G3_MH = (byte)0x80; + + /** + * The CCITT T.4 Group 3 Coding Option (G3 MR-Modified READ) is a + * compression method standardized by the International Telegraph and + * Telephone Consultative Committee (CCITT) for facsimile. It enables + * two-dimensional compression. + */ + public static final byte COMPID_G3_MR = (byte)0x81; + + /** + * The CCITT T.6 Group 4 Coding Standard (G4 MMR-Modified Modified READ) is a + * compression method standardized by the International Telegraph and + * Telephone Consultative Committee (CCITT) for facsimile. It enables + * two-dimensional compression. + */ + public static final byte COMPID_G3_MMR = (byte)0x82; + + /** the image size parameter */ + private ImageSizeParameter imageSizeParameter = null; + + /** the image encoding */ + private byte encoding = (byte)0x03; + + /** the image ide size */ + private byte size = 1; + + /** the image compression */ + private byte compression = (byte)0xC0; + + /** the image color model */ + private byte colorModel = (byte)0x01; + + /** the image data */ + private byte[] data; + + /** + * Main Constructor + */ + public ImageContent() { + } + + /** + * Sets the image size parameter + * + * @param imageSizeParameter the image size parameter. + */ + public void setImageSizeParameter(ImageSizeParameter imageSizeParameter) { + this.imageSizeParameter = imageSizeParameter; + } + + /** + * Sets the image encoding. + * + * @param enc The image encoding. + */ + public void setImageEncoding(byte enc) { + this.encoding = enc; + } + + /** + * Sets the image compression. + * + * @param comp The image compression. + */ + public void setImageCompression(byte comp) { + this.compression = comp; + } + + /** + * Sets the image IDE size. + * + * @param s The IDE size. + */ + public void setImageIDESize(byte s) { + this.size = s; + } + + /** + * Sets the image IDE color model. + * + * @param color the IDE color model. + */ + public void setImageIDEColorModel(byte color) { + this.colorModel = color; + } + + /** + * Set the image data (can be byte array or inputstream) + * + * @param imageData the image data + */ + public void setImageData(byte[] imageData) { + this.data = imageData; + } + + private static final int MAX_DATA_LEN = 65535; + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + if (imageSizeParameter != null) { + imageSizeParameter.writeToStream(os); + } + + // TODO convert to triplet/parameter class + os.write(getImageEncodingParameter()); + + os.write(getImageIDESizeParameter()); + + os.write(getIDEStructureParameter()); + + os.write(getExternalAlgorithmParameter()); + + final byte[] dataHeader = new byte[] { + (byte)0xFE, // ID + (byte)0x92, // ID + 0x00, // length + 0x00 // length + }; + final int lengthOffset = 2; + + // Image Data + if (data != null) { + writeChunksToStream(data, dataHeader, lengthOffset, MAX_DATA_LEN, os); + } + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + final byte[] startData = new byte[] { + (byte)0x91, // ID + 0x01, // Length + (byte)0xff, // Object Type = IOCA Image Object + }; + os.write(startData); + } + + /** {@inheritDoc} */ + protected void writeEnd(OutputStream os) throws IOException { + final byte[] endData = new byte[] { + (byte)0x93, // ID + 0x00, // Length + }; + os.write(endData); + } + + /** + * Helper method to return the image encoding parameter. + * + * @return byte[] The data stream. + */ + private byte[] getImageEncodingParameter() { + final byte[] encodingData = new byte[] { + (byte)0x95, // ID + 0x02, // Length + encoding, + 0x01, // RECID + }; + return encodingData; + } + + /** + * Helper method to return the external algorithm parameter. + * + * @return byte[] The data stream. + */ + private byte[] getExternalAlgorithmParameter() { + if (encoding == (byte)0x83 && compression != 0) { + final byte[] extAlgData = new byte[] { + (byte)0x95, // ID + 0x00, // Length + 0x10, // ALGTYPE = Compression Algorithm + 0x00, // Reserved + (byte)0x83, // COMPRID = JPEG + 0x00, // Reserved + 0x00, // Reserved + 0x00, // Reserved + compression, // MARKER + 0x00, // Reserved + 0x00, // Reserved + 0x00, // Reserved + }; + extAlgData[1] = (byte)(extAlgData.length - 2); + return extAlgData; + } + return new byte[0]; + } + + /** + * Helper method to return the image encoding parameter. + * + * @return byte[] The data stream. + */ + private byte[] getImageIDESizeParameter() { + final byte[] ideSizeData = new byte[] { + (byte)0x96, // ID + 0x01, // Length + size, + }; + return ideSizeData; + } + + /** + * Helper method to return the external algorithm parameter. + * + * @return byte[] The data stream. + */ + private byte[] getIDEStructureParameter() { + if (colorModel != 0 && size == 24) { + final byte bits = (byte)(size / 3); + final byte[] ideStructData = new byte[] { + (byte)0x9B, // ID + 0x00, // Length + 0x00, // FLAGS + 0x00, // Reserved + colorModel, // COLOR MODEL + 0x00, // Reserved + 0x00, // Reserved + 0x00, // Reserved + bits, + bits, + bits, + }; + ideStructData[1] = (byte)(ideStructData.length - 2); + return ideStructData; + } + return new byte[0]; + } + +} diff --git a/src/java/org/apache/fop/render/afp/modca/ImageInputDescriptor.java b/src/java/org/apache/fop/afp/ioca/ImageInputDescriptor.java index bba416c88..af237a467 100644 --- a/src/java/org/apache/fop/render/afp/modca/ImageInputDescriptor.java +++ b/src/java/org/apache/fop/afp/ioca/ImageInputDescriptor.java @@ -17,11 +17,13 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.ioca; import java.io.IOException; import java.io.OutputStream; -import org.apache.fop.render.afp.tools.BinaryUtils; + +import org.apache.fop.afp.modca.AbstractAFPObject; +import org.apache.fop.afp.util.BinaryUtils; /** * The IM Image Input Descriptor structured field contains the @@ -30,30 +32,17 @@ import org.apache.fop.render.afp.tools.BinaryUtils; */ public class ImageInputDescriptor extends AbstractAFPObject { - /** - * The resolution of the raster image (default 240) - */ + /** the resolution of the raster image (default 240) */ private int resolution = 240; - - /** - * Accessor method to write the AFP datastream for the Image Input Descriptor - * @param os The stream to write to - * @throws java.io.IOException if an I/O exception occurred - */ - public void writeDataStream(OutputStream os) throws IOException { + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { byte[] data = new byte[45]; + copySF(data, Type.DESCRIPTOR, Category.IM_IMAGE); - data[0] = 0x5A; - data[1] = 0x00; + data[1] = 0x00; // length data[2] = 0x2C; - data[3] = (byte) 0xD3; - data[4] = (byte) 0xA6; - data[5] = (byte) 0x7B; - data[6] = 0x00; - data[7] = 0x00; - data[8] = 0x00; // Constant data. data[9] = 0x00; @@ -131,12 +120,12 @@ public class ImageInputDescriptor extends AbstractAFPObject { data[44] = (byte)0xFF; os.write(data); - } /** * Sets the resolution information for the raster image * the default value is a resolution of 240 dpi. + * * @param resolution The resolution value */ public void setResolution(int resolution) { diff --git a/src/java/org/apache/fop/render/afp/modca/ImageOutputControl.java b/src/java/org/apache/fop/afp/ioca/ImageOutputControl.java index 558a600a5..3d500b3fd 100644 --- a/src/java/org/apache/fop/render/afp/modca/ImageOutputControl.java +++ b/src/java/org/apache/fop/afp/ioca/ImageOutputControl.java @@ -17,11 +17,13 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.ioca; import java.io.IOException; import java.io.OutputStream; -import org.apache.fop.render.afp.tools.BinaryUtils; + +import org.apache.fop.afp.modca.AbstractAFPObject; +import org.apache.fop.afp.util.BinaryUtils; /** * The IM Image Output Control structured field specifies the position and @@ -31,9 +33,7 @@ import org.apache.fop.render.afp.tools.BinaryUtils; */ public class ImageOutputControl extends AbstractAFPObject { - /** - * The orientation of the image - */ + /** the orientation of the image */ private int orientation = 0; /** @@ -48,9 +48,7 @@ public class ImageOutputControl extends AbstractAFPObject { */ private int yCoord = 0; - /** - * Map an image point to a single presentation device - */ + /** map an image point to a single presentation device */ private boolean singlePoint = true; /** @@ -67,18 +65,12 @@ public class ImageOutputControl extends AbstractAFPObject { * The Y-axis offset. */ public ImageOutputControl(int x, int y) { - xCoord = x; yCoord = y; - } - /** - * Accessor method to write the AFP datastream for the Image Output Control - * @param os The stream to write to - * @throws java.io.IOException if an I/O exception occured - */ - public void writeDataStream(OutputStream os) throws IOException { + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { byte[] data = new byte[33]; @@ -170,7 +162,6 @@ public class ImageOutputControl extends AbstractAFPObject { data[32] = (byte) 0xFF; os.write(data); - } /** diff --git a/src/java/org/apache/fop/render/afp/modca/ImageRasterData.java b/src/java/org/apache/fop/afp/ioca/ImageRasterData.java index ca440a859..50f44d39d 100644 --- a/src/java/org/apache/fop/render/afp/modca/ImageRasterData.java +++ b/src/java/org/apache/fop/afp/ioca/ImageRasterData.java @@ -17,11 +17,13 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.ioca; import java.io.IOException; import java.io.OutputStream; -import org.apache.fop.render.afp.tools.BinaryUtils; + +import org.apache.fop.afp.modca.AbstractAFPObject; +import org.apache.fop.afp.util.BinaryUtils; /** * Contains the image points that define the IM image raster pattern. @@ -45,43 +47,28 @@ import org.apache.fop.render.afp.tools.BinaryUtils; */ public class ImageRasterData extends AbstractAFPObject { - /** - * The image raster data - */ - private byte[] rasterData; + /** the image raster data */ + private final byte[] rasterData; /** * Constructor for the image raster data object + * * @param data The raster image data */ public ImageRasterData(byte[] data) { this.rasterData = data; } - /** - * Accessor method to write the AFP datastream for the Image Raster Data - * @param os The stream to write to - * @throws java.io.IOException if an I/O exception occurred - */ - public void writeDataStream(OutputStream os) throws IOException { - + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { byte[] data = new byte[9]; - - data[0] = 0x5A; - + copySF(data, Type.DATA, Category.IM_IMAGE); // The size of the structured field - byte[] x = BinaryUtils.convert(rasterData.length + 8, 2); - data[1] = x[0]; - data[2] = x[1]; - - data[3] = (byte) 0xD3; - data[4] = (byte) 0xEE; - data[5] = (byte) 0x7B; - data[6] = 0x00; - data[7] = 0x00; - data[8] = 0x00; - + byte[] len = BinaryUtils.convert(rasterData.length + 8, 2); + data[1] = len[0]; + data[2] = len[1]; os.write(data); + os.write(rasterData); } }
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/ImageRasterPattern.java b/src/java/org/apache/fop/afp/ioca/ImageRasterPattern.java index 373e50631..789eeb950 100644 --- a/src/java/org/apache/fop/render/afp/modca/ImageRasterPattern.java +++ b/src/java/org/apache/fop/afp/ioca/ImageRasterPattern.java @@ -17,7 +17,7 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.ioca; /** * Raster data is a grid of cells covering an area of interest. diff --git a/src/java/org/apache/fop/afp/ioca/ImageSegment.java b/src/java/org/apache/fop/afp/ioca/ImageSegment.java new file mode 100644 index 000000000..9fb544719 --- /dev/null +++ b/src/java/org/apache/fop/afp/ioca/ImageSegment.java @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.ioca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.Factory; +import org.apache.fop.afp.modca.AbstractNamedAFPObject; + +/** + * An Image Segment is represented by a set of self-defining fields, fields + * that describe their own contents. It starts with a Begin Segment, and + * ends with an End Segment. + * + * Between the Begin Segment and End Segment is the image information to + * be processed, called the Image Content. + * + * Only one Image Content can exist within a single IOCA Image Segment. + */ +public class ImageSegment extends AbstractNamedAFPObject { + + /** + * The ImageContent for the image segment + */ + private ImageContent imageContent = null; + + private final Factory factory; + + /** + * Constructor for the image segment with the specified name, + * the name must be a fixed length of eight characters. + * @param factory the object factory + * + * @param name the name of the image. + */ + public ImageSegment(Factory factory, String name) { + super(name); + this.factory = factory; + } + + private ImageContent getImageContent() { + if (imageContent == null) { + this.imageContent = factory.createImageContent(); + } + return imageContent; + } + + /** + * Sets the image size parameters resolution, hsize and vsize. + * + * @param hsize The horizontal size of the image. + * @param vsize The vertical size of the image. + * @param hresol The horizontal resolution of the image. + * @param vresol The vertical resolution of the image. + */ + public void setImageSize(int hsize, int vsize, int hresol, int vresol) { + ImageSizeParameter imageSizeParameter + = factory.createImageSizeParameter(hsize, vsize, hresol, vresol); + getImageContent().setImageSizeParameter(imageSizeParameter); + } + + /** + * Sets the image encoding. + * + * @param encoding The image encoding. + */ + public void setEncoding(byte encoding) { + getImageContent().setImageEncoding(encoding); + } + + /** + * Sets the image compression. + * + * @param compression The image compression. + */ + public void setCompression(byte compression) { + getImageContent().setImageCompression(compression); + } + + /** + * Sets the image IDE size. + * + * @param size The IDE size. + */ + public void setIDESize(byte size) { + getImageContent().setImageIDESize(size); + } + + /** + * Sets the image IDE color model. + * + * @param colorModel the IDE color model. + */ + public void setIDEColorModel(byte colorModel) { + getImageContent().setImageIDEColorModel(colorModel); + } + + /** + * Set the data image data. + * + * @param data the image data + */ + public void setData(byte[] imageData) { + getImageContent().setImageData(imageData); + } + + /** {@inheritDoc} */ + public void writeContent(OutputStream os) throws IOException { + if (imageContent != null) { + imageContent.writeToStream(os); + } + } + + private static final int NAME_LENGTH = 4; + + /** {@inheritDoc} */ + protected int getNameLength() { + return NAME_LENGTH; + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + byte[] nameBytes = getNameBytes(); + byte[] data = new byte[] { + 0x70, // ID + 0x04, // Length + nameBytes[0], // Name byte 1 + nameBytes[1], // Name byte 2 + nameBytes[2], // Name byte 3 + nameBytes[3], // Name byte 4 + }; + os.write(data); + } + + /** {@inheritDoc} */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[] { + 0x71, // ID + 0x00, // Length + }; + os.write(data); + } +} diff --git a/src/java/org/apache/fop/render/afp/modca/ImageSizeParameter.java b/src/java/org/apache/fop/afp/ioca/ImageSizeParameter.java index 7dd210a1e..38e7d9e56 100644 --- a/src/java/org/apache/fop/render/afp/modca/ImageSizeParameter.java +++ b/src/java/org/apache/fop/afp/ioca/ImageSizeParameter.java @@ -17,43 +17,42 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.ioca; import java.io.IOException; import java.io.OutputStream; -import org.apache.fop.render.afp.tools.BinaryUtils; + +import org.apache.fop.afp.modca.AbstractAFPObject; +import org.apache.fop.afp.util.BinaryUtils; /** * Describes the measurement characteristics of the image when it is created. */ public class ImageSizeParameter extends AbstractAFPObject { - private int hRes = 0; - private int vRes = 0; private int hSize = 0; private int vSize = 0; + private int hRes = 0; + private int vRes = 0; /** * Constructor for a ImageSizeParameter for the specified * resolution, hsize and vsize. - * @param hresol The horizontal resolution of the image. - * @param vresol The vertical resolution of the image. + * * @param hsize The horizontal size of the image. * @param vsize The vertical size of the image. + * @param hresol The horizontal resolution of the image. + * @param vresol The vertical resolution of the image. */ - public ImageSizeParameter(int hresol, int vresol, int hsize, int vsize) { - this.hRes = hresol; - this.vRes = vresol; + public ImageSizeParameter(int hsize, int vsize, int hresol, int vresol) { this.hSize = hsize; this.vSize = vsize; + this.hRes = hresol; + this.vRes = vresol; } - /** - * Accessor method to write the AFP datastream for the Image Size Parameter - * @param os The stream to write to - * @throws java.io.IOException if an I/O exception occured - */ - public void writeDataStream(OutputStream os) throws IOException { + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { byte[] data = new byte[] { (byte)0x94, // ID = Image Size Parameter 0x09, // Length diff --git a/src/java/org/apache/fop/afp/ioca/package.html b/src/java/org/apache/fop/afp/ioca/package.html new file mode 100644 index 000000000..34e0bc19d --- /dev/null +++ b/src/java/org/apache/fop/afp/ioca/package.html @@ -0,0 +1,23 @@ +<!-- + 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.html 643433 2008-04-01 15:08:24Z acumiskey $ --> +<HTML> +<TITLE>org.apache.fop.afp.ioca Package</TITLE> +<BODY> +<P>Contains a collection of AFP Image Object Content Architecture (IOCA) structured objects.</P> +</BODY> +</HTML>
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/modca/AbstractAFPObject.java b/src/java/org/apache/fop/afp/modca/AbstractAFPObject.java new file mode 100644 index 000000000..f1b76c447 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/AbstractAFPObject.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.afp.modca; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Collection; +import java.util.Iterator; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.afp.Streamable; +import org.apache.fop.afp.util.BinaryUtils; + +/** + * This is the base class for all data stream objects. Page objects are + * responsible for building and generating the binary datastream in an + * AFP format. + */ +public abstract class AbstractAFPObject implements Streamable { + + /** Static logging instance */ + protected static final Log log = LogFactory.getLog("org.apache.xmlgraphics.afp.modca"); + + /** the structured field class id */ + protected static final byte SF_CLASS = (byte)0xD3; + + private static final byte[] SF_HEADER = new byte[] { + 0x5A, // Structured field identifier + 0x00, // Length byte 1 + 0x10, // Length byte 2 + SF_CLASS, // Structured field id byte 1 + (byte) 0x00, // Structured field id byte 2 + (byte) 0x00, // Structured field id byte 3 + 0x00, // Flags + 0x00, // Reserved + 0x00, // Reserved + }; + + /** + * Copies the template structured field data array to the given byte array + * + * @param data the structured field data byte array + * @param type the type code + * @param category the category code + */ + protected void copySF(byte[] data, byte type, byte category) { + copySF(data, SF_CLASS, type, category); + } + + /** + * Copies the template structured field data array to the given byte array + * + * @param data the structured field data byte array + * @param clazz the class code + * @param type the type code + * @param category the category code + */ + protected static void copySF(byte[] data, byte clazz, byte type, byte category) { + System.arraycopy(SF_HEADER, 0, data, 0, SF_HEADER.length); + data[3] = clazz; + data[4] = type; + data[5] = category; + } + + /** + * Writes a collection of Streamable to the AFP Datastream. + * + * @param objects a list of AFPObjects + * @param os The stream to write to + * @throws java.io.IOException an I/O exception of some sort has occurred. + */ + protected void writeObjects(Collection/*<Streamable>*/ objects, OutputStream os) + throws IOException { + if (objects != null && objects.size() > 0) { + Iterator it = objects.iterator(); + while (it.hasNext()) { + Object object = it.next(); + if (object instanceof Streamable) { + ((Streamable)object).writeToStream(os); + it.remove(); // once written, immediately remove the object + } + } + } + } + + /** + * Reads data chunks from an InputStream + * and then formats them with a structured header to a given OutputStream + * + * @param dataHeader the header data + * @param lengthOffset offset of length field in data chunk + * @param maxChunkLength the maximum chunk length + * @param inputStream the InputStream to read from + * @param outputStream the OutputStream to write to + * @throws IOException thrown if an I/O exception of some sort has occurred. + */ + protected static void copyChunks(byte[] dataHeader, int lengthOffset, + int maxChunkLength, InputStream inputStream, OutputStream outputStream) + throws IOException { + int headerLen = dataHeader.length - lengthOffset; + // length field is just before data so do not include in data length + if (headerLen == 2) { + headerLen = 0; + } + byte[] data = new byte[maxChunkLength]; + int numBytesRead = 0; + while ((numBytesRead = inputStream.read(data, 0, maxChunkLength)) > 0) { + byte[] len = BinaryUtils.convert(headerLen + numBytesRead, 2); + dataHeader[lengthOffset] = len[0]; // Length byte 1 + dataHeader[lengthOffset + 1] = len[1]; // Length byte 2 + outputStream.write(dataHeader); + outputStream.write(data, 0, numBytesRead); + } + } + + /** + * Writes data chunks to a given outputstream + * + * @param data the data byte array + * @param dataHeader the header data + * @param lengthOffset offset of length field in data chunk + * @param maxChunkLength the maximum chunk length + * @param os the outputstream to write to + * @throws IOException thrown if an I/O exception of some sort has occurred. + */ + protected static void writeChunksToStream(byte[] data, byte[] dataHeader, + int lengthOffset, int maxChunkLength, OutputStream os) throws IOException { + int dataLength = data.length; + int numFullChunks = dataLength / maxChunkLength; + int lastChunkLength = dataLength % maxChunkLength; + + int headerLen = dataHeader.length - lengthOffset; + // length field is just before data so do not include in data length + if (headerLen == 2) { + headerLen = 0; + } + + byte[] len; + int off = 0; + if (numFullChunks > 0) { + // write out full data chunks + len = BinaryUtils.convert(headerLen + maxChunkLength, 2); + dataHeader[lengthOffset] = len[0]; // Length byte 1 + dataHeader[lengthOffset + 1] = len[1]; // Length byte 2 + for (int i = 0; i < numFullChunks; i++, off += maxChunkLength) { + os.write(dataHeader); + os.write(data, off, maxChunkLength); + } + } + + if (lastChunkLength > 0) { + // write last data chunk + len = BinaryUtils.convert(headerLen + lastChunkLength, 2); + dataHeader[lengthOffset] = len[0]; // Length byte 1 + dataHeader[lengthOffset + 1] = len[1]; // Length byte 2 + os.write(dataHeader); + os.write(data, off, lastChunkLength); + } + } + + /** structured field type codes */ + public interface Type { + + /** Attribute */ + byte ATTRIBUTE = (byte)0x0A; + + /** Copy Count */ + byte COPY_COUNT = (byte)0xA2; + + /** Descriptor */ + byte DESCRIPTOR = (byte)0xA6; + + /** Control */ + byte CONTROL = (byte)0xA7; + + /** Begin */ + byte BEGIN = (byte)0xA8; + + /** End */ + byte END = (byte)0xA9; + + /** Map */ + byte MAP = (byte)0xAB; + + /** Position */ + byte POSITION = (byte)0xAC; + + /** Process */ + byte PROCESS = (byte)0xAD; + + /** Include */ + byte INCLUDE = (byte)0xAF; + + /** Table */ + byte TABLE = (byte)0xB0; + + /** Migration */ + byte MIGRATION = (byte)0xB1; + + /** Variable */ + byte VARIABLE = (byte)0xB2; + + /** Link */ + byte LINK = (byte)0xB4; + + /** Data */ + byte DATA = (byte)0xEE; + } + + /** structured field category codes */ + public interface Category { + + /** Page Segment */ + byte PAGE_SEGMENT = (byte)0x5F; + + /** Object Area */ + byte OBJECT_AREA = (byte)0x6B; + + /** Color Attribute Table */ + byte COLOR_ATTRIBUTE_TABLE = (byte)0x77; + + /** IM Image */ + byte IM_IMAGE = (byte)0x7B; + + /** Medium */ + byte MEDIUM = (byte)0x88; + + /** Coded Font */ + byte CODED_FONT = (byte)0x8A; + + /** Process Element */ + byte PROCESS_ELEMENT = (byte)0x90; + + /** Object Container */ + byte OBJECT_CONTAINER = (byte)0x92; + + /** Presentation Text */ + byte PRESENTATION_TEXT = (byte)0x9B; + + /** Index */ + byte INDEX = (byte)0xA7; + + /** Document */ + byte DOCUMENT = (byte)0xA8; + + /** Page Group */ + byte PAGE_GROUP = (byte)0xAD; + + /** Page */ + byte PAGE = (byte)0xAF; + + /** Graphics */ + byte GRAPHICS = (byte)0xBB; + + /** Data Resource */ + byte DATA_RESOURCE = (byte)0xC3; + + /** Document Environment Group (DEG) */ + byte DOCUMENT_ENVIRONMENT_GROUP = (byte)0xC4; + + /** Resource Group */ + byte RESOURCE_GROUP = (byte)0xC6; + + /** Object Environment Group (OEG) */ + byte OBJECT_ENVIRONMENT_GROUP = (byte)0xC7; + + /** Active Environment Group (AEG) */ + byte ACTIVE_ENVIRONMENT_GROUP = (byte)0xC9; + + /** Medium Map */ + byte MEDIUM_MAP = (byte)0xCC; + + /** Form Map */ + byte FORM_MAP = (byte)0xCD; + + /** Name Resource */ + byte NAME_RESOURCE = (byte)0xCE; + + /** Page Overlay */ + byte PAGE_OVERLAY = (byte)0xD8; + + /** Resource Environment Group (REG) */ + byte RESOURCE_ENVIROMENT_GROUP = (byte)0xD9; + + /** Overlay */ + byte OVERLAY = (byte)0xDF; + + /** Data Suppression */ + byte DATA_SUPRESSION = (byte)0xEA; + + /** Bar Code */ + byte BARCODE = (byte)0xEB; + + /** No Operation */ + byte NO_OPERATION = (byte)0xEE; + + /** Image */ + byte IMAGE = (byte)0xFB; + } + +} + diff --git a/src/java/org/apache/fop/afp/modca/AbstractDataObject.java b/src/java/org/apache/fop/afp/modca/AbstractDataObject.java new file mode 100644 index 000000000..4a13b4a55 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/AbstractDataObject.java @@ -0,0 +1,140 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.AFPDataObjectInfo; +import org.apache.fop.afp.AFPObjectAreaInfo; +import org.apache.fop.afp.AFPResourceInfo; +import org.apache.fop.afp.AFPResourceLevel; +import org.apache.fop.afp.Completable; +import org.apache.fop.afp.Factory; +import org.apache.fop.afp.Startable; + +/** + * Abstract base class used by the ImageObject and GraphicsObject which both + * have define an ObjectEnvironmentGroup + */ +public abstract class AbstractDataObject extends AbstractNamedAFPObject implements Startable, Completable { + + /** the object environment group */ + protected ObjectEnvironmentGroup objectEnvironmentGroup = null; + + /** the object factory */ + protected final Factory factory; + + /** the completion status of this object */ + private boolean complete; + + /** the starting status of this object */ + private boolean started; + + /** + * Named constructor + * + * @param factory the object factory + * @param name data object name + */ + public AbstractDataObject(Factory factory, String name) { + super(name); + this.factory = factory; + } + + /** + * Sets the object view port (area position and size). + * + * @param dataObjectInfo + * the object area info + */ + public void setViewport(AFPDataObjectInfo dataObjectInfo) { + AFPObjectAreaInfo objectAreaInfo = dataObjectInfo.getObjectAreaInfo(); + + // object area descriptor + int width = objectAreaInfo.getWidth(); + int height = objectAreaInfo.getHeight(); + int widthRes = objectAreaInfo.getWidthRes(); + int heightRes = objectAreaInfo.getHeightRes(); + ObjectAreaDescriptor objectAreaDescriptor + = factory.createObjectAreaDescriptor(width, height, widthRes, heightRes); + getObjectEnvironmentGroup().setObjectAreaDescriptor(objectAreaDescriptor); + + // object area position + AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo(); + AFPResourceLevel resourceLevel = resourceInfo.getLevel(); + ObjectAreaPosition objectAreaPosition = null; + if (resourceLevel.isInline()) { + int x = objectAreaInfo.getX(); + int y = objectAreaInfo.getY(); + int rotation = objectAreaInfo.getRotation(); + objectAreaPosition = factory.createObjectAreaPosition(x, y, rotation); + } else { + // positional values are specified in the oaOffset of the include object + objectAreaPosition = factory.createObjectAreaPosition(0, 0, 0); + } + getObjectEnvironmentGroup().setObjectAreaPosition(objectAreaPosition); + } + + /** + * Gets the ObjectEnvironmentGroup + * + * @return the object environment group + */ + public ObjectEnvironmentGroup getObjectEnvironmentGroup() { + if (objectEnvironmentGroup == null) { + this.objectEnvironmentGroup = factory.createObjectEnvironmentGroup(); + } + return objectEnvironmentGroup; + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + setStarted(true); + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + writeTriplets(os); + if (objectEnvironmentGroup != null) { + objectEnvironmentGroup.writeToStream(os); + } + } + + /** {@inheritDoc} */ + public void setStarted(boolean started) { + this.started = started; + } + + /** {@inheritDoc} */ + public boolean isStarted() { + return this.started; + } + + /** {@inheritDoc} */ + public void setComplete(boolean complete) { + this.complete = complete; + } + + /** {@inheritDoc} */ + public boolean isComplete() { + return this.complete; + } +} diff --git a/src/java/org/apache/fop/render/afp/modca/AbstractDescriptor.java b/src/java/org/apache/fop/afp/modca/AbstractDescriptor.java index 83ed9b99a..8344bf0d1 100644 --- a/src/java/org/apache/fop/render/afp/modca/AbstractDescriptor.java +++ b/src/java/org/apache/fop/afp/modca/AbstractDescriptor.java @@ -17,33 +17,68 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.modca; /** * Base class for AFP descriptor objects */ -public abstract class AbstractDescriptor extends AbstractAFPObject { +public abstract class AbstractDescriptor extends AbstractTripletStructuredObject { + /** width of this descriptor */ protected int width = 0; /** 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; + + /** + * Default constructor + */ + public AbstractDescriptor() { + } /** * 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; + } + + /** {@inheritDoc} */ + public String toString() { + return "width=" + width + + ", height=" + height + + ", widthRes=" + widthRes + + ", heightRes=" + heightRes; + } + + /** + * Returns the width + * + * @return the width + */ + public int getWidth() { + return this.width; + } + + /** + * Returns the height + * + * @return the height + */ + public int getHeight() { + return this.height; } + } diff --git a/src/java/org/apache/fop/afp/modca/AbstractEnvironmentGroup.java b/src/java/org/apache/fop/afp/modca/AbstractEnvironmentGroup.java new file mode 100644 index 000000000..a58bba1f0 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/AbstractEnvironmentGroup.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +/** + * A base class that encapsulates common features of + * ActiveEnvironmentGroup and ResourceEnvironmentGroup + */ +public abstract class AbstractEnvironmentGroup extends AbstractNamedAFPObject { + + /** + * The collection of MapPageOverlay objects + */ + protected List mapPageOverlays = null; + + /** + * Main constructor + * + * @param name the object name + */ + public AbstractEnvironmentGroup(String name) { + super(name); + } + + private List getMapPageOverlays() { + if (mapPageOverlays == null) { + mapPageOverlays = new java.util.ArrayList(); + } + return mapPageOverlays; + } + + /** + * Actually creates the MPO object. + * Also creates the supporting object (an IPO) + * + * @param name the name of the overlay to be used + */ + public void createOverlay(String name) { + MapPageOverlay mpo = getCurrentMapPageOverlay(); + if (mpo == null) { + mpo = new MapPageOverlay(); + getMapPageOverlays().add(mpo); + } + + try { + mpo.addOverlay(name); + } catch (MaximumSizeExceededException msee) { + mpo = new MapPageOverlay(); + getMapPageOverlays().add(mpo); + try { + mpo.addOverlay(name); + } catch (MaximumSizeExceededException ex) { + // Should never happen (but log just in case) + log.error("createOverlay():: resulted in a MaximumSizeExceededException"); + } + } + } + + /** + * Getter method for the most recent MapPageOverlay added to the + * Active Environment Group (returns null if no MapPageOverlay exist) + * + * @return the most recent Map Coded Font + */ + private MapPageOverlay getCurrentMapPageOverlay() { + if (mapPageOverlays != null && mapPageOverlays.size() > 0) { + return (MapPageOverlay) mapPageOverlays.get(mapPageOverlays.size() - 1); + } else { + return null; + } + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + super.writeContent(os); + if (mapPageOverlays != null) { + writeObjects(mapPageOverlays, os); + } + } +} diff --git a/src/java/org/apache/fop/afp/modca/AbstractNamedAFPObject.java b/src/java/org/apache/fop/afp/modca/AbstractNamedAFPObject.java new file mode 100644 index 000000000..4e0dbc349 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/AbstractNamedAFPObject.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.UnsupportedEncodingException; + +import org.apache.fop.afp.AFPConstants; + +/** + * This is the base class for all named data stream objects. + * A named data stream object has an 8 byte EBCIDIC name. + */ +public abstract class AbstractNamedAFPObject extends AbstractTripletStructuredObject { + + private static final int DEFAULT_NAME_LENGTH = 8; + + /** + * The actual name of the object + */ + protected String name = null; + + /** + * Default constructor + */ + protected AbstractNamedAFPObject() { + } + + /** + * Constructor for the ActiveEnvironmentGroup, this takes a + * name parameter which should be 8 characters long. + * + * @param name the object name + */ + protected AbstractNamedAFPObject(String name) { + this.name = name; + } + + /** + * Returns the name length + * + * @return the name length + */ + protected int getNameLength() { + return DEFAULT_NAME_LENGTH; + } + + /** + * Returns the name as a byte array in EBCIDIC encoding + * + * @return the name as a byte array in EBCIDIC encoding + */ + public byte[] getNameBytes() { + int afpNameLen = getNameLength(); + int nameLen = name.length(); + if (nameLen < afpNameLen) { + name = (name + " ").substring(0, afpNameLen); + } else if (name.length() > afpNameLen) { + String truncatedName = name.substring(nameLen - afpNameLen, nameLen); + log.warn("Constructor:: name '" + name + "'" + + " truncated to " + afpNameLen + " chars" + + " ('" + truncatedName + "')"); + name = truncatedName; + } + byte[] nameBytes = null; + try { + nameBytes = name.getBytes(AFPConstants.EBCIDIC_ENCODING); + } catch (UnsupportedEncodingException usee) { + nameBytes = name.getBytes(); + log.warn( + "Constructor:: UnsupportedEncodingException translating the name " + + name); + } + return nameBytes; + } + + /** {@inheritDoc} */ + protected void copySF(byte[] data, byte type, byte category) { + super.copySF(data, type, category); + byte[] nameData = getNameBytes(); + System.arraycopy(nameData, 0, data, 9, nameData.length); + } + + /** + * Returns the name of this object + * + * @return the name of this object + */ + public String getName() { + return this.name; + } + + /** + * Sets the name of this object + * + * @param name the object name + */ + public void setName(String name) { + this.name = name; + } + + /** {@inheritDoc} */ + public String toString() { + return getName(); + } +} diff --git a/src/java/org/apache/fop/afp/modca/AbstractPageObject.java b/src/java/org/apache/fop/afp/modca/AbstractPageObject.java new file mode 100644 index 000000000..249de1339 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/AbstractPageObject.java @@ -0,0 +1,350 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.List; + +import org.apache.fop.afp.AFPLineDataInfo; +import org.apache.fop.afp.AFPTextDataInfo; +import org.apache.fop.afp.Completable; +import org.apache.fop.afp.Factory; +import org.apache.fop.afp.fonts.AFPFont; + +/** + * Pages contain the data objects that comprise a presentation document. Each + * page has a set of data objects associated with it. Each page within a + * document is independent from any other page, and each must establish its own + * environment parameters. + * + * The page is the level in the document component hierarchy that is used for + * printing or displaying a document's content. The data objects contained in + * the page envelope in the data stream are presented when the page is + * presented. Each data object has layout information associated with it that + * directs the placement and orientation of the data on the page. In addition, + * each page contains layout information that specifies the measurement units, + * page width, and page depth. + * + * A page is initiated by a begin page structured field and terminated by an end + * page structured field. Structured fields that define objects and active + * environment groups or that specify attributes of the page may be encountered + * in page state. + * + */ +public abstract class AbstractPageObject extends AbstractNamedAFPObject implements Completable { + + /** The active environment group for the page */ + protected ActiveEnvironmentGroup activeEnvironmentGroup = null; + + /** The current presentation text object */ + private PresentationTextObject currentPresentationTextObject = null; + + /** The list of tag logical elements */ + protected List/*<TagLogicalElement>*/ tagLogicalElements = null; + + /** The list of the include page segments */ + protected List/*<IncludePageSegment>*/ includePageSegments = null; + + /** The list of objects within this resource container */ + protected List/*<AbstractStructuredAFPObject>*/ objects = new java.util.ArrayList(); + + /** The page width */ + private int width; + + /** The page height */ + private int height; + + /** The page rotation */ + protected int rotation = 0; + + /** The page state */ + protected boolean complete = false; + + /** The width resolution */ + private int widthRes; + + /** The height resolution */ + private int heightRes; + + /** the object factory */ + protected final Factory factory; + + /** + * Default constructor + * + * @param factory the object factory + */ + public AbstractPageObject(Factory factory) { + this.factory = factory; + } + + /** + * Main constructor + * + * @param factory the object factory + * @param name the name of this page object + */ + public AbstractPageObject(Factory factory, String name) { + super(name); + this.factory = factory; + } + + /** + * Construct a new page object for the specified name argument, the page + * name should be an 8 character identifier. + * + * @param factory + * the object factory. + * @param name + * the name of the page. + * @param width + * the width of the page. + * @param height + * the height of the page. + * @param rotation + * the rotation of the page. + * @param widthRes + * the width resolution of the page. + * @param heightRes + * the height resolution of the page. + */ + public AbstractPageObject(Factory factory, + String name, int width, int height, int rotation, + int widthRes, int heightRes) { + super(name); + + this.factory = factory; + this.width = width; + this.height = height; + this.rotation = rotation; + this.widthRes = widthRes; + this.heightRes = heightRes; + } + + /** + * 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 page. + * + * @param fontReference + * the font number used as the resource identifier + * @param font + * the font + * @param size + * the point size of the font + */ + public void createFont(int fontReference, AFPFont font, int size) { + getActiveEnvironmentGroup().createFont(fontReference, font, size, 0); + } + + /** + * Helper method to create a line on the current page, this method delegates + * to the presentation text object in order to construct the line. + * + * @param lineDataInfo the line data information. + */ + public void createLine(AFPLineDataInfo lineDataInfo) { + getPresentationTextObject().createLineData(lineDataInfo); + } + + /** + * Helper method to create text on the current page, this method delegates + * to the presentation text object in order to construct the text. + * + * @param textDataInfo + * the afp text data + * @throws UnsupportedEncodingException thrown if character encoding is not supported + */ + public void createText(AFPTextDataInfo textDataInfo) throws UnsupportedEncodingException { + getPresentationTextObject().createTextData(textDataInfo); + } + + /** + * Helper method to mark the end of the page. This should end the control + * sequence on the current presentation text object. + */ + public void endPage() { + if (currentPresentationTextObject != null) { + currentPresentationTextObject.endControlSequence(); + } + setComplete(true); + } + + /** + * Ends the presentation text object + */ + protected void endPresentationObject() { + if (currentPresentationTextObject != null) { + currentPresentationTextObject.endControlSequence(); + currentPresentationTextObject = null; + } + } + + /** + * 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 (currentPresentationTextObject == null) { + PresentationTextObject presentationTextObject + = factory.createPresentationTextObject(); + addObject(presentationTextObject); + this.currentPresentationTextObject = presentationTextObject; + } + return currentPresentationTextObject; + } + + /** + * Creates a TagLogicalElement on the page. + * + * @param name + * the name of the tag + * @param value + * the value of the tag + */ + public void createTagLogicalElement(String name, String value) { + TagLogicalElement tle = new TagLogicalElement(name, value); + if (tagLogicalElements == null) { + tagLogicalElements = new java.util.ArrayList/*<TagLogicalElement>*/(); + } + tagLogicalElements.add(tle); + } + + /** + * Creates a NoOperation on the page. + * + * @param content the byte data + */ + public void createNoOperation(String content) { + addObject(new NoOperation(content)); + } + + /** + * Creates an IncludePageSegment on the current page. + * + * @param name + * the name of the page segment + * @param x + * the x coordinate of the page segment. + * @param y + * the y coordinate of the page segment. + */ + public void createIncludePageSegment(String name, int x, int y) { + IncludePageSegment ips = factory.createIncludePageSegment(name, x, y); + getIncludePageSegments().add(ips); + } + + /** + * Returns the include page segments list + * + * @return the include page segments list + */ + private List getIncludePageSegments() { + if (this.includePageSegments == null) { + this.includePageSegments = new java.util.ArrayList/*<IncludePageSegment>*/(); + } + return this.includePageSegments; + } + + /** + * Returns the ActiveEnvironmentGroup associated with this page. + * + * @return the ActiveEnvironmentGroup object + */ + public ActiveEnvironmentGroup getActiveEnvironmentGroup() { + if (activeEnvironmentGroup == null) { + // every page object must have an ActiveEnvironmentGroup + this.activeEnvironmentGroup + = factory.createActiveEnvironmentGroup(width, height, widthRes, heightRes); + + if (rotation != 0) { + switch (rotation) { + case 90: + activeEnvironmentGroup.setObjectAreaPosition(width, 0, rotation); + break; + case 180: + activeEnvironmentGroup.setObjectAreaPosition(width, height, rotation); + break; + case 270: + activeEnvironmentGroup.setObjectAreaPosition(0, height, rotation); + break; + default: + } + } + } + return activeEnvironmentGroup; + } + + /** + * Returns the height of the page + * + * @return the height of the page + */ + public int getHeight() { + return height; + } + + /** + * Returns the width of the page + * + * @return the width of the page + */ + public int getWidth() { + return width; + } + + /** + * Returns the rotation of the page + * + * @return the rotation of the page + */ + public int getRotation() { + return rotation; + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + super.writeContent(os); + writeObjects(this.objects, os); + } + + /** + * Adds an AFP object reference to this page + * + * @param obj an AFP object + */ + public void addObject(Object obj) { + objects.add(obj); + } + + /** {@inheritDoc} */ + public void setComplete(boolean complete) { + this.complete = complete; + } + + /** {@inheritDoc} */ + public boolean isComplete() { + return this.complete; + } +} diff --git a/src/java/org/apache/fop/afp/modca/AbstractResourceEnvironmentGroupContainer.java b/src/java/org/apache/fop/afp/modca/AbstractResourceEnvironmentGroupContainer.java new file mode 100644 index 000000000..baba170f7 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/AbstractResourceEnvironmentGroupContainer.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.Factory; + + +/** + * An abstract class which encapsulates the common features of + * Document and PageGroup resource containers + */ +public abstract class AbstractResourceEnvironmentGroupContainer + extends AbstractResourceGroupContainer { + + /** + * The resource environment group used to store complex resources + */ + protected ResourceEnvironmentGroup resourceEnvironmentGroup = null; + + /** + * Main constructor + * + * @param factory the object factory + * @param name the name of this resource container + */ + public AbstractResourceEnvironmentGroupContainer( + Factory factory, String name) { + super(factory, name); + } + + /** + * Adds a page to the resource container. + * + * @param page - the Page object + */ + public void addPage(PageObject page) { + addObject(page); + } + + /** + * Adds a PageGroup to the resource container. + * + * @param pageGroup the PageGroup object + */ + public void addPageGroup(PageGroup pageGroup) { + addObject(pageGroup); + } + + /** + * Creates an InvokeMediaMap on the page. + * + * @param name + * the name of the media map + */ + public void createInvokeMediumMap(String name) { + InvokeMediumMap invokeMediumMap = factory.createInvokeMediumMap(name); + addObject(invokeMediumMap); + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + super.writeContent(os); + if (resourceEnvironmentGroup != null) { + resourceEnvironmentGroup.writeToStream(os); + } + } + + /** + * Returns the resource environment group + * + * @return the resource environment group + */ + protected ResourceEnvironmentGroup getResourceEnvironmentGroup() { + if (resourceEnvironmentGroup == null) { + this.resourceEnvironmentGroup = factory.createResourceEnvironmentGroup(); + } + return this.resourceEnvironmentGroup; + } +} diff --git a/src/java/org/apache/fop/afp/modca/AbstractResourceGroupContainer.java b/src/java/org/apache/fop/afp/modca/AbstractResourceGroupContainer.java new file mode 100644 index 000000000..9dcd56277 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/AbstractResourceGroupContainer.java @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collection; +import java.util.Iterator; + +import org.apache.fop.afp.Completable; +import org.apache.fop.afp.Factory; +import org.apache.fop.afp.Streamable; + + +/** + * An abstract container of resource objects + */ +public abstract class AbstractResourceGroupContainer extends AbstractPageObject +implements Streamable { + + /** The container started state */ + protected boolean started = false; + + /** the resource group object */ + protected ResourceGroup resourceGroup = null; + + /** + * Default constructor + * + * @param factory the object factory + */ + public AbstractResourceGroupContainer(Factory factory) { + super(factory); + } + + /** + * Named constructor + * + * @param factory the object factory + * @param name the name of this resource container + */ + public AbstractResourceGroupContainer(Factory factory, String name) { + super(factory, name); + } + + /** + * Construct a new page object for the specified name argument, the page + * name should be an 8 character identifier. + * + * @param factory + * the object factory + * @param name + * the name of the page. + * @param width + * the width of the page. + * @param height + * the height of the page. + * @param rotation + * the rotation of the page. + * @param widthRes + * the width resolution of the page. + * @param heightRes + * the height resolution of the page. + */ + public AbstractResourceGroupContainer(Factory factory, + String name, int width, int height, int rotation, int widthRes, int heightRes) { + super(factory, name, width, height, rotation, widthRes, heightRes); + } + + /** + * Return the number of resources in this container + * + * @return the number of resources in this container + */ + protected int getResourceCount() { + if (resourceGroup != null) { + return resourceGroup.getResourceCount(); + } + return 0; + } + + /** + * Returns true if this resource group container contains resources + * + * @return true if this resource group container contains resources + */ + protected boolean hasResources() { + return resourceGroup != null && resourceGroup.getResourceCount() > 0; + } + + /** + * Returns the resource group in this resource group container + * + * @return the resource group in this resource group container + */ + public ResourceGroup getResourceGroup() { + if (resourceGroup == null) { + resourceGroup = factory.createResourceGroup(); + } + return resourceGroup; + } + +// /** {@inheritDoc} */ +// protected void writeContent(OutputStream os) throws IOException { +// if (resourceGroup != null) { +// resourceGroup.writeToStream(os); +// } +// super.writeContent(os); +// } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + if (!started) { + writeStart(os); + started = true; + } + + writeContent(os); + + if (complete) { + writeEnd(os); + } + } + + /** {@inheritDoc} */ + protected void writeObjects(Collection/*<AbstractAFPObject>*/ objects, OutputStream os) + throws IOException { + if (objects != null && objects.size() > 0) { + Iterator it = objects.iterator(); + while (it.hasNext()) { + AbstractAFPObject ao = (AbstractAFPObject)it.next(); + if (canWrite(ao)) { + ao.writeToStream(os); + it.remove(); + } else { + break; + } + } + } + } + + /** + * Returns true if this object can be written + * + * @param obj an AFP object + * @return true if this object can be written + */ + protected boolean canWrite(AbstractAFPObject obj) { + return obj instanceof AbstractPageObject && ((Completable)obj).isComplete(); + } +} diff --git a/src/java/org/apache/fop/afp/modca/AbstractStructuredObject.java b/src/java/org/apache/fop/afp/modca/AbstractStructuredObject.java new file mode 100644 index 000000000..e848583b5 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/AbstractStructuredObject.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * An abstract class encapsulating an MODCA structured object + */ +public abstract class AbstractStructuredObject extends AbstractAFPObject { + + /** + * Default constructor + */ + protected AbstractStructuredObject() { + } + + /** + * Helper method to write the start of the Object. + * + * @param os The stream to write to + * @throws IOException throws an I/O exception if one occurred + */ + protected void writeStart(OutputStream os) throws IOException { + } + + /** + * Helper method to write the end of the Object. + * + * @param os The stream to write to + * @throws IOException an I/O exception if one occurred + */ + protected void writeEnd(OutputStream os) throws IOException { + } + + /** + * Helper method to write the contents of the Object. + * + * @param os The stream to write to + * @throws IOException throws an I/O exception if one occurred + */ + protected void writeContent(OutputStream os) throws IOException { + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + writeStart(os); + writeContent(os); + writeEnd(os); + } +} diff --git a/src/java/org/apache/fop/afp/modca/AbstractTripletStructuredObject.java b/src/java/org/apache/fop/afp/modca/AbstractTripletStructuredObject.java new file mode 100644 index 000000000..a14af2967 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/AbstractTripletStructuredObject.java @@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.apache.fop.afp.modca.Registry.ObjectType; +import org.apache.fop.afp.modca.triplets.AbstractTriplet; +import org.apache.fop.afp.modca.triplets.CommentTriplet; +import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet; +import org.apache.fop.afp.modca.triplets.ObjectClassificationTriplet; + +/** + * A MODCA structured object base class providing support for Triplets + */ +public class AbstractTripletStructuredObject extends AbstractStructuredObject { + + /** list of object triplets */ + protected List/*<AbstractTriplet>*/ triplets = new java.util.ArrayList/*<AbstractTriplet>*/(); + + /** + * Returns the triplet data length + * + * @return the triplet data length + */ + protected int getTripletDataLength() { + int dataLength = 0; + if (hasTriplets()) { + Iterator it = triplets.iterator(); + while (it.hasNext()) { + AbstractTriplet triplet = (AbstractTriplet)it.next(); + dataLength += triplet.getDataLength(); + } + } + return dataLength; + } + + /** + * Returns true when this structured field contains triplets + * + * @return true when this structured field contains triplets + */ + public boolean hasTriplets() { + return triplets.size() > 0; + } + + /** + * Writes any triplet data + * + * @param os The stream to write to + * @throws IOException The stream to write to + */ + protected void writeTriplets(OutputStream os) throws IOException { + if (hasTriplets()) { + writeObjects(triplets, os); + triplets = null; // gc + } + } + + /** + * Returns the first matching triplet found in the structured field triplet list + * + * @param tripletId the triplet identifier + */ + private AbstractTriplet getTriplet(byte tripletId) { + Iterator it = getTriplets().iterator(); + while (it.hasNext()) { + AbstractTriplet triplet = (AbstractTriplet)it.next(); + if (triplet.getId() == tripletId) { + return triplet; + } + } + return null; + } + + /** + * Returns true of this structured field has the given triplet + * + * @param tripletId the triplet identifier + * @return true if the structured field has the given triplet + */ + public boolean hasTriplet(byte tripletId) { + return getTriplet(tripletId) != null; + } + + /** + * Adds a triplet to this structured object + * + * @param triplet the triplet to add + */ + protected void addTriplet(AbstractTriplet triplet) { + triplets.add(triplet); + } + + /** + * Adds a list of triplets to the triplets contained within this structured field + * + * @param tripletCollection a collection of triplets + */ + public void addTriplets(Collection/*<Triplet>*/ tripletCollection) { + if (tripletCollection != null) { + triplets.addAll(tripletCollection); + } + } + + /** @return the triplet list pertaining to this resource */ + protected List/*<Triplet>*/ getTriplets() { + return triplets; + } + + /** + * Sets the fully qualified name of this resource + * + * @param fqnType the fully qualified name type of this resource + * @param fqnFormat the fully qualified name format of this resource + * @param fqName the fully qualified name of this resource + */ + public void setFullyQualifiedName(byte fqnType, byte fqnFormat, String fqName) { + addTriplet(new FullyQualifiedNameTriplet(fqnType, fqnFormat, fqName)); + } + + /** @return the fully qualified name of this triplet or null if it does not exist */ + public String getFullyQualifiedName() { + FullyQualifiedNameTriplet fqNameTriplet + = (FullyQualifiedNameTriplet)getTriplet(AbstractTriplet.FULLY_QUALIFIED_NAME); + if (fqNameTriplet != null) { + return fqNameTriplet.getFullyQualifiedName(); + } + log.warn(this + " has no fully qualified name"); + return null; + } + + /** + * Sets the objects classification + * + * @param objectClass the classification of the object + * @param objectType the MOD:CA registry object type entry for the given + * object/component type of the object + * @param dataInContainer whether the data resides in the container + * @param containerHasOEG whether the container has an object environment group + * @param dataInOCD whether the data resides in a object container data structured field + */ + public void setObjectClassification( + byte objectClass, ObjectType objectType, + boolean dataInContainer, boolean containerHasOEG, boolean dataInOCD) { + addTriplet( + new ObjectClassificationTriplet( + objectClass, objectType, dataInContainer, containerHasOEG, dataInOCD)); + } + + /** + * Sets a comment on this resource + * + * @param commentString a comment string + */ + public void setComment(String commentString) { + addTriplet(new CommentTriplet(AbstractTriplet.COMMENT, commentString)); + } + +} diff --git a/src/java/org/apache/fop/afp/modca/ActiveEnvironmentGroup.java b/src/java/org/apache/fop/afp/modca/ActiveEnvironmentGroup.java new file mode 100644 index 000000000..ddc986be3 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/ActiveEnvironmentGroup.java @@ -0,0 +1,221 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +import org.apache.fop.afp.Factory; +import org.apache.fop.afp.fonts.AFPFont; + +/** + * An Active Environment Group (AEG) is associated with each page, + * and is contained in the page's begin-end envelope in the data stream. + * The active environment group contains layout and formatting information + * that defines the measurement units and size of the page, and may contain + * resource information. + * + * Any objects that are required for page presentation and that are to be + * treated as resource objects must be mapped with a map structured field + * in the AEG. The scope of an active environment group is the scope of its + * containing page or overlay. + * + */ +public final class ActiveEnvironmentGroup extends AbstractEnvironmentGroup { + + /** The collection of MapCodedFont objects */ + private final List/*<MapCodedFonts>*/ mapCodedFonts + = new java.util.ArrayList/*<MapCodedFonts>*/(); + + /** the collection of MapDataResource objects */ + private final List mapDataResources = null; + + /** the Object Area Descriptor for the active environment group */ + private ObjectAreaDescriptor objectAreaDescriptor = null; + + /** the Object Area Position for the active environment group */ + private ObjectAreaPosition objectAreaPosition = null; + + /** the PresentationTextDescriptor for the active environment group */ + private PresentationTextDescriptor presentationTextDataDescriptor = null; + + /** the PageDescriptor for the active environment group */ + private PageDescriptor pageDescriptor = null; + + /** the resource manager */ + private final Factory factory; + + /** + * Constructor for the ActiveEnvironmentGroup, this takes a + * name parameter which must be 8 characters long. + * + * @param factory the object factory + * @param name the active environment group name + * @param width the page width + * @param height the page height + * @param widthRes the page width resolution + * @param heightRes the page height resolution + */ + public ActiveEnvironmentGroup(Factory factory, + String name, int width, int height, int widthRes, int heightRes) { + super(name); + + this.factory = factory; + + // Create PageDescriptor + this.pageDescriptor + = factory.createPageDescriptor(width, height, widthRes, heightRes); + + // Create ObjectAreaDescriptor + this.objectAreaDescriptor + = factory.createObjectAreaDescriptor(width, height, widthRes, heightRes); + + // Create PresentationTextDataDescriptor + this.presentationTextDataDescriptor + = factory.createPresentationTextDataDescriptor(width, height, + widthRes, heightRes); + } + + /** + * Set the position of the object area + * + * @param x the x offset + * @param y the y offset + * @param rotation the rotation + */ + public void setObjectAreaPosition(int x, int y, int rotation) { + this.objectAreaPosition = factory.createObjectAreaPosition(x, y, rotation); + } + + /** + * Accessor method to obtain the PageDescriptor object of the + * active environment group. + * + * @return the page descriptor object + */ + public PageDescriptor getPageDescriptor() { + return pageDescriptor; + } + + /** + * Accessor method to obtain the PresentationTextDataDescriptor object of + * the active environment group. + * + * @return the presentation text descriptor + */ + public PresentationTextDescriptor getPresentationTextDataDescriptor() { + return presentationTextDataDescriptor; + } + + /** {@inheritDoc} */ + public void writeContent(OutputStream os) throws IOException { + super.writeTriplets(os); + + writeObjects(mapCodedFonts, os); + writeObjects(mapDataResources, os); + writeObjects(mapPageOverlays, os); + + if (pageDescriptor != null) { + pageDescriptor.writeToStream(os); + } + if (objectAreaDescriptor != null && objectAreaPosition != null) { + objectAreaDescriptor.writeToStream(os); + objectAreaPosition.writeToStream(os); + } + if (presentationTextDataDescriptor != null) { + presentationTextDataDescriptor.writeToStream(os); + } + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.BEGIN, Category.ACTIVE_ENVIRONMENT_GROUP); + os.write(data); + } + + /** {@inheritDoc} */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.END, Category.ACTIVE_ENVIRONMENT_GROUP); + os.write(data); + } + + /** + * Method to create a map coded font object + * + * @param fontRef the font number used as the resource identifier + * @param font the font + * @param size the point size of the font + * @param orientation the orientation of the font (e.g. 0, 90, 180, 270) + */ + public void createFont(int fontRef, AFPFont font, int size, int orientation) { + MapCodedFont mapCodedFont = getCurrentMapCodedFont(); + if (mapCodedFont == null) { + mapCodedFont = factory.createMapCodedFont(); + mapCodedFonts.add(mapCodedFont); + } + + try { + mapCodedFont.addFont(fontRef, font, size, orientation); + } catch (MaximumSizeExceededException msee) { + mapCodedFont = factory.createMapCodedFont(); + mapCodedFonts.add(mapCodedFont); + + try { + mapCodedFont.addFont(fontRef, font, size, orientation); + } catch (MaximumSizeExceededException ex) { + // Should never happen (but log just in case) + log.error("createFont():: resulted in a MaximumSizeExceededException"); + } + } + } + + /** + * Getter method for the most recent MapCodedFont added to the + * Active Environment Group (returns null if no MapCodedFonts exist) + * + * @return the most recent Map Coded Font. + */ + private MapCodedFont getCurrentMapCodedFont() { + int size = mapCodedFonts.size(); + if (size > 0) { + return (MapCodedFont)mapCodedFonts.get(size - 1); + } else { + return null; + } + } + +// private List getMapDataResources() { +// if (mapDataResources == null) { +// mapDataResources = new java.util.ArrayList(); +// } +// return mapDataResources; +//} + +// /** +// * Method to create a map data resource object +// * @param dataObjectAccessor a data object accessor +// */ +// protected void createMapDataResource(DataObjectAccessor dataObjectAccessor) { +// getMapDataResources().add(new MapDataResource(dataObjectAccessor)); +// } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/modca/ContainerDataDescriptor.java b/src/java/org/apache/fop/afp/modca/ContainerDataDescriptor.java new file mode 100644 index 000000000..0f99d6624 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/ContainerDataDescriptor.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * Container data descriptor (to maintain compatibility with pre-year 2000 applications) + */ +public class ContainerDataDescriptor extends AbstractDescriptor { + + /** + * Main constructor + * + * @param width the container data width + * @param height the container data height + * @param widthRes the container width resolution + * @param heightRes the container height resolution + */ + public ContainerDataDescriptor(int width, int height, int widthRes, + int heightRes) { + super(width, height, widthRes, heightRes); + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[21]; + copySF(data, Type.DESCRIPTOR, Category.OBJECT_CONTAINER); + + // SF length + byte[] len = BinaryUtils.convert(data.length - 1, 2); + data[1] = len[0]; + data[2] = len[1]; + + // XocBase = 10 inches + data[9] = 0x00; + + // YocBase = 10 inches + data[10] = 0x00; + + // XocUnits + byte[] xdpi = BinaryUtils.convert(widthRes * 10, 2); + data[11] = xdpi[0]; + data[12] = xdpi[1]; + + // YocUnits + byte[] ydpi = BinaryUtils.convert(heightRes * 10, 2); + data[13] = ydpi[0]; + data[14] = ydpi[1]; + + // XocSize + byte[] xsize = BinaryUtils.convert(width, 3); + data[15] = xsize[0]; + data[16] = xsize[1]; + data[17] = xsize[2]; + + // YocSize + byte[] ysize = BinaryUtils.convert(height, 3); + data[18] = ysize[0]; + data[19] = ysize[1]; + data[20] = ysize[2]; + } + +} diff --git a/src/java/org/apache/fop/afp/modca/Document.java b/src/java/org/apache/fop/afp/modca/Document.java new file mode 100644 index 000000000..02a7b64e1 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/Document.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.Factory; + +/** + * The document is the highest level of the MO:DCA data-stream document + * component hierarchy. Documents can be made up of pages, and the pages, which + * are at the intermediate level, can be made up of objects. Objects are at the + * lowest level, and can be bar codes, graphics, images, and presentation text. + * + * At each level of the hierarchy certain sets of MO:DCA data structures, called + * structured fields, are permissible. The document, pages and objects are + * bounded by structured fields that define their beginnings and their ends. + * These structured fields, called begin-end pairs, provide an envelope for the + * data-stream components. This feature enables a processor of the data stream + * that is not fully compliant with the architecture to bypass those objects + * that are beyond its scope, and to process the data stream to the best of its + * abilities. + * + * A presentation document is one that has been formatted and is intended for + * presentation, usually on a printer or display device. A data stream + * containing a presentation document should produce the same document content + * in the same format on different printers or display devices dependent, + * however, on the capabilities of each of the printers or display devices. A + * presentation document can reference resources that are to be included as part + * of the document to be presented. + * + */ +public final class Document extends AbstractResourceEnvironmentGroupContainer { + + /** + * Constructor for the document object. + * + * @param factory + * the object factory + * @param name + * the name of the document + */ + public Document(Factory factory, String name) { + super(factory, name); + } + + /** + * Method to mark the end of the page group. + */ + public void endDocument() { + complete = true; + } + + /** {@inheritDoc} */ + public boolean isComplete() { + return complete; + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.BEGIN, Category.DOCUMENT); + os.write(data); + } + + /** {@inheritDoc} */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.END, Category.DOCUMENT); + os.write(data); + } + + /** {@inheritDoc} */ + public String toString() { + return this.name; + } + +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/modca/GraphicsDataDescriptor.java b/src/java/org/apache/fop/afp/modca/GraphicsDataDescriptor.java new file mode 100644 index 000000000..5495e2e9c --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/GraphicsDataDescriptor.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * GOCA Graphics Data Descriptor + */ +public class GraphicsDataDescriptor extends AbstractDescriptor { + + private final int xlwind; + + private final int xrwind; + + private final int ybwind; + + private final int ytwind; + + /** + * Main constructor + * + * @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 + * @param widthRes + * the width resolution of the graphics window + * @param heightRes + * the height resolution of the graphics window + */ + public GraphicsDataDescriptor(int xlwind, int xrwind, int ybwind, + int ytwind, int widthRes, int heightRes) { + this.xlwind = xlwind; + this.xrwind = xrwind; + this.ybwind = ybwind; + this.ytwind = ytwind; + super.widthRes = widthRes; + super.heightRes = heightRes; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] headerData = new byte[9]; + copySF(headerData, Type.DESCRIPTOR, Category.GRAPHICS); + + byte[] drawingOrderSubsetData = getDrawingOrderSubset(); + + byte[] windowSpecificationData = getWindowSpecification(); + + byte[] len = BinaryUtils.convert(headerData.length + + drawingOrderSubsetData.length + + windowSpecificationData.length - 1, 2); + headerData[1] = len[0]; + headerData[2] = len[1]; + + os.write(headerData); + os.write(drawingOrderSubsetData); + os.write(windowSpecificationData); + } + + /** + * Returns the drawing order subset data + * + * @return the drawing order subset data + */ + private byte[] getDrawingOrderSubset() { + final byte[] data = new byte[] { + // 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 + }; + return data; + } + + private static final int ABS = 2; + private static final int IMGRES = 8; + + /** + * Returns the window specification data + * + * @return the window specification data + */ + private byte[] getWindowSpecification() { + 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[] xResol = BinaryUtils.convert(widthRes * 10, 2); + byte[] yResol = BinaryUtils.convert(heightRes * 10, 2); + byte[] imxyres = xResol; + + // Window specification + final byte[] data = new byte[] { + (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) + + xResol[0], // XRESOL + xResol[1], + yResol[0], // YRESOL + yResol[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] + }; + return data; + } +} diff --git a/src/java/org/apache/fop/afp/modca/GraphicsObject.java b/src/java/org/apache/fop/afp/modca/GraphicsObject.java new file mode 100644 index 000000000..24b3f949e --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/GraphicsObject.java @@ -0,0 +1,385 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.awt.Color; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.List; + +import org.apache.fop.afp.AFPDataObjectInfo; +import org.apache.fop.afp.AFPObjectAreaInfo; +import org.apache.fop.afp.Completable; +import org.apache.fop.afp.Factory; +import org.apache.fop.afp.StructuredData; +import org.apache.fop.afp.goca.GraphicsAreaBegin; +import org.apache.fop.afp.goca.GraphicsAreaEnd; +import org.apache.fop.afp.goca.GraphicsBox; +import org.apache.fop.afp.goca.GraphicsChainedSegment; +import org.apache.fop.afp.goca.GraphicsCharacterString; +import org.apache.fop.afp.goca.GraphicsData; +import org.apache.fop.afp.goca.GraphicsFillet; +import org.apache.fop.afp.goca.GraphicsFullArc; +import org.apache.fop.afp.goca.GraphicsImage; +import org.apache.fop.afp.goca.GraphicsLine; +import org.apache.fop.afp.goca.GraphicsSetArcParameters; +import org.apache.fop.afp.goca.GraphicsSetCharacterSet; +import org.apache.fop.afp.goca.GraphicsSetCurrentPosition; +import org.apache.fop.afp.goca.GraphicsSetLineType; +import org.apache.fop.afp.goca.GraphicsSetLineWidth; +import org.apache.fop.afp.goca.GraphicsSetPatternSymbol; +import org.apache.fop.afp.goca.GraphicsSetProcessColor; + +/** + * 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 currentData = null; + + /** list of objects contained within this container */ + protected List/*<GraphicsData>*/ objects + = new java.util.ArrayList/*<GraphicsData>*/(); + + /** the graphics state */ + private final GraphicsState graphicsState = new GraphicsState(); + + /** + * Default constructor + * + * @param factory the object factory + * @param name the name of graphics object + */ + public GraphicsObject(Factory factory, String name) { + super(factory, name); + } + + /** {@inheritDoc} */ + public void setViewport(AFPDataObjectInfo dataObjectInfo) { + super.setViewport(dataObjectInfo); + + AFPObjectAreaInfo objectAreaInfo = dataObjectInfo.getObjectAreaInfo(); + int width = objectAreaInfo.getWidth(); + int height = objectAreaInfo.getHeight(); + int widthRes = objectAreaInfo.getWidthRes(); + int heightRes = objectAreaInfo.getHeightRes(); + final int leftEdge = 0; + final int topEdge = 0; + GraphicsDataDescriptor graphicsDataDescriptor = factory.createGraphicsDataDescriptor( + leftEdge, width, topEdge, height, widthRes, heightRes); + + getObjectEnvironmentGroup().setDataDescriptor(graphicsDataDescriptor); + } + + /** {@inheritDoc} */ + public void addObject(StructuredData object) { + if (currentData == null) { + newData(); + } else if (currentData.getDataLength() + object.getDataLength() + >= GraphicsData.MAX_DATA_LEN) { + // graphics data full so transfer current incomplete segment to new data + GraphicsChainedSegment currentSegment + = (GraphicsChainedSegment)currentData.removeCurrentSegment(); + currentSegment.setName(newData().createSegmentName()); + currentData.addSegment(currentSegment); + } + currentData.addObject(object); + } + + /** + * Gets the current graphics data, creating a new one if necessary + * + * @return the current graphics data + */ + private GraphicsData getData() { + if (this.currentData == null) { + return newData(); + } + return this.currentData; + } + + /** + * Creates a new graphics data + * + * @return a newly created graphics data + */ + private GraphicsData newData() { + if (currentData != null) { + currentData.setComplete(true); + } + this.currentData = factory.createGraphicsData(); + objects.add(currentData); + return currentData; + } + + /** + * Sets the current color + * + * @param color the active color to use + */ + public void setColor(Color color) { + if (!color.equals(graphicsState.color)) { + addObject(new GraphicsSetProcessColor(color)); + graphicsState.color = color; + } + } + + /** + * Sets the current position + * + * @param coords the x and y coordinates of the current position + */ + public void setCurrentPosition(int[] coords) { + addObject(new GraphicsSetCurrentPosition(coords)); + } + + /** + * Sets the line width + * + * @param lineWidth the line width multiplier + */ + public void setLineWidth(int lineWidth) { + if (lineWidth != graphicsState.lineWidth) { + addObject(new GraphicsSetLineWidth(lineWidth)); + graphicsState.lineWidth = lineWidth; + } + } + + /** + * Sets the line type + * + * @param lineType the line type + */ + public void setLineType(byte lineType) { + if (lineType != graphicsState.lineType) { + addObject(new GraphicsSetLineType(lineType)); + graphicsState.lineType = lineType; + } + } + + /** + * Sets whether the following shape is to be filled + * + * @param fill true if the following shape is to be filled + */ + public void setFill(boolean fill) { + setPatternSymbol(fill ? + GraphicsSetPatternSymbol.SOLID_FILL : + GraphicsSetPatternSymbol.NO_FILL); + } + + /** + * Sets the fill pattern of the next shape + * + * @param the fill pattern of the next shape + */ + public void setPatternSymbol(byte patternSymbol) { + if (patternSymbol != graphicsState.patternSymbol) { + addObject(new GraphicsSetPatternSymbol(patternSymbol)); + graphicsState.patternSymbol = patternSymbol; + } + } + + /** + * Sets the character set to use + * + * @param characterSet the character set (font) reference + */ + public void setCharacterSet(int characterSet) { + if (characterSet != graphicsState.characterSet) { + addObject(new GraphicsSetCharacterSet(characterSet)); + graphicsState.characterSet = characterSet; + } + } + + /** + * Adds a line at the given x/y coordinates + * + * @param coords the x/y coordinates (can be a series) + */ + public void addLine(int[] coords) { + addLine(coords, false); + } + + /** + * Adds a line at the given x/y coordinates + * + * @param coords the x/y coordinates (can be a series) + * @param relative relative true for a line at current position (relative to) + */ + public void addLine(int[] coords, boolean relative) { + addObject(new GraphicsLine(coords, relative)); + } + + /** + * Adds a box at the given coordinates + * + * @param coords the x/y coordinates + */ + public void addBox(int[] coords) { + addObject(new GraphicsBox(coords)); + } + + /** + * Adds a fillet (curve) at the given coordinates + * + * @param coords the x/y coordinates + */ + public void addFillet(int[] coords) { + addFillet(coords, false); + } + + /** + * Adds a fillet (curve) at the given coordinates + * + * @param coords the x/y coordinates + * @param relative relative true for a fillet (curve) at current position (relative to) + */ + public void addFillet(int[] coords, boolean relative) { + addObject(new GraphicsFillet(coords, relative)); + } + + /** + * 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) { + addObject(new GraphicsSetArcParameters(xmaj, ymin, xmin, ymaj)); + } + + /** + * Adds a full 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) { + addObject(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 imgData the image data + */ + public void addImage(int x, int y, int width, int height, byte[] imgData) { + addObject(new GraphicsImage(x, y, width, height, imgData)); + } + + /** + * 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) { + addObject(new GraphicsCharacterString(str, x, y)); + } + + /** + * Begins a graphics area (start of fill) + */ + public void beginArea() { + addObject(new GraphicsAreaBegin()); + } + + /** + * Ends a graphics area (end of fill) + */ + public void endArea() { + addObject(new GraphicsAreaEnd()); + } + + /** {@inheritDoc} */ + public String toString() { + return "GraphicsObject: " + getName(); + } + + /** + * Creates a new graphics segment + */ + public void newSegment() { + getData().newSegment(); + } + + /** {@inheritDoc} */ + public void setComplete(boolean complete) { + Iterator it = objects.iterator(); + while (it.hasNext()) { + Completable completedObject = (Completable)it.next(); + completedObject.setComplete(true); + } + super.setComplete(complete); + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + super.writeStart(os); + byte[] data = new byte[17]; + copySF(data, Type.BEGIN, Category.GRAPHICS); + os.write(data); + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + super.writeContent(os); + writeObjects(objects, os); + } + + /** {@inheritDoc} */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.END, Category.GRAPHICS); + os.write(data); + } + + /** the internal graphics state */ + private class GraphicsState { + /** the current color */ + private Color color; + + /** the current line type */ + private byte lineType; + + /** the current line width */ + private int lineWidth; + + /** the current fill pattern */ + private byte patternSymbol; + + /** the current character set */ + private int characterSet; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/IMImageObject.java b/src/java/org/apache/fop/afp/modca/IMImageObject.java index bb43950dd..a09042441 100644 --- a/src/java/org/apache/fop/render/afp/modca/IMImageObject.java +++ b/src/java/org/apache/fop/afp/modca/IMImageObject.java @@ -17,11 +17,16 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.modca; import java.io.IOException; import java.io.OutputStream; +import org.apache.fop.afp.ioca.ImageCellPosition; +import org.apache.fop.afp.ioca.ImageInputDescriptor; +import org.apache.fop.afp.ioca.ImageOutputControl; +import org.apache.fop.afp.ioca.ImageRasterData; + /** * An IM image data object specifies the contents of a raster image and * its placement on a page, overlay, or page segment. An IM image can be @@ -60,16 +65,16 @@ public class IMImageObject extends AbstractNamedAFPObject { /** * Constructor for the image object with the specified name, * the name must be a fixed length of eight characters. + * * @param name The name of the image. */ public IMImageObject(String name) { - super(name); - } /** * Sets the ImageOutputControl. + * * @param imageOutputControl The imageOutputControl to set */ public void setImageOutputControl(ImageOutputControl imageOutputControl) { @@ -78,6 +83,7 @@ public class IMImageObject extends AbstractNamedAFPObject { /** * Sets the ImageCellPosition. + * * @param imageCellPosition The imageCellPosition to set */ public void setImageCellPosition(ImageCellPosition imageCellPosition) { @@ -86,6 +92,7 @@ public class IMImageObject extends AbstractNamedAFPObject { /** * Sets the ImageInputDescriptor. + * * @param imageInputDescriptor The imageInputDescriptor to set */ public void setImageInputDescriptor(ImageInputDescriptor imageInputDescriptor) { @@ -94,98 +101,41 @@ public class IMImageObject extends AbstractNamedAFPObject { /** * Sets the ImageRastorData. + * * @param imageRasterData The imageRasterData to set */ public void setImageRasterData(ImageRasterData imageRasterData) { this.imageRasterData = imageRasterData; } - /** - * Accessor method to write the AFP datastream for the IM Image Objetc - * @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 { - - writeStart(os); - + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + super.writeContent(os); if (imageOutputControl != null) { - imageOutputControl.writeDataStream(os); + imageOutputControl.writeToStream(os); } - if (imageInputDescriptor != null) { - imageInputDescriptor.writeDataStream(os); + imageInputDescriptor.writeToStream(os); } - if (imageCellPosition != null) { - imageCellPosition.writeDataStream(os); + imageCellPosition.writeToStream(os); } - if (imageRasterData != null) { - imageRasterData.writeDataStream(os); + imageRasterData.writeToStream(os); } - - writeEnd(os); - } - /** - * Helper method to write the start of the IM Image Object. - * @param os The stream to write to - */ - private void writeStart(OutputStream os) - throws IOException { - + /** {@inheritDoc} */ + 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 - data[3] = (byte) 0xD3; // Structured field id byte 1 - data[4] = (byte) 0xA8; // Structured field id byte 2 - data[5] = (byte) 0x7B; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - + copySF(data, Type.BEGIN, Category.IM_IMAGE); os.write(data); - } - /** - * Helper method to write the end of the IM Image Object. - * @param os The stream to write to - */ - private void writeEnd(OutputStream os) - throws IOException { - + /** {@inheritDoc} */ + 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 - data[3] = (byte) 0xD3; // Structured field id byte 1 - data[4] = (byte) 0xA9; // Structured field id byte 2 - data[5] = (byte) 0x7B; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - + copySF(data, Type.END, Category.IM_IMAGE); os.write(data); - } - } diff --git a/src/java/org/apache/fop/afp/modca/ImageDataDescriptor.java b/src/java/org/apache/fop/afp/modca/ImageDataDescriptor.java new file mode 100644 index 000000000..07976e18a --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/ImageDataDescriptor.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * ImageDataDescriptor + */ +public class ImageDataDescriptor extends AbstractDescriptor { + + /** + * Constructor for a ImageDataDescriptor for the specified + * resolution, width and height. + * + * @param width The width of the image. + * @param height The height of the height. + * @param widthRes The horizontal resolution of the image. + * @param heightRes The vertical resolution of the image. + */ + public ImageDataDescriptor(int width, int height, int widthRes, int heightRes) { + super(width, height, widthRes, heightRes); + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[22]; + copySF(data, Type.DESCRIPTOR, Category.IMAGE); + + // SF length + byte[] len = BinaryUtils.convert(data.length - 1, 2); + data[1] = len[0]; + data[2] = len[1]; + + byte[] x = BinaryUtils.convert(widthRes, 2); + data[10] = x[0]; + data[11] = x[1]; + + byte[] y = BinaryUtils.convert(heightRes, 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]; + + data[18] = (byte)0xF7; // ID = Set IOCA Function Set + data[19] = 0x02; // Length + data[20] = 0x01; // Category = Function set identifier + data[21] = 0x0B; // FCNSET = IOCA FS 11 + + os.write(data); + } +} diff --git a/src/java/org/apache/fop/afp/modca/ImageObject.java b/src/java/org/apache/fop/afp/modca/ImageObject.java new file mode 100644 index 000000000..24ac0cb22 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/ImageObject.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.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.commons.io.output.ByteArrayOutputStream; +import org.apache.fop.afp.AFPDataObjectInfo; +import org.apache.fop.afp.AFPImageObjectInfo; +import org.apache.fop.afp.Factory; +import org.apache.fop.afp.ioca.ImageSegment; + +/** + * An IOCA Image Data Object + */ +public class ImageObject extends AbstractDataObject { + + private static final int MAX_DATA_LEN = 32759; + + /** the image segment */ + private ImageSegment imageSegment = null; + + /** + * Constructor for the image object with the specified name, + * the name must be a fixed length of eight characters. + * + * @param name The name of the image. + * @param factory the resource manager + */ + public ImageObject(Factory factory, String name) { + super(factory, name); + } + + private ImageSegment getImageSegment() { + if (imageSegment == null) { + this.imageSegment = factory.createImageSegment(); + } + return imageSegment; + } + + /** {@inheritDoc} */ + public void setViewport(AFPDataObjectInfo dataObjectInfo) { + super.setViewport(dataObjectInfo); + + AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)dataObjectInfo; + int dataWidth = imageObjectInfo.getDataWidth(); + int dataHeight = imageObjectInfo.getDataHeight(); + +// AFPObjectAreaInfo objectAreaInfo = dataObjectInfo.getObjectAreaInfo(); +// int widthRes = objectAreaInfo.getWidthRes(); +// int heightRes = objectAreaInfo.getHeightRes(); + + int dataWidthRes = imageObjectInfo.getDataWidthRes(); + int dataHeightRes = imageObjectInfo.getDataWidthRes(); + ImageDataDescriptor imageDataDescriptor + = factory.createImageDataDescriptor(dataWidth, dataHeight, dataWidthRes, dataHeightRes); + getObjectEnvironmentGroup().setDataDescriptor(imageDataDescriptor); + + getImageSegment().setImageSize(dataWidth, dataHeight, dataWidthRes, dataHeightRes); + } + + /** + * Sets the image encoding. + * + * @param encoding The image encoding. + */ + public void setEncoding(byte encoding) { + getImageSegment().setEncoding(encoding); + } + + /** + * Sets the image compression. + * + * @param compression The image compression. + */ + public void setCompression(byte compression) { + getImageSegment().setCompression(compression); + } + + /** + * Sets the image IDE size. + * + * @param size The IDE size. + */ + public void setIDESize(byte size) { + getImageSegment().setIDESize(size); + } + + /** + * Sets the image IDE color model. + * + * @param colorModel the IDE color model. + */ + public void setIDEColorModel(byte colorModel) { + getImageSegment().setIDEColorModel(colorModel); + } + + /** + * Set the data of the image. + * + * @param data the image data + */ + public void setData(byte[] imageData) { + getImageSegment().setData(imageData); + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.BEGIN, Category.IMAGE); + os.write(data); + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + super.writeContent(os); + + if (imageSegment != null) { + final byte[] dataHeader = new byte[9]; + copySF(dataHeader, SF_CLASS, Type.DATA, Category.IMAGE); + final int lengthOffset = 1; + + // TODO save memory! + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + imageSegment.writeToStream(baos); + byte[] data = baos.toByteArray(); + writeChunksToStream(data, dataHeader, lengthOffset, MAX_DATA_LEN, os); + } + } + + /** {@inheritDoc} */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.END, Category.IMAGE); + os.write(data); + } +} diff --git a/src/java/org/apache/fop/afp/modca/IncludeObject.java b/src/java/org/apache/fop/afp/modca/IncludeObject.java new file mode 100644 index 000000000..2dff6bd87 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/IncludeObject.java @@ -0,0 +1,301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.modca.triplets.MappingOptionTriplet; +import org.apache.fop.afp.modca.triplets.MeasurementUnitsTriplet; +import org.apache.fop.afp.modca.triplets.ObjectAreaSizeTriplet; +import org.apache.fop.afp.util.BinaryUtils; + +/** + * An Include Object structured field references an object on a page or overlay. + * It optionally contains parameters that identify the object and that specify + * presentation parameters such as object position, size, orientation, mapping, + * and default color. + * <p> + * Where the presentation parameters conflict with parameters specified in the + * object's environment group (OEG), the parameters in the Include Object + * structured field override. If the referenced object is a page segment, the + * IOB parameters override the corresponding environment group parameters on all + * data objects in the page segment. + * </p> + */ +public class IncludeObject extends AbstractNamedAFPObject { + + /** the object referenced is of type page segment */ + public static final byte TYPE_PAGE_SEGMENT = (byte)0x5F; + + /** the object referenced is of type other */ + public static final byte TYPE_OTHER = (byte)0x92; + + /** the object referenced is of type graphic */ + public static final byte TYPE_GRAPHIC = (byte)0xBB; + + /** the object referenced is of type barcode */ + public static final byte TYPE_BARCODE = (byte)0xEB; + + /** the object referenced is of type image */ + public static final byte TYPE_IMAGE = (byte)0xFB; + + + /** the object type referenced (default is other) */ + private byte objectType = TYPE_OTHER; + + /** the X-axis origin of the object area */ + private int xoaOset = 0; + + /** the Y-axis origin of the object area */ + private int yoaOset = 0; + + /** the orientation of the referenced object */ + private int oaOrent = 0; + + /** the X-axis origin defined in the object */ + private int xocaOset = -1; + + /** the Y-axis origin defined in the object */ + private int yocaOset = -1; + + /** + * Constructor for the include object with the specified name, the name must + * be a fixed length of eight characters and is the name of the referenced + * object. + * + * @param name the name of this include object + */ + public IncludeObject(String name) { + super(name); + } + + /** + * Sets the orientation to use for the Include Object. + * + * @param orientation + * The orientation (0,90, 180, 270) + */ + public void setObjectAreaOrientation(int orientation) { + if (orientation == 0 || orientation == 90 || orientation == 180 + || orientation == 270) { + this.oaOrent = orientation; + } else { + throw new IllegalArgumentException( + "The orientation must be one of the values 0, 90, 180, 270"); + } + } + + /** + * Sets the x and y offset to the origin in the object area + * + * @param x the X-axis origin of the object area + * @param y the Y-axis origin of the object area + */ + public void setObjectAreaOffset(int x, int y) { + this.xoaOset = x; + this.yoaOset = y; + } + + /** + * Sets the x and y offset of the content area to the object area + * used in conjunction with the {@link MappingOptionTriplet.POSITION} and + * {@link MappingOptionTriplet.POSITION_AND_TRIM}. + * + * @param x the X-axis origin defined in the object + * @param y the Y-axis origin defined in the object + */ + public void setContentAreaOffset(int x, int y) { + this.xocaOset = x; + this.yocaOset = y; + } + + /** + * Sets the data object type + * + * @param type the data object type + */ + public void setObjectType(byte type) { + this.objectType = type; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[36]; + super.copySF(data, Type.INCLUDE, Category.DATA_RESOURCE); + + // Set the total record length + int tripletDataLength = getTripletDataLength(); + byte[] len = BinaryUtils.convert(35 + tripletDataLength, 2); //Ignore first byte + data[1] = len[0]; + data[2] = len[1]; + + data[17] = 0x00; // reserved + data[18] = objectType; + + //XoaOset (object area) + if (xoaOset > -1) { + byte[] x = BinaryUtils.convert(xoaOset, 3); + data[19] = x[0]; + data[20] = x[1]; + data[21] = x[2]; + } else { + data[19] = (byte)0xFF; + data[20] = (byte)0xFF; + data[21] = (byte)0xFF; + } + + // YoaOset (object area) + if (yoaOset > -1) { + byte[] y = BinaryUtils.convert(yoaOset, 3); + data[22] = y[0]; + data[23] = y[1]; + data[24] = y[2]; + } else { + data[22] = (byte)0xFF; + data[23] = (byte)0xFF; + data[24] = (byte)0xFF; + } + + // XoaOrent/YoaOrent + switch (oaOrent) { + case -1: // use x/y axis orientation defined in object + data[25] = (byte)0xFF; // x axis rotation + data[26] = (byte)0xFF; // + data[27] = (byte)0xFF; // y axis rotation + data[28] = (byte)0xFF; + break; + case 90: + data[25] = 0x2D; + data[26] = 0x00; + data[27] = 0x5A; + data[28] = 0x00; + break; + case 180: + data[25] = 0x5A; + data[25] = 0x00; + data[27] = (byte)0x87; + data[28] = 0x00; + break; + case 270: + data[25] = (byte)0x87; + data[26] = 0x00; + data[27] = 0x00; + data[28] = 0x00; + break; + default: // 0 degrees + data[25] = 0x00; + data[26] = 0x00; + data[27] = 0x2D; + data[28] = 0x00; + break; + } + + // XocaOset (object content) + if (xocaOset > -1) { + byte[] x = BinaryUtils.convert(xocaOset, 3); + data[29] = x[0]; + data[30] = x[1]; + data[31] = x[2]; + } else { + data[29] = (byte)0xFF; + data[30] = (byte)0xFF; + data[31] = (byte)0xFF; + } + + // YocaOset (object content) + if (yocaOset > -1) { + byte[] y = BinaryUtils.convert(yocaOset, 3); + data[32] = y[0]; + data[33] = y[1]; + data[34] = y[2]; + } else { + data[32] = (byte)0xFF; + data[33] = (byte)0xFF; + data[34] = (byte)0xFF; + } + // RefCSys (Reference coordinate system) + data[35] = 0x01; // Page or overlay coordinate system + + // Write structured field data + os.write(data); + + // Write triplet for FQN internal/external object reference + writeTriplets(os); + } + + private String getObjectTypeName() { + String objectTypeName = null; + if (objectType == TYPE_PAGE_SEGMENT) { + objectTypeName = "page segment"; + } else if (objectType == TYPE_OTHER) { + objectTypeName = "other"; + } else if (objectType == TYPE_GRAPHIC) { + objectTypeName = "graphic"; + } else if (objectType == TYPE_BARCODE) { + objectTypeName = "barcode"; + } else if (objectType == TYPE_IMAGE) { + objectTypeName = "image"; + } + return objectTypeName; + } + + /** {@inheritDoc} */ + public String toString() { + return "IncludeObject{name=" + this.getName() + + ", objectType=" + getObjectTypeName() + + ", xoaOset=" + xoaOset + + ", yoaOset=" + yoaOset + + ", oaOrent" + oaOrent + + ", xocaOset=" + xocaOset + + ", yocaOset=" + yocaOset + + "}"; + } + + /** + * Sets the mapping option + * + * @param optionValue the mapping option value + */ + public void setMappingOption(byte optionValue) { + addTriplet(new MappingOptionTriplet(optionValue)); + } + + /** + * Sets the extent of an object area in the X and Y directions + * + * @param x the x direction extent + * @param y the y direction extent + */ + public void setObjectAreaSize(int x, int y) { + addTriplet(new ObjectAreaSizeTriplet(x, y)); + } + + /** + * Sets the measurement units used to specify the units of measure + * + * @param xRes units per base on the x-axis + * @param yRes units per base on the y-axis + */ + public void setMeasurementUnits(int xRes, int yRes) { + addTriplet(new MeasurementUnitsTriplet(xRes, xRes)); + } + +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/IncludePageOverlay.java b/src/java/org/apache/fop/afp/modca/IncludePageOverlay.java index 7c52fe0a2..44f0edc5b 100644 --- a/src/java/org/apache/fop/render/afp/modca/IncludePageOverlay.java +++ b/src/java/org/apache/fop/afp/modca/IncludePageOverlay.java @@ -17,12 +17,12 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.modca; import java.io.IOException; import java.io.OutputStream; -import org.apache.fop.render.afp.tools.BinaryUtils; +import org.apache.fop.afp.util.BinaryUtils; /** * @@ -56,6 +56,7 @@ public class IncludePageOverlay extends AbstractNamedAFPObject { /** * Constructor for the Include Page Overlay + * * @param overlayName Name of the page segment * @param x The x position * @param y The y position @@ -63,13 +64,14 @@ public class IncludePageOverlay extends AbstractNamedAFPObject { */ public IncludePageOverlay(String overlayName, int x, int y, int orientation) { super(overlayName); + this.x = x; this.y = y; setOrientation(orientation); } /** - * Sets the orienation to use for the overlay. + * Sets the orientation to use for the overlay. * * @param orientation * The orientation (0,90, 180, 270) @@ -84,45 +86,25 @@ public class IncludePageOverlay extends AbstractNamedAFPObject { } } - /** - * Accessor method to write the AFP datastream for the Include Page Overlay - * @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 { - + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { byte[] data = new byte[25]; //(9 +16) - - data[0] = 0x5A; + copySF(data, Type.INCLUDE, Category.PAGE_OVERLAY); // Set the total record length byte[] len = BinaryUtils.convert(24, 2); //Ignore first byte data[1] = len[0]; data[2] = len[1]; - // Structured field ID for a IPO - data[3] = (byte) 0xD3; - data[4] = (byte) 0xAF; - data[5] = (byte) 0xD8; - - data[6] = 0x00; // Reserved - data[7] = 0x00; // Reserved - data[8] = 0x00; // Reserved - - for (int i = 0; i < nameBytes.length; i++) { - data[9 + i] = nameBytes[i]; - } - - byte[] xcoord = BinaryUtils.convert(x, 3); - data[17] = xcoord[0]; // x coordinate - data[18] = xcoord[1]; - data[19] = xcoord[2]; + byte[] xPos = BinaryUtils.convert(x, 3); + data[17] = xPos[0]; // x coordinate + data[18] = xPos[1]; + data[19] = xPos[2]; - byte[] ycoord = BinaryUtils.convert(y, 3); - data[20] = ycoord[0]; // y coordinate - data[21] = ycoord[1]; - data[22] = ycoord[2]; + byte[] yPos = BinaryUtils.convert(y, 3); + data[20] = yPos[0]; // y coordinate + data[21] = yPos[1]; + data[22] = yPos[2]; switch (orientation) { case 90: diff --git a/src/java/org/apache/fop/render/afp/modca/IncludePageSegment.java b/src/java/org/apache/fop/afp/modca/IncludePageSegment.java index 7792a7162..7355e3b1a 100644 --- a/src/java/org/apache/fop/render/afp/modca/IncludePageSegment.java +++ b/src/java/org/apache/fop/afp/modca/IncludePageSegment.java @@ -17,12 +17,12 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.modca; import java.io.IOException; import java.io.OutputStream; -import org.apache.fop.render.afp.tools.BinaryUtils; +import org.apache.fop.afp.util.BinaryUtils; /** * The Include Page Segment structured field references a page segment resource @@ -45,64 +45,46 @@ public class IncludePageSegment extends AbstractNamedAFPObject { /** * The x position where we need to put this object on the page */ - private byte[] x; - + private int x; + /** * The y position where we need to put this object on the page */ - private byte[] y; - + private int y; + /** * Constructor for the Include Page Segment + * * @param name Name of the page segment * @param x The x position * @param y The y position */ public IncludePageSegment(String name, int x, int y) { - super(name); - this.x = BinaryUtils.convert(x, 3); - this.y = BinaryUtils.convert(y, 3); - + + this.x = x; + this.y = y; } - /** - * Accessor method to write the AFP datastream for the Include Page Segment - * @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 { - + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { byte[] data = new byte[23]; //(9 +14) - - data[0] = 0x5A; + copySF(data, Type.INCLUDE, Category.PAGE_SEGMENT); // Set the total record length - byte[] rl1 = BinaryUtils.convert(22, 2); //Ignore first byte - data[1] = rl1[0]; - data[2] = rl1[1]; - - // Structured field ID for a IPS - data[3] = (byte) 0xD3; - data[4] = (byte) 0xAF; - data[5] = (byte) 0x5F; - - data[6] = 0x00; // Reserved - data[7] = 0x00; // Reserved - data[8] = 0x00; // Reserved - - for (int i = 0; i < nameBytes.length; i++) { - data[9 + i] = nameBytes[i]; - } - - data[17] = x[0]; // x coordinate - data[18] = x[1]; - data[19] = x[2]; - - data[20] = y[0]; // y coordinate - data[21] = y[1]; - data[22] = y[2]; + byte[] len = BinaryUtils.convert(22, 2); //Ignore first byte + data[1] = len[0]; + data[2] = len[1]; + + byte[] xPos = BinaryUtils.convert(x, 3); + data[17] = xPos[0]; // x coordinate + data[18] = xPos[1]; + data[19] = xPos[2]; + + byte[] yPos = BinaryUtils.convert(y, 3); + data[20] = yPos[0]; // y coordinate + data[21] = yPos[1]; + data[22] = yPos[2]; os.write(data); } diff --git a/src/java/org/apache/fop/afp/modca/InterchangeSet.java b/src/java/org/apache/fop/afp/modca/InterchangeSet.java new file mode 100644 index 000000000..28a4da42b --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/InterchangeSet.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.afp.modca; + +/** + * MO:DCA Interchange Set + */ +public class InterchangeSet { + /** interchange set 1 string value */ + public static final String MODCA_PRESENTATION_INTERCHANGE_SET_1 = "MO:DCA-P IS/1"; + + /** interchange set 2 string value */ + public static final String MODCA_PRESENTATION_INTERCHANGE_SET_2 = "MO:DCA-P IS/2"; + + /** resource interchange set string value */ + public static final String MODCA_RESOURCE_INTERCHANGE_SET = "MO:DCA-L"; + + private static final String[] NAMES = { + MODCA_PRESENTATION_INTERCHANGE_SET_1, + MODCA_PRESENTATION_INTERCHANGE_SET_2, + MODCA_RESOURCE_INTERCHANGE_SET + }; + + private static final int SET_1 = 0; + private static final int SET_2 = 1; + private static final int RESOURCE_SET = 2; + + /** the actual interchange set in use */ + private int value; + + /** + * Returns the interchange set value of a given string + * + * @param str an interchange set value + * @return an interchange set + */ + public static InterchangeSet valueOf(String str) { + if (MODCA_PRESENTATION_INTERCHANGE_SET_1.equals(str)) { + return new InterchangeSet(SET_1); + } else if (MODCA_PRESENTATION_INTERCHANGE_SET_2.equals(str)) { + return new InterchangeSet(SET_2); + } else if (MODCA_RESOURCE_INTERCHANGE_SET.equals(str)) { + return new InterchangeSet(RESOURCE_SET); + } else { + throw new IllegalArgumentException("Invalid MO:DCA interchange set :" + str); + } + } + + /** + * Main constructor + * + * @param value the interchange set value + */ + public InterchangeSet(int value) { + this.value = value; + } + + /** + * Returns true if complies with MOD:CA interchange set 1 + * + * @return true if complies with MOD:CA interchange set 1 + */ + protected boolean is1() { + return value == SET_1; + } + + /** + * Returns true if complies with MOD:CA interchange set 2 + * + * @return true if complies with MOD:CA interchange set 2 + */ + public boolean is2() { + return value == SET_2; + } + + /** + * Returns true if complies with MOD:CA resource set + * + * @return true if complies with MOD:CA resource set + */ + public boolean isResource() { + return value == RESOURCE_SET; + } + + /** {@inheritDoc} */ + public String toString() { + return NAMES[value]; + } + + /** + * Returns true if MOD:CA interchange set 2 (resource groups) is supported + * + * @return true if MOD:CA interchange set 2 (resource groups) is supported + */ + public boolean supportsLevel2() { + return is2() || isResource(); + } +} diff --git a/src/java/org/apache/fop/render/afp/modca/InvokeMediumMap.java b/src/java/org/apache/fop/afp/modca/InvokeMediumMap.java index f38096ade..f910a0b9c 100644 --- a/src/java/org/apache/fop/render/afp/modca/InvokeMediumMap.java +++ b/src/java/org/apache/fop/afp/modca/InvokeMediumMap.java @@ -17,12 +17,12 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.modca; import java.io.IOException; import java.io.OutputStream; -import org.apache.fop.render.afp.tools.BinaryUtils; +import org.apache.fop.afp.util.BinaryUtils; /** * The Invoke Medium Map structured field identifies the Medium Map that is to @@ -34,48 +34,24 @@ public class InvokeMediumMap extends AbstractNamedAFPObject { /** * Constructor for the Invoke Medium Map - * @param mediumMapName Name of the medium map + * + * @param name the name of the medium map */ - public InvokeMediumMap(String mediumMapName) { - - super(mediumMapName); - + public InvokeMediumMap(String name) { + super(name); } - /** - * Accessor method to write the AFP datastream for the Invoke Medium Map - * @param os The stream to write to - * @throws java.io.IOException if an I/O exception of some sort has occurred - */ - public void writeDataStream(OutputStream os) - throws IOException { + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { byte[] data = new byte[17]; - - data[0] = 0x5A; + copySF(data, Type.MAP, Category.MEDIUM_MAP); // Set the total record length - byte[] rl1 = BinaryUtils.convert(16, 2); //Ignore first byte - data[1] = rl1[0]; - data[2] = rl1[1]; - - // Structured field ID for a IPO - data[3] = (byte) 0xD3; - data[4] = (byte) 0xAB; - data[5] = (byte) 0xCC; - - data[6] = 0x00; // Reserved - data[7] = 0x00; // Reserved - data[8] = 0x00; // Reserved - - for (int i = 0; i < nameBytes.length; i++) { - - data[9 + i] = nameBytes[i]; - - } + byte[] len = BinaryUtils.convert(16, 2); //Ignore first byte + data[1] = len[0]; + data[2] = len[1]; os.write(data); - } - }
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/MapCodedFont.java b/src/java/org/apache/fop/afp/modca/MapCodedFont.java index f0f372fcb..54b4d1796 100644 --- a/src/java/org/apache/fop/render/afp/modca/MapCodedFont.java +++ b/src/java/org/apache/fop/afp/modca/MapCodedFont.java @@ -17,7 +17,7 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.modca; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -26,12 +26,13 @@ import java.io.UnsupportedEncodingException; import java.util.Iterator; import java.util.List; -import org.apache.fop.render.afp.exceptions.FontRuntimeException; -import org.apache.fop.render.afp.fonts.AFPFont; -import org.apache.fop.render.afp.fonts.CharacterSet; -import org.apache.fop.render.afp.fonts.OutlineFont; -import org.apache.fop.render.afp.fonts.RasterFont; -import org.apache.fop.render.afp.tools.BinaryUtils; +import org.apache.fop.afp.AFPConstants; +import org.apache.fop.afp.fonts.AFPFont; +import org.apache.fop.afp.fonts.CharacterSet; +import org.apache.fop.afp.fonts.FontRuntimeException; +import org.apache.fop.afp.fonts.OutlineFont; +import org.apache.fop.afp.fonts.RasterFont; +import org.apache.fop.afp.util.BinaryUtils; /** * The Map Coded Font structured field maps a unique coded font resource local @@ -39,46 +40,29 @@ import org.apache.fop.render.afp.tools.BinaryUtils; * descriptor, to the identifier of a coded font resource object. Additionally, * the Map Coded Font structured field specifies a set of resource attributes * for the coded font. - * - * @author <a href="mailto:pete@townsend.uk.com">Pete Townsend </a> */ -public class MapCodedFont extends AbstractAFPObject { +public class MapCodedFont extends AbstractStructuredObject { - /** - * The collection of map coded fonts (maximum of 254) - */ - private List fontList = null; + /** the collection of map coded fonts (maximum of 254) */ + private final List/*<FontDefinition>*/ fontList + = new java.util.ArrayList/*<FontDefinition>*/(); /** - * Constructor for the MapCodedFont + * Main constructor */ public MapCodedFont() { - - fontList = new java.util.ArrayList(); - } - /** - * Accessor method to write the AFP datastream for the Map Coded Font - * @param os The stream to write to - * @throws java.io.IOException an I/O exception of some sort has occurred - */ - public void writeDataStream(OutputStream os) throws IOException { - + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - baos.write(0x5A); - baos.write(new byte[] {0x00, 0x00}); - - // Field identifier for a MapCodedFont - baos.write(new byte[] {(byte) 0xD3, (byte) 0xAB, (byte) 0x8A}); - - // Reserved - baos.write(new byte[] {0x00, 0x00, 0x00}); + byte[] startData = new byte[9]; + copySF(startData, Type.MAP, Category.CODED_FONT); + baos.write(startData); Iterator iter = fontList.iterator(); while (iter.hasNext()) { - FontDefinition fd = (FontDefinition) iter.next(); // Start of repeating groups (occurs 1 to 254) @@ -138,7 +122,6 @@ public class MapCodedFont extends AbstractAFPObject { baos.write(0x5D); baos.write(BinaryUtils.convert(fd.scale, 2)); } - } byte[] data = baos.toByteArray(); @@ -149,7 +132,6 @@ public class MapCodedFont extends AbstractAFPObject { data[2] = rl1[1]; os.write(data); - } /** @@ -168,29 +150,27 @@ public class MapCodedFont extends AbstractAFPObject { public void addFont(int fontReference, AFPFont font, int size, int orientation) throws MaximumSizeExceededException { - FontDefinition fd = new FontDefinition(); + FontDefinition fontDefinition = new FontDefinition(); - fd.fontReferenceKey = BinaryUtils.convert(fontReference)[0]; + fontDefinition.fontReferenceKey = BinaryUtils.convert(fontReference)[0]; switch (orientation) { case 90: - fd.orientation = 0x2D; + fontDefinition.orientation = 0x2D; break; case 180: - fd.orientation = 0x5A; + fontDefinition.orientation = 0x5A; break; case 270: - fd.orientation = (byte) 0x87; + fontDefinition.orientation = (byte) 0x87; break; default: - fd.orientation = 0x00; + fontDefinition.orientation = 0x00; break; } try { - if (font instanceof RasterFont) { - RasterFont raster = (RasterFont) font; CharacterSet cs = raster.getCharacterSet(size); if (cs == null) { @@ -200,45 +180,43 @@ public class MapCodedFont extends AbstractAFPObject { throw new FontRuntimeException(msg); } - fd.characterSet = cs.getNameBytes(); + fontDefinition.characterSet = cs.getNameBytes(); - if (fd.characterSet.length != 8) { + if (fontDefinition.characterSet.length != 8) { throw new IllegalArgumentException("The character set " - + new String(fd.characterSet, + + new String(fontDefinition.characterSet, AFPConstants.EBCIDIC_ENCODING) + " must have a fixed length of 8 characters."); } - fd.codePage = cs.getCodePage().getBytes( + fontDefinition.codePage = cs.getCodePage().getBytes( AFPConstants.EBCIDIC_ENCODING); - if (fd.codePage.length != 8) { + if (fontDefinition.codePage.length != 8) { throw new IllegalArgumentException("The code page " - + new String(fd.codePage, + + new String(fontDefinition.codePage, AFPConstants.EBCIDIC_ENCODING) + " must have a fixed length of 8 characters."); } } else if (font instanceof OutlineFont) { - OutlineFont outline = (OutlineFont) font; CharacterSet cs = outline.getCharacterSet(); - fd.characterSet = cs.getNameBytes(); + fontDefinition.characterSet = cs.getNameBytes(); // There are approximately 72 points to 1 inch or 20 1440ths per point. - fd.scale = ((size / 1000) * 20); + fontDefinition.scale = ((size / 1000) * 20); - fd.codePage = cs.getCodePage().getBytes( + fontDefinition.codePage = cs.getCodePage().getBytes( AFPConstants.EBCIDIC_ENCODING); - if (fd.codePage.length != 8) { + if (fontDefinition.codePage.length != 8) { throw new IllegalArgumentException("The code page " - + new String(fd.codePage, + + new String(fontDefinition.codePage, AFPConstants.EBCIDIC_ENCODING) + " must have a fixed length of 8 characters."); } - } else { String msg = "Font of type " + font.getClass().getName() + " not recognized."; @@ -247,22 +225,19 @@ public class MapCodedFont extends AbstractAFPObject { } if (fontList.size() > 253) { - // Throw an exception if the size is exceeded throw new MaximumSizeExceededException(); - } else { - fontList.add(fd); + fontList.add(fontDefinition); } } catch (UnsupportedEncodingException ex) { - throw new FontRuntimeException("Failed to create font " + " due to a UnsupportedEncodingException", ex); - } } + /** * Private utility class used as a container for font attributes */ @@ -292,7 +267,6 @@ public class MapCodedFont extends AbstractAFPObject { * The scale (only specified for outline fonts) */ private int scale = 0; - } -}
\ No newline at end of file +} diff --git a/src/java/org/apache/fop/afp/modca/MapContainerData.java b/src/java/org/apache/fop/afp/modca/MapContainerData.java new file mode 100644 index 000000000..8411592aa --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/MapContainerData.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.modca.triplets.MappingOptionTriplet; +import org.apache.fop.afp.util.BinaryUtils; + +/** + * The Map Container Data structured field specifies how a presentation data object + * that is carried in an Object Container is mapped into its object area. + */ +public class MapContainerData extends AbstractTripletStructuredObject { + + /** + * Main constructor + * + * @param optionValue the mapping option value + */ + public MapContainerData(byte optionValue) { + super.addTriplet(new MappingOptionTriplet(optionValue)); + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[11]; + copySF(data, Type.MAP, Category.OBJECT_CONTAINER); + int tripletLen = getTripletDataLength(); + + byte[] len = BinaryUtils.convert(10 + tripletLen, 2); + data[1] = len[0]; + data[2] = len[1]; + + len = BinaryUtils.convert(2 + tripletLen, 2); + data[9] = len[0]; + data[10] = len[1]; + os.write(data); + writeTriplets(os); + } +} diff --git a/src/java/org/apache/fop/afp/modca/MapDataResource.java b/src/java/org/apache/fop/afp/modca/MapDataResource.java new file mode 100644 index 000000000..566f60ce5 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/MapDataResource.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * The Map Data Resource structured field specifies resources that are + * required for presentation. + */ +public class MapDataResource extends AbstractTripletStructuredObject { + + /** + * Main constructor + */ + public MapDataResource() { + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + super.writeStart(os); + byte[] data = new byte[11]; + copySF(data, Type.MAP, Category.DATA_RESOURCE); + + int tripletDataLen = getTripletDataLength(); + + byte[] len = BinaryUtils.convert(10 + tripletDataLen, 2); + data[1] = len[0]; + data[2] = len[1]; + + len = BinaryUtils.convert(2 + tripletDataLen, 2); + data[9] = len[0]; + data[10] = len[1]; + + os.write(data); + writeTriplets(os); + } +} diff --git a/src/java/org/apache/fop/render/afp/modca/MapPageOverlay.java b/src/java/org/apache/fop/afp/modca/MapPageOverlay.java index 129a3f5a1..9fd3c7059 100644 --- a/src/java/org/apache/fop/render/afp/modca/MapPageOverlay.java +++ b/src/java/org/apache/fop/afp/modca/MapPageOverlay.java @@ -17,14 +17,15 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.modca; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.List; -import org.apache.fop.render.afp.tools.BinaryUtils; +import org.apache.fop.afp.AFPConstants; +import org.apache.fop.afp.util.BinaryUtils; /** * The Map Page Overlay structured field maps a Resource Local ID to the name of @@ -33,18 +34,26 @@ import org.apache.fop.render.afp.tools.BinaryUtils; */ public class MapPageOverlay extends AbstractAFPObject { + private static final int MAX_SIZE = 253; + /** * The collection of overlays (maximum of 254 stored as byte[]) */ - private List overLays = new java.util.ArrayList(); + private List overLays = null; /** * Constructor for the Map Page Overlay */ public MapPageOverlay() { - } + private List getOverlays() { + if (overLays == null) { + this.overLays = new java.util.ArrayList(); + } + return this.overLays; + } + /** * Add an overlay to to the map page overlay object. * @@ -53,36 +62,28 @@ public class MapPageOverlay extends AbstractAFPObject { * @throws MaximumSizeExceededException if the maximum size is reached */ public void addOverlay(String name) throws MaximumSizeExceededException { - - if (overLays.size() > 253) { + if (getOverlays().size() > MAX_SIZE) { throw new MaximumSizeExceededException(); } - if (name.length() != 8) { throw new IllegalArgumentException("The name of overlay " + name + " must be 8 characters"); } - if (log.isDebugEnabled()) { log.debug("addOverlay():: adding overlay " + name); } - try { byte[] data = name.getBytes(AFPConstants.EBCIDIC_ENCODING); - overLays.add(data); + getOverlays().add(data); } catch (UnsupportedEncodingException usee) { log.error("addOverlay():: UnsupportedEncodingException translating the name " + name); } } - /** - * Accessor method to write the AFP datastream for the Map Page Overlay - * @param os The stream to write to - * @throws java.io.IOException if an I/O exception occurred - */ - public void writeDataStream(OutputStream os) throws IOException { - int oLayCount = overLays.size(); + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + int oLayCount = getOverlays().size(); int recordlength = oLayCount * 18; byte[] data = new byte[recordlength + 9]; @@ -98,8 +99,8 @@ public class MapPageOverlay extends AbstractAFPObject { // Structured field ID for a MPO data[3] = (byte) 0xD3; - data[4] = (byte) 0xAB; - data[5] = (byte) 0xD8; + data[4] = (byte) Type.MAP; + data[5] = (byte) Category.PAGE_OVERLAY; data[6] = 0x00; // Reserved data[7] = 0x00; // Reserved diff --git a/src/java/org/apache/fop/render/afp/modca/MaximumSizeExceededException.java b/src/java/org/apache/fop/afp/modca/MaximumSizeExceededException.java index a66fa9b30..6d1c74156 100644 --- a/src/java/org/apache/fop/render/afp/modca/MaximumSizeExceededException.java +++ b/src/java/org/apache/fop/afp/modca/MaximumSizeExceededException.java @@ -17,7 +17,7 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.modca; /** * An exception to handle maximum sizes being exceeded. diff --git a/src/java/org/apache/fop/render/afp/modca/NoOperation.java b/src/java/org/apache/fop/afp/modca/NoOperation.java index 54515a070..cb5841346 100644 --- a/src/java/org/apache/fop/render/afp/modca/NoOperation.java +++ b/src/java/org/apache/fop/afp/modca/NoOperation.java @@ -17,12 +17,13 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.modca; import java.io.IOException; import java.io.OutputStream; -import org.apache.fop.render.afp.tools.BinaryUtils; +import org.apache.fop.afp.AFPConstants; +import org.apache.fop.afp.util.BinaryUtils; /** * The No Operation structured field may be used to carry comments @@ -60,7 +61,7 @@ public class NoOperation extends AbstractAFPObject { * @param os The outputsteam stream * @throws java.io.IOException if an I/O exception occurs during processing */ - public void writeDataStream(OutputStream os) throws IOException { + public void writeToStream(OutputStream os) throws IOException { byte[] contentData = content.getBytes(AFPConstants.EBCIDIC_ENCODING); int contentLen = contentData.length; diff --git a/src/java/org/apache/fop/afp/modca/ObjectAreaDescriptor.java b/src/java/org/apache/fop/afp/modca/ObjectAreaDescriptor.java new file mode 100644 index 000000000..25323b864 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/ObjectAreaDescriptor.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.modca.triplets.DescriptorPositionTriplet; +import org.apache.fop.afp.modca.triplets.MeasurementUnitsTriplet; +import org.apache.fop.afp.modca.triplets.ObjectAreaSizeTriplet; +import org.apache.fop.afp.modca.triplets.PresentationSpaceResetMixingTriplet; +import org.apache.fop.afp.util.BinaryUtils; + +/** + * The Object Area Descriptor structured field specifies the size and attributes + * of an object area presentation space. + */ +public class ObjectAreaDescriptor extends AbstractDescriptor { + + /** + * Construct an object area descriptor for the specified object width + * and object height. + * + * @param width the object width. + * @param height the object height. + * @param widthRes the object width resolution. + * @param heightRes the object height resolution. + */ + public ObjectAreaDescriptor(int width, int height, int widthRes, int heightRes) { + super(width, height, widthRes, heightRes); + } + + private static final byte OBJECT_AREA_POSITION_ID = 0x01; + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[9]; + copySF(data, Type.DESCRIPTOR, Category.OBJECT_AREA); + + addTriplet(new DescriptorPositionTriplet(OBJECT_AREA_POSITION_ID)); + addTriplet(new MeasurementUnitsTriplet(widthRes, heightRes)); + addTriplet(new ObjectAreaSizeTriplet(width, height)); + addTriplet(new PresentationSpaceResetMixingTriplet( + PresentationSpaceResetMixingTriplet.NOT_RESET)); + + int tripletDataLength = getTripletDataLength(); + byte[] len = BinaryUtils.convert(data.length + tripletDataLength - 1, 2); + data[1] = len[0]; // Length + data[2] = len[1]; + os.write(data); + + writeTriplets(os); + } + +} diff --git a/src/java/org/apache/fop/afp/modca/ObjectAreaPosition.java b/src/java/org/apache/fop/afp/modca/ObjectAreaPosition.java new file mode 100644 index 000000000..3929c1196 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/ObjectAreaPosition.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * The Object Area Position structured field specifies the origin and + * orientation of the object area, and the origin and orientation of the + * object content within the object area. + */ +public class ObjectAreaPosition extends AbstractAFPObject { + + private final int x; + private final int y; + private final int rotation; + private int xOffset; + private int yOffset; + + /** + * Construct an object area position for the specified object y, y position. + * + * @param x The x coordinate. + * @param y The y coordinate. + * @param rotation The coordinate system rotation (must be 0, 90, 180, 270). + */ + public ObjectAreaPosition(int x, int y, int rotation) { + this.x = x; + this.y = y; + this.rotation = rotation; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[33]; + copySF(data, Type.POSITION, Category.OBJECT_AREA); + + byte[] len = BinaryUtils.convert(32, 2); + data[1] = len[0]; // Length + data[2] = len[1]; + + data[9] = 0x01; // OAPosID = 1 + data[10] = 0x17; // RGLength = 23 + + byte[] xcoord = BinaryUtils.convert(x, 3); + data[11] = xcoord[0]; // XoaOSet + data[12] = xcoord[1]; + data[13] = xcoord[2]; + + byte[] ycoord = BinaryUtils.convert(y, 3); + data[14] = ycoord[0]; // YoaOSet + data[15] = ycoord[1]; + data[16] = ycoord[2]; + + byte xorient = (byte)(rotation / 2); + data[17] = xorient; // XoaOrent + + byte yorient = (byte)(rotation / 2 + 45); + data[19] = yorient; // YoaOrent + + byte[] xoffset = BinaryUtils.convert(xOffset, 3); + data[22] = xoffset[0]; // XocaOSet + data[23] = xoffset[1]; + data[24] = xoffset[2]; + + byte[] yoffset = BinaryUtils.convert(yOffset, 3); + data[25] = yoffset[0]; // YocaOSet + data[26] = yoffset[1]; + data[27] = yoffset[2]; + + data[28] = 0x00; // XocaOrent + data[29] = 0x00; + + data[30] = 0x2D; // YocaOrent + data[31] = 0x00; + + data[32] = 0x01; // RefCSys + + os.write(data); + } + + /** {@inheritDoc} */ + public String toString() { + return "ObjectAreaPosition{" + + "x=" + x + + ", y=" + y + + ", rotation=" + rotation + + ", rotation=" + rotation + + ", xOffset=" + xOffset + + ", yOffset=" + yOffset; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/modca/ObjectContainer.java b/src/java/org/apache/fop/afp/modca/ObjectContainer.java new file mode 100644 index 000000000..39b935d01 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/ObjectContainer.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.AFPDataObjectInfo; +import org.apache.fop.afp.AFPObjectAreaInfo; +import org.apache.fop.afp.AFPResourceInfo; +import org.apache.fop.afp.AFPResourceLevel; +import org.apache.fop.afp.Factory; +import org.apache.fop.afp.modca.triplets.MappingOptionTriplet; +import org.apache.fop.afp.util.BinaryUtils; + +/** + * Object containers are MO:DCA objects that envelop and carry object data. + */ +public class ObjectContainer extends AbstractDataObject { + + /** the object container data maximum length */ + private static final int MAX_DATA_LEN = 32759; + + private byte[] data; + + /** + * Main constructor + * + * @param factory the object factory + * @param name the name of this object container + */ + public ObjectContainer(Factory factory, String name) { + super(factory, name); + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + byte[] headerData = new byte[17]; + copySF(headerData, Type.BEGIN, Category.OBJECT_CONTAINER); + + // Set the total record length + int containerLen = headerData.length + getTripletDataLength() - 1; + byte[] len = BinaryUtils.convert(containerLen, 2); + headerData[1] = len[0]; // Length byte 1 + headerData[2] = len[1]; // Length byte 2 + + os.write(headerData); + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + super.writeContent(os); // write triplets and OEG + + // write OCDs + byte[] dataHeader = new byte[9]; + copySF(dataHeader, SF_CLASS, Type.DATA, Category.OBJECT_CONTAINER); + final int lengthOffset = 1; + + if (data != null) { + writeChunksToStream(data, dataHeader, lengthOffset, MAX_DATA_LEN, os); + } + } + + /** {@inheritDoc} */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.END, Category.OBJECT_CONTAINER); + os.write(data); + } + + /** {@inheritDoc} */ + public void setViewport(AFPDataObjectInfo dataObjectInfo) { + AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo(); + AFPResourceLevel resourceLevel = resourceInfo.getLevel(); + + // only need to set MCD and CDD when OC when is inlined (pre-2000 apps) + if (resourceLevel.isInline()) { + super.setViewport(dataObjectInfo); + + MapContainerData mapContainerData + = factory.createMapContainerData(MappingOptionTriplet.SCALE_TO_FIT); + getObjectEnvironmentGroup().setMapContainerData(mapContainerData); + + int dataWidth = dataObjectInfo.getDataWidth(); + int dataHeight = dataObjectInfo.getDataHeight(); + + AFPObjectAreaInfo objectAreaInfo = dataObjectInfo.getObjectAreaInfo(); + int widthRes = objectAreaInfo.getWidthRes(); + int heightRes = objectAreaInfo.getHeightRes(); + + ContainerDataDescriptor containerDataDescriptor + = factory.createContainerDataDescriptor( + dataWidth, dataHeight, widthRes, heightRes); + getObjectEnvironmentGroup().setDataDescriptor(containerDataDescriptor); + } + } + + /** + * Sets the inputstream for the the object container data + * + * @param inputStream the inputstream for the object container data + */ + public void setData(byte[] data) { + this.data = data; + } +} diff --git a/src/java/org/apache/fop/afp/modca/ObjectEnvironmentGroup.java b/src/java/org/apache/fop/afp/modca/ObjectEnvironmentGroup.java new file mode 100644 index 000000000..bc0cc5a63 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/ObjectEnvironmentGroup.java @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * An Object Environment Group (OEG) may be associated with an object and is contained + * within the object's begin-end envelope. + * The object environment group defines the object's origin and orientation on the page, + * and can contain font and color attribute table information. The scope of an object + * environment group is the scope of its containing object. + * + * An application that creates a data-stream document may omit some of the parameters + * 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 { + + /** the PresentationEnvironmentControl for the object environment group */ + private PresentationEnvironmentControl presentationEnvironmentControl; + + /** the ObjectAreaDescriptor for the object environment group */ + private ObjectAreaDescriptor objectAreaDescriptor; + + /** the ObjectAreaPosition for the object environment group */ + private ObjectAreaPosition objectAreaPosition; + + /** the DataDescriptor for the object environment group */ + private AbstractDescriptor dataDescriptor; + + /** the MapDataResource for the object environment group */ + private MapDataResource mapDataResource; + + /** the MapContainerData for the object environment group */ + private MapContainerData mapContainerData; + + /** + * Constructor for the ObjectEnvironmentGroup, this takes a + * name parameter which must be 8 characters long. + * + * @param name the object environment group name + */ + public ObjectEnvironmentGroup(String name) { + super(name); + } + + /** + * Sets the Object Area Descriptor + * + * @param objectAreaDescriptor the object area descriptor + */ + public void setObjectAreaDescriptor(ObjectAreaDescriptor objectAreaDescriptor) { + this.objectAreaDescriptor = objectAreaDescriptor; + } + + /** + * Sets the Object Area Position + * + * @param objectAreaPosition the object area position + */ + public void setObjectAreaPosition(ObjectAreaPosition objectAreaPosition) { + this.objectAreaPosition = objectAreaPosition; + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.BEGIN, Category.OBJECT_ENVIRONMENT_GROUP); + + int tripletDataLength = getTripletDataLength(); + int sfLen = data.length + tripletDataLength - 1; + byte[] len = BinaryUtils.convert(sfLen, 2); + data[1] = len[0]; + data[2] = len[1]; + + os.write(data); + + writeTriplets(os); + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + super.writeContent(os); + + if (presentationEnvironmentControl != null) { + presentationEnvironmentControl.writeToStream(os); + } + + if (objectAreaDescriptor != null) { + objectAreaDescriptor.writeToStream(os); + } + + if (objectAreaPosition != null) { + objectAreaPosition.writeToStream(os); + } + + if (mapContainerData != null) { + mapContainerData.writeToStream(os); + } + + if (mapDataResource != null) { + mapDataResource.writeToStream(os); + } + + if (dataDescriptor != null) { + dataDescriptor.writeToStream(os); + } + } + + /** {@inheritDoc} */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.END, Category.OBJECT_ENVIRONMENT_GROUP); + os.write(data); + } + + /** + * Sets the presentation environment control + * + * @param presentationEnvironmentControl the presentation environment control + */ + public void setPresentationEnvironmentControl( + PresentationEnvironmentControl presentationEnvironmentControl) { + this.presentationEnvironmentControl = presentationEnvironmentControl; + } + + /** + * Sets the data descriptor + * + * @param dataDescriptor the data descriptor + */ + public void setDataDescriptor(AbstractDescriptor dataDescriptor) { + this.dataDescriptor = dataDescriptor; + } + + /** + * Sets the map data resource + * + * @param mapDataResource the map data resource + */ + public void setMapDataResource(MapDataResource mapDataResource) { + this.mapDataResource = mapDataResource; + } + + /** + * Sets the map container data + * + * @param mapContainerData the map container data + */ + public void setMapContainerData(MapContainerData mapContainerData) { + this.mapContainerData = mapContainerData; + } + + /** + * Returns the object area descriptor + * + * @return the object area descriptor + */ + public ObjectAreaDescriptor getObjectAreaDescriptor() { + return this.objectAreaDescriptor; + } + +} diff --git a/src/java/org/apache/fop/afp/modca/Overlay.java b/src/java/org/apache/fop/afp/modca/Overlay.java new file mode 100644 index 000000000..ea9619b20 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/Overlay.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.Factory; + + +/** + * An overlay is a MO:DCA-P resource object. + * + * It may be stored in an external resource library or it may be + * carried in a resource group. An overlay is similar to a page in + * that it defines its own environment and carries the same data objects. + */ +public class Overlay extends PageObject { + + /** + * Construct a new overlay object for the specified name argument, the overlay + * name should be an 8 character identifier. + * + * @param factory + * the resource manager of the page. + * @param name + * the name of the page. + * @param width + * the width of the page. + * @param height + * the height of the page. + * @param rotation + * the rotation of the page. + * @param widthResolution + * the width resolution of the page. + * @param heightResolution + * the height resolution of the page. + */ + public Overlay(Factory factory, + String name, int width, int height, int rotation, + int widthResolution, int heightResolution) { + super(factory, name, width, height, rotation, widthResolution, heightResolution); + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.BEGIN, Category.OVERLAY); + os.write(data); + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + super.writeContent(os); + + getActiveEnvironmentGroup().writeToStream(os); + + writeObjects(includePageSegments, os); + writeObjects(tagLogicalElements, os); + writeObjects(objects, os); + } + + + /** {@inheritDoc} */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.END, Category.OVERLAY); + os.write(data); + } +} diff --git a/src/java/org/apache/fop/render/afp/modca/PageDescriptor.java b/src/java/org/apache/fop/afp/modca/PageDescriptor.java index 541df823e..502123def 100644 --- a/src/java/org/apache/fop/render/afp/modca/PageDescriptor.java +++ b/src/java/org/apache/fop/afp/modca/PageDescriptor.java @@ -17,11 +17,12 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.modca; import java.io.IOException; import java.io.OutputStream; -import org.apache.fop.render.afp.tools.BinaryUtils; + +import org.apache.fop.afp.util.BinaryUtils; /** * The Page Descriptor structured field specifies the size and attributes of @@ -33,47 +34,35 @@ public class PageDescriptor extends AbstractDescriptor { /** * Construct a page descriptor for the specified page width * 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); } - /** - * Accessor method to write the AFP datastream for the Page Descriptor - * @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 { - - log.debug("width=" + width); - log.debug("height=" + height); + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { byte[] data = new byte[24]; - data[0] = 0x5A; - data[1] = 0x00; + copySF(data, Type.DESCRIPTOR, Category.PAGE); data[2] = 0x17; - data[3] = (byte) 0xD3; - data[4] = (byte) 0xA6; - data[5] = (byte) 0xAF; - - data[6] = 0x00; // Flags - data[7] = 0x00; // Reserved - data[8] = 0x00; // Reserved + // XpgBase data[9] = 0x00; // XpgBase = 10 inches + + // YpgBase 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/afp/modca/PageGroup.java b/src/java/org/apache/fop/afp/modca/PageGroup.java new file mode 100644 index 000000000..13be9745e --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/PageGroup.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +import org.apache.fop.afp.Factory; + +/** + * A page group is used in the data stream to define a named, logical grouping + * of sequential pages. Page groups are delimited by begin-end structured fields + * that carry the name of the page group. Page groups are defined so that the + * pages that comprise the group can be referenced or processed as a single + * entity. Page groups are often processed in stand-alone fashion; that is, they + * are indexed, retrieved, and presented outside the context of the containing + * document. + */ +public class PageGroup extends AbstractResourceEnvironmentGroupContainer { + + /** The tag logical elements contained within this group */ + private List tagLogicalElements = null; + + /** + * Constructor for the PageGroup. + * + * @param factory the resource manager + * @param name the name of the page group + */ + public PageGroup(Factory factory, String name) { + super(factory, name); + } + + private List getTagLogicalElements() { + if (tagLogicalElements == null) { + this.tagLogicalElements = new java.util.ArrayList(); + } + return this.tagLogicalElements; + } + + /** + * Creates a TagLogicalElement on the page. + * + * @param name + * the name of the tag + * @param value + * the value of the tag + */ + public void createTagLogicalElement(String name, String value) { + TagLogicalElement tle = factory.createTagLogicalElement(name, value); + if (!getTagLogicalElements().contains(tle)) { + getTagLogicalElements().add(tle); + } + } + + /** + * Method to mark the end of the page group. + */ + public void endPageGroup() { + complete = true; + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + writeObjects(tagLogicalElements, os); + super.writeContent(os); + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.BEGIN, Category.PAGE_GROUP); + os.write(data); + } + + /** {@inheritDoc} */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.END, Category.PAGE_GROUP); + os.write(data); + } + + /** {@inheritDoc} */ + public String toString() { + return this.getName(); + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/modca/PageObject.java b/src/java/org/apache/fop/afp/modca/PageObject.java new file mode 100644 index 000000000..33852d90b --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/PageObject.java @@ -0,0 +1,219 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.Factory; +import org.apache.fop.afp.ioca.ImageCellPosition; +import org.apache.fop.afp.ioca.ImageInputDescriptor; +import org.apache.fop.afp.ioca.ImageOutputControl; +import org.apache.fop.afp.ioca.ImageRasterData; +import org.apache.fop.afp.ioca.ImageRasterPattern; + +/** + * Pages contain the data objects that comprise a presentation document. Each + * page has a set of data objects associated with it. Each page within a + * document is independent from any other page, and each must establish its own + * environment parameters. + * + * The page is the level in the document component hierarchy that is used for + * printing or displaying a document's content. The data objects contained in + * the page envelope in the data stream are presented when the page is + * presented. Each data object has layout information associated with it that + * directs the placement and orientation of the data on the page. In addition, + * each page contains layout information that specifies the measurement units, + * page width, and page depth. + * + * A page is initiated by a begin page structured field and terminated by an end + * page structured field. Structured fields that define objects and active + * environment groups or that specify attributes of the page may be encountered + * in page state. + * + */ +public class PageObject extends AbstractResourceGroupContainer { + + /** + * Construct a new page object for the specified name argument, the page + * name should be an 8 character identifier. + * + * @param factory the resource manager + * + * @param name + * the name of the page. + * @param width + * the width of the page. + * @param height + * the height of the page. + * @param rotation + * the rotation of the page. + * @param widthRes + * the width resolution of the page. + * @param heightRes + * the height resolution of the page. + */ + public PageObject(Factory factory, + String name, int width, int height, int rotation, + int widthRes, int heightRes) { + super(factory, name, width, height, rotation, widthRes, heightRes); + } + + /** + * Creates an IncludePageOverlay on the page. + * + * @param name + * the name of the overlay + * @param x + * the x position of the overlay + * @param y + * the y position of the overlay + * @param orientation + * the orientation required for the overlay + */ + public void createIncludePageOverlay(String name, int x, int y, int orientation) { + getActiveEnvironmentGroup().createOverlay(name); + IncludePageOverlay ipo = new IncludePageOverlay(name, x, y, orientation); + addObject(ipo); + } + + /** + * This method will create shading on the page using the specified + * coordinates (the shading contrast is controlled via the red, green blue + * parameters, by converting this to grayscale). + * + * @param x + * the x coordinate of the shading + * @param y + * the y coordinate of the shading + * @param w + * the width of the shaded area + * @param h + * the height of the shaded area + * @param red + * the red value + * @param green + * the green value + * @param blue + * the blue value + */ + public void createShading(int x, int y, int w, int h, int red, int green, int blue) { + int xCoord = 0; + int yCoord = 0; + int areaWidth = 0; + int areaHeight = 0; + switch (rotation) { + case 90: + xCoord = areaWidth - y - h; + yCoord = x; + areaWidth = h; + areaHeight = w; + break; + case 180: + xCoord = areaWidth - x - w; + yCoord = areaHeight - y - h; + areaWidth = w; + areaHeight = h; + break; + case 270: + xCoord = y; + yCoord = areaHeight - x - w; + areaWidth = h; + areaHeight = w; + break; + default: + xCoord = x; + yCoord = y; + areaWidth = w; + areaHeight = h; + break; + } + + // Convert the color to grey scale + float shade = (float) ((red * 0.3) + (green * 0.59) + (blue * 0.11)); + + int grayscale = Math.round((shade / 255) * 16); + + IMImageObject imImageObject = factory.createIMImageObject(); + + ImageOutputControl imageOutputControl = new ImageOutputControl(0, 0); + ImageInputDescriptor imageInputDescriptor = new ImageInputDescriptor(); + ImageCellPosition imageCellPosition = new ImageCellPosition(xCoord, yCoord); + imageCellPosition.setXFillSize(areaWidth); + imageCellPosition.setYFillSize(areaHeight); + imageCellPosition.setXSize(64); + imageCellPosition.setYSize(8); + + //defining this as a resource + byte[] rasterData = ImageRasterPattern.getRasterData(grayscale); + ImageRasterData imageRasterData = factory.createImageRasterData(rasterData); + + imImageObject.setImageOutputControl(imageOutputControl); + imImageObject.setImageInputDescriptor(imageInputDescriptor); + imImageObject.setImageCellPosition(imageCellPosition); + imImageObject.setImageRasterData(imageRasterData); + addObject(imImageObject); + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.BEGIN, Category.PAGE); + os.write(data); + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + writeTriplets(os); + + getActiveEnvironmentGroup().writeToStream(os); + + writeObjects(includePageSegments, os); + writeObjects(tagLogicalElements, os); + writeObjects(objects, os); + } + + /** {@inheritDoc} */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.END, Category.PAGE); + os.write(data); + } + + /** + * Adds an AFP object reference to this page + * + * @param obj an AFP object + */ + public void addObject(Object obj) { + endPresentationObject(); + super.addObject(obj); + } + + /** {@inheritDoc} */ + public String toString() { + return this.getName(); + } + + /** {@inheritDoc} */ + protected boolean canWrite(AbstractAFPObject ao) { + return true; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/modca/PageSegment.java b/src/java/org/apache/fop/afp/modca/PageSegment.java new file mode 100644 index 000000000..ab1388efb --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/PageSegment.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.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +/** + * A page segment is a MO:DCA-P resource object. It may be stored in an + * external resource library or it may be carried in a resource group. + * Page segments contain any combination of IOCA image objects and + * GOCA graphics objects. + */ +public class PageSegment extends AbstractNamedAFPObject { + + private List/*<AbstractAFPObject>*/ objects = null; + + /** + * Main constructor + * + * @param name the name of this object + */ + public PageSegment(String name) { + super(name); + } + + /** + * Returns a list of objects contained withing this page segment + * + * @return a list of objects contained within this page segment + */ + public List/*<AbstractAFPObject>*/ getObjects() { + if (objects == null) { + objects = new java.util.ArrayList(); + } + return objects; + } + + /** + * Adds a resource object (image/graphic) to this page segment + * + * @param object the resource objec to add to this page segment + */ + public void addObject(AbstractAFPObject object) { + getObjects().add(object); + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.BEGIN, Category.PAGE_SEGMENT); + os.write(data); + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + super.writeContent(os); + writeObjects(objects, os); + } + + /** {@inheritDoc} */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.END, Category.PAGE_SEGMENT); + os.write(data); + } + + /** {@inheritDoc} */ + public String toString() { + return this.name; + } +} diff --git a/src/java/org/apache/fop/afp/modca/PreprocessPresentationObject.java b/src/java/org/apache/fop/afp/modca/PreprocessPresentationObject.java new file mode 100644 index 000000000..72e261662 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/PreprocessPresentationObject.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet; +import org.apache.fop.afp.util.BinaryUtils; + +/** + * The Preprocess Presentation Object structured field specifies presentation + * parameters for a data object that has been mapped as a resource. + */ +public class PreprocessPresentationObject extends AbstractTripletStructuredObject { + private static final byte TYPE_OTHER = (byte)0x92; + private static final byte TYPE_OVERLAY = (byte)0xDF; + private static final byte TYPE_IMAGE = (byte)0xFB; + + private byte objType = TYPE_OTHER; + private byte objOrent = 0; // object always processed at 0 degree orientation + private int objXOffset = -1; + private int objYOffset = -1; + + /** + * Main constructor + * + * @param prePresObj the presentation object to be preprocessed + */ + public PreprocessPresentationObject(AbstractTripletStructuredObject prePresObj) { + if (prePresObj instanceof ImageObject || prePresObj instanceof Overlay) { + if (prePresObj instanceof ImageObject) { + this.objType = TYPE_IMAGE; + } else { + this.objType = TYPE_OVERLAY; + } + setFullyQualifiedName( + FullyQualifiedNameTriplet.TYPE_BEGIN_RESOURCE_OBJECT_REF, + FullyQualifiedNameTriplet.FORMAT_CHARSTR, + prePresObj.getFullyQualifiedName()); + } else { + this.objType = TYPE_OTHER; + } + } + + public static final byte ORIENTATION_ZERO_DEGREES = 1; + public static final byte ORIENTATION_90_DEGREES = 2; + public static final byte ORIENTATION_180_DEGREES = 4; + public static final byte ORIENTATION_270_DEGREES = 8; + + /** + * Sets the object orientations relative to media leading edge + * + * @param orientation the object orientations relative to media leading edge + */ + public void setOrientation(byte orientation) { + objOrent = orientation; + } + + /** + * Sets the X axis origin for object content + * + * @param xOffset the X axis origin for object content + */ + public void setXOffset(int xOffset) { + this.objXOffset = xOffset; + } + + /** + * Sets the Y axis origin for object content + * + * @param yOffset the Y axis origin for object content + */ + public void setYOffset(int yOffset) { + this.objYOffset = yOffset; + } + + /** {@inheritDoc} */ + public void writeStart(OutputStream os) throws IOException { + super.writeStart(os); + + byte[] data = new byte[9]; + copySF(data, Type.PROCESS, Category.DATA_RESOURCE); + + byte[] l = BinaryUtils.convert(19 + getTripletDataLength(), 2); + data[1] = l[0]; // Length byte 1 + data[2] = l[1]; // Length byte 1 + + os.write(data); + } + + /** {@inheritDoc} */ + public void writeContent(OutputStream os) throws IOException { + byte[] data = new byte[12]; + byte[] l = BinaryUtils.convert(12 + getTripletDataLength(), 2); + data[0] = l[0]; // RGLength + data[1] = l[1]; // RGLength + data[2] = objType; // ObjType + data[3] = 0x00; // Reserved + data[4] = 0x00; // Reserved + data[5] = objOrent; // ObjOrent + if (objXOffset > 0) { + byte[] xOff = BinaryUtils.convert(objYOffset, 3); + data[6] = xOff[0]; // XocaOset (not specified) + data[7] = xOff[1]; // XocaOset + data[8] = xOff[2]; // XocaOset + } else { + data[6] = (byte)0xFF; // XocaOset (not specified) + data[7] = (byte)0xFF; // XocaOset + data[8] = (byte)0xFF; // XocaOset + } + if (objYOffset > 0) { + byte[] yOff = BinaryUtils.convert(objYOffset, 3); + data[9] = yOff[0]; // YocaOset (not specified) + data[10] = yOff[1]; // YocaOset + data[11] = yOff[2]; // YocaOset + } else { + data[9] = (byte)0xFF; // YocaOset (not specified) + data[10] = (byte)0xFF; // YocaOset + data[11] = (byte)0xFF; // YocaOset + } + os.write(data); + + writeTriplets(os); + } + +} diff --git a/src/java/org/apache/fop/afp/modca/PresentationEnvironmentControl.java b/src/java/org/apache/fop/afp/modca/PresentationEnvironmentControl.java new file mode 100644 index 000000000..a2ebe22f6 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/PresentationEnvironmentControl.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * The Presentation Environment Control structured field specifies parameters that + * affect the rendering of presentation data and the appearance that is to be assumed + * by the presentation device. + */ +public class PresentationEnvironmentControl extends AbstractTripletStructuredObject { + + /** + * Main constructor + */ + public PresentationEnvironmentControl() { + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = new byte[11]; + copySF(data, Type.CONTROL, Category.DOCUMENT); + int tripletDataLen = getTripletDataLength(); + byte[] len = BinaryUtils.convert(10 + tripletDataLen); + data[1] = len[0]; + data[2] = len[1]; + data[9] = 0x00; // Reserved; must be zero + data[10] = 0x00; // Reserved; must be zero + + os.write(data); + + writeTriplets(os); + } + +// /** +// * Sets the object offset +// */ +// public void setObjectOffset() { +// addTriplet(new ObjectOffsetTriplet()); +// } +// +// /** +// * Sets the rendering intent +// */ +// public void setRenderingIntent() { +// addTriplet(new RenderingIntentTriplet()); +// } +// +// /** +// * Sets the device appearance +// */ +// public void setDeviceAppearance() { +// addTriplet(new DeviceAppearanceTriplet()); +// } + + + // TODO +// private class DeviceAppearanceTriplet extends AbstractTriplet { +// public DeviceAppearanceTriplet() { +// super(AbstractTriplet.DEVICE_APPEARANCE); +// } +// } + + // TODO +// private class RenderingIntentTriplet extends AbstractTriplet { +// public RenderingIntentTriplet() { +// super(AbstractTriplet.RENDERING_INTENT); +// } +// } + + // TODO +// private class ObjectOffsetTriplet extends AbstractTriplet { +// public ObjectOffsetTriplet() { +// super(AbstractTriplet.OBJECT_OFFSET); +// } +// } +} diff --git a/src/java/org/apache/fop/render/afp/modca/PresentationTextData.java b/src/java/org/apache/fop/afp/modca/PresentationTextData.java index 98beb96f7..645a461d8 100644 --- a/src/java/org/apache/fop/render/afp/modca/PresentationTextData.java +++ b/src/java/org/apache/fop/afp/modca/PresentationTextData.java @@ -17,14 +17,17 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.modca; import java.awt.Color; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.io.UnsupportedEncodingException; -import org.apache.fop.render.afp.tools.BinaryUtils; +import org.apache.commons.io.output.ByteArrayOutputStream; +import org.apache.fop.afp.AFPLineDataInfo; +import org.apache.fop.afp.AFPTextDataInfo; +import org.apache.fop.afp.util.BinaryUtils; /** * Presentation text data contains the graphic characters and the control @@ -48,58 +51,38 @@ import org.apache.fop.render.afp.tools.BinaryUtils; */ public class PresentationTextData extends AbstractAFPObject { - /** - * The maximum size of the presentation text data. - */ + /** the maximum size of the presentation text data.*/ private static final int MAX_SIZE = 8192; - /** - * The afp data relating to this presentaion text data. - */ - private ByteArrayOutputStream _baos = new ByteArrayOutputStream(1024); + /** the AFP data relating to this presentation text data. */ + private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - /** - * The current x coordinate. - */ - private int _currentXCoordinate = -1; + /** the current x coordinate. */ + private int currentX = -1; - /** - * The current y cooridnate - */ - private int _currentYCoordinate = -1; + /** the current y cooridnate */ + private int currentY = -1; - /** - * The current font - */ - private String _currentFont = ""; + /** the current font */ + private String currentFont = ""; - /** - * The current orientation - */ - private int _currentOrientation = 0; + /** the current orientation */ + private int currentOrientation = 0; - /** - * The current color - */ - private Color _currentColor = new Color(0, 0, 0); + /** the current color */ + private Color currentColor = new Color(0, 0, 0); - /** - * The current variable space increment - */ - private int _currentVariableSpaceCharacterIncrement = 0; + /** the current variable space increment */ + private int currentVariableSpaceCharacterIncrement = 0; - /** - * The current inter character adjustment - */ - private int _currentInterCharacterAdjustment = 0; + /** the current inter character adjustment */ + private int currentInterCharacterAdjustment = 0; /** * Default constructor for the PresentationTextData. */ public PresentationTextData() { - this(false); - } /** @@ -111,22 +94,22 @@ public class PresentationTextData extends AbstractAFPObject { * The control sequence indicator. */ public PresentationTextData(boolean controlInd) { - - _baos.write(new byte[] { 0x5A, // Structured field identifier - 0x00, // Record length byte 1 - 0x00, // Record length byte 2 - (byte) 0xD3, // PresentationTextData identifier byte 1 - (byte) 0xEE, // PresentationTextData identifier byte 2 - (byte) 0x9B, // PresentationTextData identifier byte 3 - 0x00, // Flag - 0x00, // Reserved - 0x00, // Reserved - }, 0, 9); + final byte[] data = { + 0x5A, // Structured field identifier + 0x00, // Record length byte 1 + 0x00, // Record length byte 2 + SF_CLASS, // PresentationTextData identifier byte 1 + Type.DATA, // PresentationTextData identifier byte 2 + Category.PRESENTATION_TEXT, // PresentationTextData identifier byte 3 + 0x00, // Flag + 0x00, // Reserved + 0x00, // Reserved + }; + baos.write(data, 0, 9); if (controlInd) { - _baos.write(new byte[] { 0x2B, (byte) 0xD3 }, 0, 2); + baos.write(new byte[] {0x2B, (byte) 0xD3}, 0, 2); } - } /** @@ -140,16 +123,14 @@ public class PresentationTextData extends AbstractAFPObject { * The output stream to which data should be written. */ 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); } /** @@ -163,14 +144,10 @@ public class PresentationTextData extends AbstractAFPObject { * The output stream to which data should be written. */ private void absoluteMoveInline(int coordinate, - ByteArrayOutputStream afpdata) { - + ByteArrayOutputStream afpdata) { byte[] b = BinaryUtils.convert(coordinate, 2); - - afpdata.write(new byte[] { 0x04, (byte) 0xC7, b[0], b[1], }, 0, 4); - - _currentXCoordinate = coordinate; - + afpdata.write(new byte[] {0x04, (byte) 0xC7, b[0], b[1]}, 0, 4); + currentX = coordinate; } /** @@ -184,16 +161,14 @@ public class PresentationTextData extends AbstractAFPObject { * The output stream to which data should be written. */ private void absoluteMoveBaseline(int coordinate, - ByteArrayOutputStream afpdata) { - + ByteArrayOutputStream afpdata) { byte[] b = BinaryUtils.convert(coordinate, 2); - - afpdata.write(new byte[] { 0x04, (byte) 0xD3, b[0], b[1], }, 0, 4); - - _currentYCoordinate = coordinate; - + afpdata.write(new byte[] {0x04, (byte) 0xD3, b[0], b[1]}, 0, 4); + currentY = coordinate; } + private static final int TRANSPARENT_MAX_SIZE = 253; + /** * The Transparent Data control sequence contains a sequence of code points * that are presented without a scan for embedded control sequences. @@ -204,21 +179,16 @@ public class PresentationTextData extends AbstractAFPObject { * The output stream to which data should be written. */ private void addTransparentData(byte[] data, ByteArrayOutputStream afpdata) { - // Calculate the length int l = data.length + 2; - if (l > 255) { // Check that we are not exceeding the maximum length throw new IllegalArgumentException( - "Transparent data is longer than 253 bytes: " + data); + "Transparent data is longer than " + TRANSPARENT_MAX_SIZE + " bytes: " + data); } - - afpdata.write(new byte[] { BinaryUtils.convert(l)[0], (byte) 0xDB, }, - 0, 2); - + afpdata.write(new byte[] {BinaryUtils.convert(l)[0], (byte) 0xDB}, + 0, 2); afpdata.write(data, 0, data.length); - } /** @@ -234,12 +204,11 @@ public class PresentationTextData extends AbstractAFPObject { * The output stream to which data should be written. */ private void drawBaxisRule(int length, int width, - ByteArrayOutputStream afpdata) { - - afpdata.write(new byte[] { 0x07, // Length - (byte) 0xE7, // Type + ByteArrayOutputStream afpdata) { + afpdata.write(new byte[] { + 0x07, // Length + (byte) 0xE7, // Type }, 0, 2); - // Rule length byte[] data1 = BinaryUtils.shortToByteArray((short) length); afpdata.write(data1, 0, data1.length); @@ -248,7 +217,6 @@ public class PresentationTextData extends AbstractAFPObject { afpdata.write(data2, 0, data2.length); // Rule width fraction afpdata.write(0x00); - } /** @@ -264,12 +232,11 @@ public class PresentationTextData extends AbstractAFPObject { * The output stream to which data should be written. */ private void drawIaxisRule(int length, int width, - ByteArrayOutputStream afpdata) { - - afpdata.write(new byte[] { 0x07, // Length - (byte) 0xE5, // Type + ByteArrayOutputStream afpdata) { + afpdata.write(new byte[] { + 0x07, // Length + (byte) 0xE5, // Type }, 0, 2); - // Rule length byte[] data1 = BinaryUtils.shortToByteArray((short) length); afpdata.write(data1, 0, data1.length); @@ -278,152 +245,170 @@ public class PresentationTextData extends AbstractAFPObject { afpdata.write(data2, 0, data2.length); // Rule width fraction afpdata.write(0x00); - } /** * Create the presentation text data for the byte array of data. * - * @param fontNumber - * The font resource identifier. - * @param x - * The x coordinate for the text data. - * @param y - * The y coordinate for the text data. - * @param orientation - * The orientation of the text data. - * @param col - * The text color. - * @param vsci - * The variable space character increment. - * @param ica - * The inter character adjustment. - * @param data - * The text data to be created. + * @param textDataInfo + * the afp text data * @throws MaximumSizeExceededException + * thrown if the maximum number of text data is exceeded + * @throws UnsupportedEncodingException + * thrown if character encoding is not supported */ - public void createTextData(int fontNumber, int x, int y, int orientation, - Color col, int vsci, int ica, byte[] data) - throws MaximumSizeExceededException { + public void createTextData(AFPTextDataInfo textDataInfo) + throws MaximumSizeExceededException, UnsupportedEncodingException { ByteArrayOutputStream afpdata = new ByteArrayOutputStream(); - if (_currentOrientation != orientation) { - setTextOrientation(orientation, afpdata); - _currentOrientation = orientation; - _currentXCoordinate = -1; - _currentYCoordinate = -1; + int rotation = textDataInfo.getRotation(); + if (currentOrientation != rotation) { + setTextOrientation(rotation, afpdata); + currentOrientation = rotation; + currentX = -1; + currentY = -1; } - // Avoid unnecessary specification of the Y co-ordinate - if (y != _currentYCoordinate) { + // Avoid unnecessary specification of the Y coordinate + int y = textDataInfo.getY(); + if (currentY != y) { absoluteMoveBaseline(y, afpdata); - _currentXCoordinate = -1; + currentX = -1; } - // Avoid unnecessary specification of the X co-ordinate - if (x != _currentXCoordinate) { + // Avoid unnecessary specification of the X coordinate + int x = textDataInfo.getX(); + if (currentX != x) { absoluteMoveInline(x, afpdata); } // Avoid unnecessary specification of the variable space increment - if (vsci != _currentVariableSpaceCharacterIncrement) { - setVariableSpaceCharacterIncrement(vsci, afpdata); - _currentVariableSpaceCharacterIncrement = vsci; + if (textDataInfo.getVariableSpaceCharacterIncrement() + != currentVariableSpaceCharacterIncrement) { + setVariableSpaceCharacterIncrement(textDataInfo + .getVariableSpaceCharacterIncrement(), afpdata); + currentVariableSpaceCharacterIncrement = textDataInfo + .getVariableSpaceCharacterIncrement(); } // Avoid unnecessary specification of the inter character adjustment - if (ica != _currentInterCharacterAdjustment) { - setInterCharacterAdjustment(ica, afpdata); - _currentInterCharacterAdjustment = ica; + if (textDataInfo.getInterCharacterAdjustment() != currentInterCharacterAdjustment) { + setInterCharacterAdjustment(textDataInfo.getInterCharacterAdjustment(), + afpdata); + currentInterCharacterAdjustment = textDataInfo + .getInterCharacterAdjustment(); } // Avoid unnecessary specification of the text color - if (!col.equals(_currentColor)) { - setExtendedTextColor(col, afpdata); - _currentColor = col; + if (!textDataInfo.getColor().equals(currentColor)) { + setExtendedTextColor(textDataInfo.getColor(), afpdata); + currentColor = textDataInfo.getColor(); } - setCodedFont(BinaryUtils.convert(fontNumber)[0], afpdata); - addTransparentData(data, afpdata); - _currentXCoordinate = -1; + setCodedFont(BinaryUtils.convert(textDataInfo.getFontReference())[0], + afpdata); + + // Add transparent data + String textString = textDataInfo.getString(); + String encoding = textDataInfo.getEncoding(); + byte[] data = textString.getBytes(encoding); + if (data.length <= TRANSPARENT_MAX_SIZE) { + addTransparentData(data, afpdata); + } else { + // data size greater than TRANSPARENT_MAX_SIZE so slice + int numTransData = data.length / TRANSPARENT_MAX_SIZE; + byte[] buff = new byte[TRANSPARENT_MAX_SIZE]; + int currIndex = 0; + for (int transDataCnt = 0; transDataCnt < numTransData; transDataCnt++) { + currIndex = transDataCnt * TRANSPARENT_MAX_SIZE; + System.arraycopy(data, currIndex, buff, 0, TRANSPARENT_MAX_SIZE); + addTransparentData(buff, afpdata); + } + int remainingTransData = data.length / TRANSPARENT_MAX_SIZE; + buff = new byte[remainingTransData]; + System.arraycopy(data, currIndex, buff, 0, remainingTransData); + addTransparentData(buff, afpdata); + } + currentX = -1; - int s = afpdata.size(); + int dataSize = afpdata.size(); - if (_baos.size() + s > MAX_SIZE) { - _currentXCoordinate = -1; - _currentYCoordinate = -1; + if (baos.size() + dataSize > MAX_SIZE) { + currentX = -1; + currentY = -1; throw new MaximumSizeExceededException(); } byte[] outputdata = afpdata.toByteArray(); - _baos.write(outputdata, 0, outputdata.length); + baos.write(outputdata, 0, outputdata.length); + } + private int ensurePositive(int value) { + if (value < 0) { + return 0; + } + return value; } /** * Drawing of lines using the starting and ending coordinates, thickness and * colour arguments. * - * @param x1 - * The starting X coordinate. - * @param y1 - * The starting Y coordinate. - * @param x2 - * The ending X coordinate. - * @param y2 - * The ending Y coordinate. - * @param thickness - * The line thickness. - * @param orientation - * The orientation of the text data. - * @param col - * The text color. + * @param lineDataInfo the line data information. + * @throws MaximumSizeExceededException + * thrown if the maximum number of line data has been exceeded */ - public void createLineData(int x1, int y1, int x2, int y2, int thickness, - int orientation, Color col) throws MaximumSizeExceededException { + public void createLineData(AFPLineDataInfo lineDataInfo) throws MaximumSizeExceededException { ByteArrayOutputStream afpdata = new ByteArrayOutputStream(); - if (_currentOrientation != orientation) { + int orientation = lineDataInfo.getRotation(); + if (currentOrientation != orientation) { setTextOrientation(orientation, afpdata); - _currentOrientation = orientation; + currentOrientation = orientation; } // Avoid unnecessary specification of the Y coordinate - if (y1 != _currentYCoordinate) { + int y1 = ensurePositive(lineDataInfo.getY1()); + if (y1 != currentY) { absoluteMoveBaseline(y1, afpdata); } // Avoid unnecessary specification of the X coordinate - if (x1 != _currentXCoordinate) { + int x1 = ensurePositive(lineDataInfo.getX1()); + if (x1 != currentX) { absoluteMoveInline(x1, afpdata); } - if (!col.equals(_currentColor)) { - setExtendedTextColor(col, afpdata); - _currentColor = col; + Color color = lineDataInfo.getColor(); + if (!color.equals(currentColor)) { + setExtendedTextColor(color, afpdata); + currentColor = color; } + int x2 = ensurePositive(lineDataInfo.getX2()); + int y2 = ensurePositive(lineDataInfo.getY2()); + int thickness = lineDataInfo.getThickness(); if (y1 == y2) { drawIaxisRule(x2 - x1, thickness, afpdata); } else if (x1 == x2) { drawBaxisRule(y2 - y1, thickness, afpdata); } else { + log.error("Invalid axis rule unable to draw line"); return; } - int s = afpdata.size(); + int dataSize = afpdata.size(); - if (_baos.size() + s > MAX_SIZE) { - _currentXCoordinate = -1; - _currentYCoordinate = -1; + if (baos.size() + dataSize > MAX_SIZE) { + currentX = -1; + currentY = -1; throw new MaximumSizeExceededException(); } byte[] outputdata = afpdata.toByteArray(); - _baos.write(outputdata, 0, outputdata.length); - + baos.write(outputdata, 0, outputdata.length); } /** @@ -436,141 +421,117 @@ public class PresentationTextData extends AbstractAFPObject { * and minutes. * * @param orientation - * The text orientation (0,90, 180, 270). - * @param afpdata + * The text orientation (0, 90, 180, 270). + * @param os * The output stream to which data should be written. */ private void setTextOrientation(int orientation, - ByteArrayOutputStream afpdata) { - - afpdata.write(new byte[] { 0x06, (byte) 0xF7, }, 0, 2); - + ByteArrayOutputStream os) { + os.write(new byte[] {0x06, (byte) 0xF7, }, 0, 2); switch (orientation) { - case 90: - afpdata.write(0x2D); - afpdata.write(0x00); - afpdata.write(0x5A); - afpdata.write(0x00); - break; - case 180: - afpdata.write(0x5A); - afpdata.write(0x00); - afpdata.write(0x87); - afpdata.write(0x00); - break; - case 270: - afpdata.write(0x87); - afpdata.write(0x00); - afpdata.write(0x00); - afpdata.write(0x00); - break; - default: - afpdata.write(0x00); - afpdata.write(0x00); - afpdata.write(0x2D); - afpdata.write(0x00); - break; + case 90: + os.write(0x2D); + os.write(0x00); + os.write(0x5A); + os.write(0x00); + break; + case 180: + os.write(0x5A); + os.write(0x00); + os.write(0x87); + os.write(0x00); + break; + case 270: + os.write(0x87); + os.write(0x00); + os.write(0x00); + os.write(0x00); + break; + default: + os.write(0x00); + os.write(0x00); + os.write(0x2D); + os.write(0x00); + break; } - } /** * The Set Extended Text Color control sequence specifies a color value and - * defines the color space and encoding for that value. The specified color - * value is applied to foreground areas of the text presentation space. - * This is a modal control sequence. + * defines the color space and encoding for that value. The specified color + * value is applied to foreground areas of the text presentation space. This + * is a modal control sequence. * * @param col * The color to be set. - * @param afpdata + * @param os * The output stream to which data should be written. */ - private void setExtendedTextColor(Color col, - ByteArrayOutputStream afpdata) { - - afpdata.write(new byte[] { - 15 // Control sequence length - , (byte)0x81 // Control sequence function type - , 0x00 // Reserved; must be zero - , 0x01 // Color space - 0x01 = RGB - , 0x00 // Reserved; must be zero - , 0x00 // Reserved; must be zero - , 0x00 // Reserved; must be zero - , 0x00 // Reserved; must be zero - , 8 // Number of bits in component 1 - , 8 // Number of bits in component 2 - , 8 // Number of bits in component 3 - , 0 // Number of bits in component 4 - , (byte)(col.getRed()) // Red intensity - , (byte)(col.getGreen()) // Green intensity - , (byte)(col.getBlue()) // Blue intensity - }, 0, 15); - + private void setExtendedTextColor(Color col, ByteArrayOutputStream os) { + byte[] colorData = new byte[] { + 15, // Control sequence length + (byte) 0x81, // Control sequence function type + 0x00, // Reserved; must be zero + 0x01, // Color space - 0x01 = RGB + 0x00, // Reserved; must be zero + 0x00, // Reserved; must be zero + 0x00, // Reserved; must be zero + 0x00, // Reserved; must be zero + 8, // Number of bits in component 1 + 8, // Number of bits in component 2 + 8, // Number of bits in component 3 + 0, // Number of bits in component 4 + (byte) (col.getRed()), // Red intensity + (byte) (col.getGreen()), // Green intensity + (byte) (col.getBlue()), // Blue intensity + }; + + os.write(colorData, 0, colorData.length); } /** - * //TODO - * This is a modal control sequence. + * //TODO This is a modal control sequence. * * @param incr * The increment to be set. - * @param afpdata + * @param os * The output stream to which data should be written. */ private void setVariableSpaceCharacterIncrement(int incr, - ByteArrayOutputStream afpdata) { - + ByteArrayOutputStream os) { byte[] b = BinaryUtils.convert(incr, 2); - afpdata.write(new byte[] { - 4 // Control sequence length - , (byte)0xC5 // Control sequence function type - , b[0] - , b[1] - }, 0, 4); - + os.write(new byte[] { + 4, // Control sequence length + (byte) 0xC5, // Control sequence function type + b[0], b[1] }, + 0, 4); } /** - * //TODO - * This is a modal control sequence. + * //TODO This is a modal control sequence. * * @param incr * The increment to be set. - * @param afpdata + * @param os * The output stream to which data should be written. */ - private void setInterCharacterAdjustment(int incr, - ByteArrayOutputStream afpdata) { - + private void setInterCharacterAdjustment(int incr, ByteArrayOutputStream os) { byte[] b = BinaryUtils.convert(Math.abs(incr), 2); - - afpdata.write(new byte[] { - 5 // Control sequence length - , (byte)0xC3 // Control sequence function type - , b[0] - , b[1] - , (byte)(incr >= 0 ? 0 : 1) // Direction - }, 0, 5); - + os.write(new byte[] { + 5, // Control sequence length + (byte) 0xC3, // Control sequence function type + b[0], b[1], (byte) (incr >= 0 ? 0 : 1) // Direction + }, 0, 5); } - /** - * Accessor method to write the AFP datastream for - * the text data. - * @param os The stream to write to - * @throws java.io.IOException - */ - public void writeDataStream(OutputStream os) - throws IOException { - - byte[] data = _baos.toByteArray(); + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = baos.toByteArray(); byte[] size = BinaryUtils.convert(data.length - 1, 2); data[1] = size[0]; data[2] = size[1]; - os.write(data); - } /** @@ -581,19 +542,15 @@ public class PresentationTextData extends AbstractAFPObject { * method terminates the control sequence. * * @throws MaximumSizeExceededException + * thrown in the event that maximum size has been exceeded */ public void endControlSequence() throws MaximumSizeExceededException { - byte[] data = new byte[2]; 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/afp/modca/PresentationTextDescriptor.java index 3858f4169..ef2696da8 100644 --- a/src/java/org/apache/fop/render/afp/modca/PresentationTextDescriptor.java +++ b/src/java/org/apache/fop/afp/modca/PresentationTextDescriptor.java @@ -17,11 +17,12 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.modca; import java.io.IOException; import java.io.OutputStream; -import org.apache.fop.render.afp.tools.BinaryUtils; + +import org.apache.fop.afp.util.BinaryUtils; /** * The Presentation Text Descriptor specifies the units of measure for the @@ -50,42 +51,34 @@ public class PresentationTextDescriptor extends AbstractDescriptor { /** * 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 PresentationTextDescriptor(int width, int height, - int widthResolution, int heightResolution) { - super(width, height, widthResolution, heightResolution); + int widthRes, int heightRes) { + super(width, height, widthRes, heightRes); } - /** - * Accessor method to write the AFP datastream for the Presentation Text Descriptor - * @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 { - + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { byte[] data = new byte[23]; - data[0] = 0x5A; - data[1] = 0x00; + + copySF(data, Type.MIGRATION, Category.PRESENTATION_TEXT); + + data[1] = 0x00; // length data[2] = 0x16; - data[3] = (byte) 0xD3; - data[4] = (byte) 0xB1; - data[5] = (byte) 0x9B; - data[6] = 0x00; - data[7] = 0x00; - data[8] = 0x00; + 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]; @@ -103,7 +96,6 @@ public class PresentationTextDescriptor extends AbstractDescriptor { data[22] = 0x00; os.write(data); - } }
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/modca/PresentationTextObject.java b/src/java/org/apache/fop/afp/modca/PresentationTextObject.java new file mode 100644 index 000000000..4a8bbbb18 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/PresentationTextObject.java @@ -0,0 +1,174 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.List; + +import org.apache.fop.afp.AFPLineDataInfo; +import org.apache.fop.afp.AFPTextDataInfo; + +/** + * The Presentation Text object is the data object used in document processing + * environments for representing text which has been prepared for presentation. + * Text, as used here, means an ordered string of characters, such as graphic + * symbols, numbers, and letters, that are suitable for the specific purpose of + * representing coherent information. Text which has been prepared for + * presentation has been reduced to a primitive form through explicit + * specification of the characters and their placement in the presentation + * space. Control sequences which designate specific control functions may be + * embedded within the text. These functions extend the primitive form by + * applying specific characteristics to the text when it is presented. The + * collection of the graphic characters and control codes is called Presentation + * Text, and the object that contains the Presentation Text is called the + * PresentationText object. + */ +public class PresentationTextObject extends AbstractNamedAFPObject { + + /** + * The current presentation text data + */ + private PresentationTextData currentPresentationTextData = null; + + /** + * The presentation text data list + */ + private List/*<PresentationTextData>*/ presentationTextDataList = null; + + /** + * Construct a new PresentationTextObject for the specified name argument, + * the name should be an 8 character identifier. + * + * @param name the name of this presentation object + */ + public PresentationTextObject(String name) { + super(name); + } + + /** + * Create the presentation text data for the byte array of data. + * + * @param textDataInfo + * The afp text data + * @throws UnsupportedEncodingException thrown if character encoding is not supported + */ + public void createTextData(AFPTextDataInfo textDataInfo) throws UnsupportedEncodingException { + if (currentPresentationTextData == null) { + startPresentationTextData(); + } + try { + currentPresentationTextData.createTextData(textDataInfo); + } catch (MaximumSizeExceededException msee) { + endPresentationTextData(); + createTextData(textDataInfo); + } catch (UnsupportedEncodingException e) { + endPresentationTextData(); + throw e; + } + } + + /** + * Drawing of lines using the starting and ending coordinates, thickness and + * orientation arguments. + * + * @param lineDataInfo the line data information. + */ + public void createLineData(AFPLineDataInfo lineDataInfo) { + if (currentPresentationTextData == null) { + startPresentationTextData(); + } + try { + currentPresentationTextData.createLineData(lineDataInfo); + } catch (MaximumSizeExceededException msee) { + endPresentationTextData(); + createLineData(lineDataInfo); + } + } + + /** + * Helper method to mark the start of the presentation text data + */ + private void startPresentationTextData() { + if (presentationTextDataList == null) { + presentationTextDataList = new java.util.ArrayList/*<PresentationTextData>*/(); + } + if (presentationTextDataList.size() == 0) { + currentPresentationTextData = new PresentationTextData(true); + } else { + currentPresentationTextData = new PresentationTextData(); + } + presentationTextDataList.add(currentPresentationTextData); + } + + /** + * Helper method to mark the end of the presentation text data + */ + private void endPresentationTextData() { + this.currentPresentationTextData = null; + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.BEGIN, Category.PRESENTATION_TEXT); + os.write(data); + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + writeObjects(this.presentationTextDataList, os); + } + + /** {@inheritDoc} */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.END, Category.PRESENTATION_TEXT); + os.write(data); + } + + /** + * A control sequence is a sequence of bytes that specifies a control + * function. A control sequence consists of a control sequence introducer + * and zero or more parameters. The control sequence can extend multiple + * presentation text data objects, but must eventually be terminated. This + * method terminates the control sequence. + */ + public void endControlSequence() { + if (currentPresentationTextData == null) { + startPresentationTextData(); + } + try { + currentPresentationTextData.endControlSequence(); + } catch (MaximumSizeExceededException msee) { + endPresentationTextData(); + endControlSequence(); + } + } + + /** {@inheritDoc} */ + public String toString() { + if (presentationTextDataList != null) { + return presentationTextDataList.toString(); + } + return null; + } +} diff --git a/src/java/org/apache/fop/afp/modca/Registry.java b/src/java/org/apache/fop/afp/modca/Registry.java new file mode 100644 index 000000000..481a72afd --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/Registry.java @@ -0,0 +1,288 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.modca; + +import java.util.Collections; + +import org.apache.xmlgraphics.util.MimeConstants; + +/** + * MOD:CA Registry of object types + */ +public final class Registry { + /** IOB supported object types */ + private static final byte COMPID_IOCA_FS10 = 5; + private static final byte COMPID_IOCA_FS11 = 11; + private static final byte COMPID_IOCA_FS40 = 55; + private static final byte COMPID_IOCA_FS45 = 12; + private static final byte COMPID_EPS = 13; + private static final byte COMPID_TIFF = 14; + private static final byte COMPID_GIF = 22; + private static final byte COMPID_JFIF = 23; // jpeg file interchange format + private static final byte COMPID_PDF_SINGLE_PAGE = 25; + private static final byte COMPID_PCL_PAGE_OBJECT = 34; + + private static final byte COMPID_TRUETYPE_OPENTYPE_FONT_RESOURCE_OBJECT = 51; + private static final byte COMPID_TRUETYPE_OPENTYPE_FONT_COLLECTION_RESOURCE_OBJECT = 53; + + /** mime type entry mapping */ + private final java.util.Map/*<String, ObjectType>*/ mimeObjectTypeMap + = Collections.synchronizedMap( + new java.util.HashMap/*<String, ObjectType>*/()); + + /** singleton instance */ + private static Registry instance = null; + + /** + * Returns a single instance of a MO:DCA Registry + * + * @return a single instance of an MO:DCA Registry + */ + public static Registry getInstance() { + synchronized (Registry.class) { + if (instance == null) { + instance = new Registry(); + } + } + return instance; + } + + /** + * private constructor + */ + private Registry() { + init(); + } + + /** + * Initializes the mimetype map + */ + private void init() { + mimeObjectTypeMap.put( + MimeConstants.MIME_AFP_IOCA_FS10, + new ObjectType( + COMPID_IOCA_FS10, + new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x05}, + "IOCA FS10", + true, + MimeConstants.MIME_AFP_IOCA_FS10 + ) + ); + mimeObjectTypeMap.put( + MimeConstants.MIME_AFP_IOCA_FS11, + new ObjectType( + COMPID_IOCA_FS11, + new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x11}, + "IOCA FS11", + true, + MimeConstants.MIME_AFP_IOCA_FS11 + ) + ); +// mimeObjectTypeMap.put( +// MimeConstants.MIME_AFP_IOCA_FS40, +// new ObjectType( +// COMPID_IOCA_FS40, +// new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x37}, +// "IOCA FS40", +// true, +// MimeConstants.MIME_AFP_IOCA_FS40 +// ) +//); + mimeObjectTypeMap.put( + MimeConstants.MIME_AFP_IOCA_FS45, + new ObjectType( + COMPID_IOCA_FS45, + new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x12}, + "IOCA FS45", + true, + MimeConstants.MIME_AFP_IOCA_FS45 + ) + ); + mimeObjectTypeMap.put( + MimeConstants.MIME_EPS, + new ObjectType( + COMPID_EPS, + new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x0D}, + "Encapsulated Postscript", + true, + MimeConstants.MIME_EPS + ) + ); + mimeObjectTypeMap.put( + MimeConstants.MIME_TIFF, + new ObjectType( + COMPID_TIFF, + new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x0E}, + "TIFF", + true, + MimeConstants.MIME_TIFF + ) + ); + mimeObjectTypeMap.put( + MimeConstants.MIME_GIF, + new ObjectType( + COMPID_GIF, + new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x16}, + "GIF", + true, + MimeConstants.MIME_GIF + ) + ); + mimeObjectTypeMap.put( + MimeConstants.MIME_JPEG, + new ObjectType( + COMPID_JFIF, + new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x17}, + "JFIF", + true, + MimeConstants.MIME_JPEG + ) + ); + mimeObjectTypeMap.put(MimeConstants.MIME_PDF, + new ObjectType( + COMPID_PDF_SINGLE_PAGE, + new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x19}, + "PDF Single-page Object", + true, + MimeConstants.MIME_PDF + ) + ); + mimeObjectTypeMap.put( + MimeConstants.MIME_PCL, + new ObjectType( + COMPID_PCL_PAGE_OBJECT, + new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x22}, + "PCL Page Object", + true, + MimeConstants.MIME_PCL + ) + ); +// mimeObjectTypeMap.put( +// null, +// new ObjectType( +// COMPID_TRUETYPE_OPENTYPE_FONT_RESOURCE_OBJECT, +// new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x33}, +// "TrueType/OpenType Font Resource Object", +// true, +// null +// ) +// ); +// mimeObjectTypeMap.put( +// null, +// new ObjectType( +// COMPID_TRUETYPE_OPENTYPE_FONT_COLLECTION_RESOURCE_OBJECT, +// new byte[] {0x06, 0x07, 0x2B, 0x12, 0x00, 0x04, 0x01, 0x01, 0x35}, +// "TrueType/OpenType Font Collection Resource Object", +// true, +// null +// ) +// ); + } + + /** + * Returns the MOD:CA object type given a mimetype + * + * @param mimeType the object mimetype + * @return the MOD:CA object type + */ + public ObjectType getObjectType(String mimeType) { + return (ObjectType)mimeObjectTypeMap.get(mimeType); + } + + /** + * Encapsulates a MOD:CA Registry Object Type entry + */ + public class ObjectType { + private final byte componentId; + private final byte[] oid; + private final String name; + private final boolean includable; + private final String mimeType; + + /** + * Main constructor + * + * @param componentId the component id of this object type + * @param oid the object id of this object type + * @param name the object type name + * @param includable true if this object can be included with an IOB structured field + * @param mimeType the mime type associated with this object type + */ + public ObjectType(byte componentId, byte[] oid, String name, + boolean includable, String mimeType) { + this.componentId = componentId; + this.oid = oid; + this.name = name; + this.includable = includable; + this.mimeType = mimeType; + } + + /** + * Returns a MOD:CA object type OID from a given a componentId + * + * @return the corresponding object type id for a given component id + * or null if the component id is unknown and the object type OID was not found. + */ + public byte[] getOID() { + return this.oid; + } + + /** + * Returns the object type name for the given componentId + * + * @return the object type name for the given componentId + */ + public String getName() { + return this.name; + } + + /** + * Returns the compontentId for this entry + * + * @return the compontentId for this entry + */ + public byte getComponentId() { + return this.componentId; + } + + /** + * Returns true if this component can be included with an IOB structured field + * + * @return true if this component can be included with an IOB structured field + */ + public boolean isIncludable() { + return this.includable; + } + + /** + * Returns the mime type associated with this object type + * + * @return the mime type associated with this object type + */ + public String getMimeType() { + return this.mimeType; + } + + /** {@inheritDoc} */ + public String toString() { + return this.getName(); + } + } +} diff --git a/src/java/org/apache/fop/afp/modca/ResourceEnvironmentGroup.java b/src/java/org/apache/fop/afp/modca/ResourceEnvironmentGroup.java new file mode 100644 index 000000000..2e4f57314 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/ResourceEnvironmentGroup.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +import org.apache.fop.afp.Completable; + +/** + * A Resource Environment Group contains a set of resources for a document + * or for a group of pages in a document. + */ +public class ResourceEnvironmentGroup extends AbstractEnvironmentGroup implements Completable { + + /** default name for the resource group */ + private static final String DEFAULT_NAME = "REG00001"; + + /** the maps data resources contained in this resource environment group */ + private List/*<MapDataResource>*/ mapDataResources = null; + + /** the maps page overlays contained in this resource environment group */ + private List mapPageOverlays = null; + + /** the pre-process presentation objects contained in this resource environment group */ + private List/*<PreprocessPresentationObject>*/ preProcessPresentationObjects = null; + + /** the resource environment group state */ + private boolean complete = false; + + /** + * Default constructor + */ + public ResourceEnvironmentGroup() { + this(DEFAULT_NAME); + } + + private List/*<MapDataResource>*/ getMapDataResources() { + if (mapDataResources == null) { + this.mapDataResources = new java.util.ArrayList/*<MapDataResource>*/(); + } + return this.mapDataResources; + } + + private List getMapPageOverlays() { + if (mapPageOverlays == null) { + this.mapPageOverlays = new java.util.ArrayList(); + } + return this.mapPageOverlays; + } + + private List/*<PreprocessPresentationObject>*/ getPreprocessPresentationObjects() { + if (preProcessPresentationObjects == null) { + this.preProcessPresentationObjects + = new java.util.ArrayList/*<PreprocessPresentationObject>*/(); + } + return this.preProcessPresentationObjects; + } + + /** + * Constructor for the ResourceEnvironmentGroup, this takes a + * name parameter which must be 8 characters long. + * @param name the resource environment group name + */ + public ResourceEnvironmentGroup(String name) { + super(name); + } + +// /** +// * Adds an AFP object mapping reference to this resource environment group +// * @param obj the object to add +// */ +// public void addObject(AbstractStructuredAFPObject obj) { +// getMapDataResources().add(new MapDataResource(obj)); +// createOverlay(obj.get); +// getPreprocessPresentationObjects().add(new PreprocessPresentationObject(obj)); +// } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.BEGIN, Category.RESOURCE_ENVIROMENT_GROUP); + os.write(data); + } + + /** {@inheritDoc} */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.END, Category.RESOURCE_ENVIROMENT_GROUP); + os.write(data); + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + writeObjects(mapDataResources, os); + writeObjects(mapPageOverlays, os); + writeObjects(preProcessPresentationObjects, os); + } + + /** {@inheritDoc} */ + public void setComplete(boolean complete) { + this.complete = complete; + } + + /** {@inheritDoc} */ + public boolean isComplete() { + return complete; + } + +} diff --git a/src/java/org/apache/fop/afp/modca/ResourceGroup.java b/src/java/org/apache/fop/afp/modca/ResourceGroup.java new file mode 100644 index 000000000..2218998a0 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/ResourceGroup.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.Set; + +import org.apache.fop.afp.Streamable; + +/** + * A Resource Group contains a set of overlays. + */ +public class ResourceGroup extends AbstractNamedAFPObject { + + /** Set of resource uri */ + private final Set/*<String>*/ resourceSet = new java.util.HashSet/*<String>*/(); + + /** + * Constructor for the ResourceGroup, this takes a + * name parameter which must be 8 characters long. + * + * @param name the resource group name + */ + public ResourceGroup(String name) { + super(name); + } + + /** + * Add this named object to this resource group + * + * @param namedObject a named object + * @throws IOException thrown if an I/O exception of some sort has occurred. + */ + public void addObject(AbstractNamedAFPObject namedObject) throws IOException { + resourceSet.add(namedObject); + } + + /** + * Returns the number of resources contained in this resource group + * + * @return the number of resources contained in this resource group + */ + public int getResourceCount() { + return resourceSet.size(); + } + + /** + * Returns true if the resource exists within this resource group, + * false otherwise. + * + * @param uri the uri of the resource + * @return true if the resource exists within this resource group + */ + public boolean resourceExists(String uri) { + return resourceSet.contains(uri); + } + + /** {@inheritDoc} */ + public void writeStart(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.BEGIN, Category.RESOURCE_GROUP); + os.write(data); + } + + /** {@inheritDoc} */ + public void writeContent(OutputStream os) throws IOException { + Iterator it = resourceSet.iterator(); + while (it.hasNext()) { + Object object = it.next(); + if (object instanceof Streamable) { + Streamable streamableObject = (Streamable)object; + streamableObject.writeToStream(os); + } + } + } + + /** {@inheritDoc} */ + public void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.END, Category.RESOURCE_GROUP); + os.write(data); + } + + /** {@inheritDoc} */ + public String toString() { + return this.name + " " + resourceSet/*getResourceMap()*/; + } +} diff --git a/src/java/org/apache/fop/afp/modca/ResourceObject.java b/src/java/org/apache/fop/afp/modca/ResourceObject.java new file mode 100644 index 000000000..0f555a42e --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/ResourceObject.java @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.modca.triplets.ResourceObjectTypeTriplet; +import org.apache.fop.afp.util.BinaryUtils; + +/** + * This resource structured field begins an envelope that is used to carry + * resource objects in print-file-level (external) resource groups. + */ +public class ResourceObject extends AbstractNamedAFPObject { + + /** graphics object type */ + public static final byte TYPE_GRAPHIC = 0x03; + + /** barcode object type */ + public static final byte TYPE_BARCODE = 0x05; + + /** image object type */ + public static final byte TYPE_IMAGE = 0x06; + + /** font character set type */ + public static final byte TYPE_FONT_CHARACTER_SET = 0x40; + + /** code page type */ + public static final byte TYPE_CODE_PAGE = 0x41; + + /** coded font type */ + public static final byte TYPE_CODED_FONT = 0x42; + + /** object container type */ + public static final byte TYPE_OBJECT_CONTAINER = (byte) 0x92; + + /** document object type */ + public static final byte TYPE_DOCUMENT = (byte) 0xA8; + + /** page segment object type */ + public static final byte TYPE_PAGE_SEGMENT = (byte) 0xFB; + + /** overlay object type */ + public static final byte TYPE_OVERLAY_OBJECT = (byte) 0xFC; + + /** page def type */ + public static final byte TYPE_PAGEDEF = (byte) 0xFD; + + /** form def type */ + public static final byte TYPE_FORMDEF = (byte) 0xFE; + + private AbstractNamedAFPObject namedObject; + + /** + * Default constructor + * + * @param name the name of this resource (reference id) + */ + public ResourceObject(String name) { + super(name); + } + + /** + * Sets the data object referenced by this resource object + * + * @param namedObject the named data object + */ + public void setDataObject(AbstractNamedAFPObject namedObject) { + this.namedObject = namedObject; + } + + /** + * Returns the data object referenced by this resource object + * + * @return the data object referenced by this resource object + */ + public AbstractNamedAFPObject getDataObject() { + return namedObject; + } + + /** {@inheritDoc} */ + protected void writeStart(OutputStream os) throws IOException { + super.writeStart(os); + + byte[] data = new byte[19]; + copySF(data, Type.BEGIN, Category.NAME_RESOURCE); + + // Set the total record length + int tripletDataLength = getTripletDataLength(); + byte[] len = BinaryUtils.convert(18 + tripletDataLength, 2); + data[1] = len[0]; // Length byte 1 + data[2] = len[1]; // Length byte 2 + + // Set reserved bits + data[17] = 0x00; // Reserved + data[18] = 0x00; // Reserved + + os.write(data); + + // Write triplets + writeTriplets(os); + } + + /** {@inheritDoc} */ + protected void writeContent(OutputStream os) throws IOException { + if (namedObject != null) { + namedObject.writeToStream(os); + } + } + + /** {@inheritDoc} */ + protected void writeEnd(OutputStream os) throws IOException { + byte[] data = new byte[17]; + copySF(data, Type.END, Category.NAME_RESOURCE); + os.write(data); + } + + /** {@inheritDoc} */ + public String toString() { + return this.getName(); + } + + /** + * Sets Resource Object Type triplet + * + * @param type the resource object type + */ + public void setType(byte type) { + getTriplets().add(new ResourceObjectTypeTriplet(type)); + } + +} diff --git a/src/java/org/apache/fop/afp/modca/StreamedResourceGroup.java b/src/java/org/apache/fop/afp/modca/StreamedResourceGroup.java new file mode 100644 index 000000000..65df33ae4 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/StreamedResourceGroup.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.Completable; + +/** + * A print-file resource group + */ +public class StreamedResourceGroup extends ResourceGroup implements Completable { + /** the outputstream to write to */ + private final OutputStream os; + + private boolean started = false; + + private boolean complete = false; + + /** + * Main constructor + * + * @param name the resource group name + * @param os the outputstream + */ + public StreamedResourceGroup(String name, OutputStream os) { + super(name); + this.os = os; + } + + /** + * Adds a resource to the external resource group + * + * @param namedObject a named object + * @throws IOException thrown if an I/O exception of some sort has occurred. + */ + public void addObject(AbstractNamedAFPObject namedObject) throws IOException { + if (!started) { + writeStart(os); + started = true; + } + try { + namedObject.writeToStream(os); + } finally { + os.flush(); + } + } + + /** + * Closes this external resource group file + * + * @throws IOException thrown if an I/O exception of some sort has occurred. + */ + public void close() throws IOException { + writeEnd(os); + complete = true; + } + + /** + * Returns the outputstream + * + * @return the outputstream + */ + public OutputStream getOutputStream() { + return this.os; + } + + /** {@inheritDoc} */ + public void setComplete(boolean complete) { + this.complete = complete; + } + + /** {@inheritDoc} */ + public boolean isComplete() { + return this.complete; + } + +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/TagLogicalElement.java b/src/java/org/apache/fop/afp/modca/TagLogicalElement.java index 937f2019a..2e1fa5e07 100644 --- a/src/java/org/apache/fop/render/afp/modca/TagLogicalElement.java +++ b/src/java/org/apache/fop/afp/modca/TagLogicalElement.java @@ -17,13 +17,14 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.modca; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; -import org.apache.fop.render.afp.tools.BinaryUtils; +import org.apache.fop.afp.AFPConstants; +import org.apache.fop.afp.util.BinaryUtils; /** * A Tag Logical Element structured field assigns an attribute name and an @@ -49,72 +50,41 @@ public class TagLogicalElement extends AbstractAFPObject { /** * Name of the key, used within the TLE */ - private String tleName = null; + private String name = null; /** * Value returned by the key */ - private String tleValue = null; - - /** - * Byte representaion of the name - */ - private byte[] tleByteName = null; - - /** - * Byte representaion of the value - */ - private byte[] tleByteValue = null; + private String value = null; /** * Construct a tag logical element with the name and value specified. + * * @param name the name of the tag logical element * @param value the value of the tag logical element */ public TagLogicalElement(String name, String value) { - - this.tleName = name; - this.tleValue = value; - - try { - - this.tleByteName = name.getBytes(AFPConstants.EBCIDIC_ENCODING); - this.tleByteValue = value.getBytes(AFPConstants.EBCIDIC_ENCODING); - - } catch (UnsupportedEncodingException usee) { - - this.tleByteName = name.getBytes(); - this.tleByteValue = value.getBytes(); - log.warn( - "Constructor:: UnsupportedEncodingException translating the name " - + name); - - } - + this.name = name; + this.value = value; } - /** - * Accessor method to obtain the byte array AFP datastream for the - * TagLogicalElement. - * @param os The outputsteam stream - * @throws java.io.IOException if an I/O exception occurred - */ - public void writeDataStream(OutputStream os) throws IOException { + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { - byte[] data = new byte[17 + tleName.length() + tleValue.length()]; + byte[] data = new byte[17 + name.length() + value.length()]; data[0] = 0x5A; // Set the total record length byte[] rl1 - = BinaryUtils.convert(16 + tleName.length() + tleValue.length(), 2); + = BinaryUtils.convert(16 + name.length() + value.length(), 2); //Ignore first byte data[1] = rl1[0]; data[2] = rl1[1]; // Structured field ID for a TLE data[3] = (byte) 0xD3; - data[4] = (byte) 0xA0; - data[5] = (byte) 0x90; + data[4] = (byte) Type.ATTRIBUTE; + data[5] = (byte) Category.PROCESS_ELEMENT; data[6] = 0x00; // Reserved data[7] = 0x00; // Reserved @@ -122,12 +92,25 @@ public class TagLogicalElement extends AbstractAFPObject { //Use 2 triplets, attrubute name and value (the key for indexing) - byte[] rl2 = BinaryUtils.convert(tleName.length() + 4, 1); + byte[] rl2 = BinaryUtils.convert(name.length() + 4, 1); data[9] = rl2[0]; // length of the triplet, including this field data[10] = 0x02; //Identifies it as a FQN triplet data[11] = 0x0B; // GID format data[12] = 0x00; + byte[] tleByteName = null; + byte[] tleByteValue = null; + try { + tleByteName = name.getBytes(AFPConstants.EBCIDIC_ENCODING); + tleByteValue = value.getBytes(AFPConstants.EBCIDIC_ENCODING); + } catch (UnsupportedEncodingException usee) { + tleByteName = name.getBytes(); + tleByteValue = value.getBytes(); + log.warn( + "Constructor:: UnsupportedEncodingException translating the name " + + name); + } + int pos = 13; for (int i = 0; i < tleByteName.length; i++) { data[pos++] = tleByteName[i]; diff --git a/src/java/org/apache/fop/render/afp/modca/TagLogicalElementBean.java b/src/java/org/apache/fop/afp/modca/TagLogicalElementBean.java index 29ac9eb5d..5d4523777 100644 --- a/src/java/org/apache/fop/render/afp/modca/TagLogicalElementBean.java +++ b/src/java/org/apache/fop/afp/modca/TagLogicalElementBean.java @@ -17,7 +17,7 @@ /* $Id$ */ -package org.apache.fop.render.afp.modca; +package org.apache.fop.afp.modca; /** * The TagLogicalElementBean provides a bean for holding the attributes of @@ -34,6 +34,7 @@ public class TagLogicalElementBean { /** * Constructor for the TagLogicalElementBean. + * * @param key the key attribute * @param value the value attribute */ @@ -44,6 +45,7 @@ public class TagLogicalElementBean { /** * Getter for the key attribute. + * * @return the key */ public String getKey() { @@ -52,6 +54,7 @@ public class TagLogicalElementBean { /** * Getter for the value attribute. + * * @return the value */ public String getValue() { diff --git a/src/java/org/apache/fop/afp/modca/package.html b/src/java/org/apache/fop/afp/modca/package.html new file mode 100644 index 000000000..572743558 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/package.html @@ -0,0 +1,23 @@ +<!-- + 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.html 643433 2008-04-01 15:08:24Z acumiskey $ --> +<HTML> +<TITLE>org.apache.fop.afp.modca Package</TITLE> +<BODY> +<P>Contains a collection of AFP Mixed Object Document Content Architecture (MO:DCA) structured objects.</P> +</BODY> +</HTML>
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/modca/triplets/AbstractTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/AbstractTriplet.java new file mode 100644 index 000000000..4e75d4204 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/AbstractTriplet.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.afp.modca.triplets; + +import org.apache.fop.afp.Streamable; +import org.apache.fop.afp.StructuredData; + +/** + * A simple implementation of a MOD:CA triplet + */ +public abstract class AbstractTriplet implements Streamable, StructuredData { + public static final byte CODED_GRAPHIC_CHARACTER_SET_GLOBAL_IDENTIFIER = 0x01; + + /** Triplet identifiers */ + public static final byte FULLY_QUALIFIED_NAME = 0x02; + public static final byte MAPPING_OPTION = 0x04; + public static final byte OBJECT_CLASSIFICATION = 0x10; + public static final byte MODCA_INTERCHANGE_SET = 0x18; + public static final byte FONT_DESCRIPTOR_SPECIFICATION = 0x1F; + public static final byte OBJECT_FUNCTION_SET_SPECIFICATION = 0x21; + public static final byte EXTENDED_RESOURCE_LOCAL_IDENTIFIER = 0x22; + public static final byte RESOURCE_LOCAL_IDENTIFIER = 0x24; + public static final byte RESOURCE_SECTION_NUMBER = 0x25; + public static final byte CHARACTER_ROTATION = 0x26; + public static final byte OBJECT_BYTE_OFFSET = 0x2D; + public static final byte ATTRIBUTE_VALUE = 0x36; + public static final byte DESCRIPTOR_POSITION = 0x43; + public static final byte MEDIA_EJECT_CONTROL = 0x45; + public static final byte PAGE_OVERLAY_CONDITIONAL_PROCESSING = 0x46; + public static final byte RESOURCE_USAGE_ATTRIBUTE = 0x47; + public static final byte MEASUREMENT_UNITS = 0x4B; + public static final byte OBJECT_AREA_SIZE = 0x4C; + public static final byte AREA_DEFINITION = 0x4D; + public static final byte COLOR_SPECIFICATION = 0x4E; + public static final byte ENCODING_SCHEME_ID = 0x50; + public static final byte MEDIUM_MAP_PAGE_NUMBER = 0x56; + public static final byte OBJECT_BYTE_EXTENT = 0x57; + public static final byte OBJECT_STRUCTURED_FIELD_OFFSET = 0x58; + public static final byte OBJECT_STRUCTURED_FIELD_EXTENT = 0x59; + public static final byte OBJECT_OFFSET = 0x5A; + public static final byte FONT_HORIZONTAL_SCALE_FACTOR = 0x5D; + public static final byte OBJECT_COUNT = 0x5E; + public static final byte OBJECT_DATE_AND_TIMESTAMP = 0x62; + public static final byte COMMENT = 0x65; + public static final byte MEDIUM_ORIENTATION = 0x68; + public static final byte RESOURCE_OBJECT_INCLUDE = 0x6C; + public static final byte PRESENTATION_SPACE_RESET_MIXING = 0x70; + public static final byte PRESENTATION_SPACE_MIXING_RULE = 0x71; + public static final byte UNIVERSAL_DATE_AND_TIMESTAMP = 0x72; + public static final byte TONER_SAVER = 0x74; + public static final byte COLOR_FIDELITY = 0x75; + public static final byte FONT_FIDELITY = 0x78; + public static final byte ATTRIBUTE_QUALIFIER = (byte)0x80; + public static final byte PAGE_POSITION_INFORMATION = (byte)0x81; + public static final byte PARAMETER_VALUE = (byte)0x82; + public static final byte PRESENTATION_CONTROL = (byte)0x83; + public static final byte FONT_RESOLUTION_AND_METRIC_TECHNOLOGY = (byte)0x84; + public static final byte FINISHING_OPERATION = (byte)0x85; + public static final byte TEXT_FIDELITY = (byte)0x86; + public static final byte MEDIA_FIDELITY = (byte)0x87; + public static final byte FINISHING_FIDELITY = (byte)0x88; + public static final byte DATA_OBJECT_FONT_DESCRIPTOR = (byte)0x8B; + public static final byte LOCALE_SELECTOR = (byte)0x8C; + public static final byte UP3I_FINISHING_OPERATION = (byte)0x8E; + public static final byte COLOR_MANAGEMENT_RESOURCE_DESCRIPTOR = (byte)0x91; + public static final byte RENDERING_INTENT = (byte)0x95; + public static final byte CMR_TAG_FIDELITY = (byte)0x96; + public static final byte DEVICE_APPEARANCE = (byte)0x97; + + /** the triplet identifier */ + protected final byte id; + + /** + * Constructor + * + * @param id the triplet identifier (see static definitions above) + */ + public AbstractTriplet(byte id) { + this.id = id; + } + + /** + * Returns the triplet identifier + * + * @return the triplet identifier + */ + public byte getId() { + return this.id; + } + + /** + * Returns the structured triplet data array + * + * @return the structured triplet data array + */ + public byte[] getData() { + int dataLen = getDataLength(); + byte[] data = new byte[dataLen]; + data[0] = (byte)dataLen; + data[1] = id; + return data; + } +} diff --git a/src/java/org/apache/fop/afp/modca/triplets/CommentTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/CommentTriplet.java new file mode 100644 index 000000000..9b15de8c1 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/CommentTriplet.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca.triplets; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.AFPConstants; + +/** + * An inline comment triplet. + */ +public class CommentTriplet extends AbstractTriplet { + + private final String commentString; + + public CommentTriplet(byte id, String commentString) { + super(id); + this.commentString = commentString; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 2 + commentString.length(); + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + byte[] strData = commentString.getBytes(AFPConstants.EBCIDIC_ENCODING); + System.arraycopy(strData, 0, data, 2, strData.length); + os.write(data); + } + +} diff --git a/src/java/org/apache/fop/afp/modca/triplets/DescriptorPositionTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/DescriptorPositionTriplet.java new file mode 100644 index 000000000..cff6400af --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/DescriptorPositionTriplet.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.afp.modca.triplets; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Associates an ObjectAreaPosition with and ObjectAreaDescriptor structured field + */ +public class DescriptorPositionTriplet extends AbstractTriplet { + + private final byte oapId; + + /** + * Main constructor + * + * @param oapId the object area position id + */ + public DescriptorPositionTriplet(byte oapId) { + super(DESCRIPTOR_POSITION); + this.oapId = oapId; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 3; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + data[2] = oapId; + os.write(data); + } +} diff --git a/src/java/org/apache/fop/afp/modca/triplets/ExtendedResourceLocalIdentifierTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/ExtendedResourceLocalIdentifierTriplet.java new file mode 100644 index 000000000..af9452fcb --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/ExtendedResourceLocalIdentifierTriplet.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca.triplets; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * The Extended Resource Local Identifier triplet specifies a resource type and a + * four byte local identifier or LID. The LID usually is associated with a specific + * resource name by a map structured field, such as a Map Data Resource structured + * field, or a Map Media Type structured field. + */ +public class ExtendedResourceLocalIdentifierTriplet extends AbstractTriplet { + + /** the image resource type */ + public static final byte TYPE_IMAGE_RESOURCE = 0x10; + + /** the retired value type */ + public static final byte TYPE_RETIRED_VALUE = 0x30; + + /** the retired value type */ + public static final byte TYPE_MEDIA_RESOURCE = 0x40; + + /** the resource type */ + private final byte type; + + /** the resource local id */ + private final int localId; + + /** + * Main constructor + * + * @param type the resource type + * @param localId the resource local id + */ + public ExtendedResourceLocalIdentifierTriplet(byte type, int localId) { + super(AbstractTriplet.EXTENDED_RESOURCE_LOCAL_IDENTIFIER); + this.type = type; + this.localId = localId; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + data[2] = type; + byte[] resLID = BinaryUtils.convert(localId, 4); // 4 bytes + System.arraycopy(resLID, 0, data, 3, resLID.length); + os.write(data); + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 7; + } +} diff --git a/src/java/org/apache/fop/afp/modca/triplets/FullyQualifiedNameTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/FullyQualifiedNameTriplet.java new file mode 100644 index 000000000..55653457c --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/FullyQualifiedNameTriplet.java @@ -0,0 +1,208 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.modca.triplets; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import org.apache.fop.afp.AFPConstants; + +/** + * A Fully Qualified Name triplet enable the identification and referencing of + * objects using Gloabl Identifiers (GIDs). + */ +public class FullyQualifiedNameTriplet extends AbstractTriplet { + + // Specifies how the GID will be used + + /** This GID replaces the first parameter in the structured field that contains a GID name. */ + public static final byte TYPE_REPLACE_FIRST_GID_NAME = 0x01; + + /** This triplet contains the name of a font family. */ + public static final byte TYPE_FONT_FAMILY_NAME = 0x07; + + /** This triplet contains the name of a font typeface. */ + public static final byte TYPE_FONT_TYPEFACE_NAME = 0x08; + + /** This triplet specifies a reference to the MO:DCA resource hierarchy. */ + public static final byte TYPE_MODCA_RESOURCE_HIERARCHY_REF = 0x09; + + /** The triplet contains a GID reference to a begin resource group structured field. */ + public static final byte TYPE_BEGIN_RESOURCE_GROUP_REF = 0x0A; + + /** The triplet contains a GID reference to a document attribute. */ + public static final byte TYPE_ATTRIBUTE_GID = 0x0B; + + /** The triplet contains the GID of a process element. */ + public static final byte TYPE_PROCESS_ELEMENT_GID = 0x0C; + + /** The triplet contains a reference to a begin page group structured field. */ + public static final byte TYPE_BEGIN_PAGE_GROUP_REF = 0x0D; + + /** The triplet contains a reference to a media type. */ + public static final byte TYPE_MEDIA_TYPE_REF = 0x11; + + /** The triplet contains a reference to a color management resource. */ + public static final byte TYPE_COLOR_MANAGEMENT_RESOURCE_REF = 0x41; + + /** The triplet contains a reference to a data-object font file that defines a base font. */ + public static final byte TYPE_DATA_OBJECT_FONT_BASE_FONT_ID = 0x6E; + + /** The triplet contains a reference to a data-object font file that defines a linked font. */ + public static final byte TYPE_DATA_OBJECT_FONT_LINKED_FONT_ID = 0x7E; + + /** The triplet contains a reference to a begin document structured field. */ + public static final byte TYPE_BEGIN_DOCUMENT_REF = (byte)0x83; + + /** + * The triplet contains a reference to a begin structured field associated with a resource; + * or contains a GID reference to a coded font. + */ + public static final byte TYPE_BEGIN_RESOURCE_OBJECT_REF = (byte)0x84; + + /** + * The triplet contains a GID reference to a code page that specifies the code points and + * graphic character names for a coded font. + */ + public static final byte TYPE_CODE_PAGE_NAME_REF = (byte)0x85; + + /** + * The triplet contains a GID name reference to a font character set that specifies + * a set of graphics characters. + */ + public static final byte TYPE_FONT_CHARSET_NAME_REF = (byte)0x86; + + /** The triplet contains a GID reference to a begin page structured field. */ + public static final byte TYPE_BEGIN_PAGE_REF = (byte)0x87; + + /** The triplet contains a GID reference to a begin medium map structured field. */ + public static final byte TYPE_BEGIN_MEDIUM_MAP_REF = (byte)0x8D; + + /** + * The triplet contains a GID reference to a coded font, which identifies a specific + * code page and a specific font character set. + */ + public static final byte TYPE_CODED_FONT_NAME_REF = (byte)0x8E; + + /** The triplet contains a GID reference to a begin document index structured field. */ + public static final byte TYPE_BEGIN_DOCUMENT_INDEX_REF = (byte)0x98; + + /** The triplet contains a GID reference to a begin overlay structured field. */ + public static final byte TYPE_BEGIN_OVERLAY_REF = (byte)0xB0; + + /** The triplet contains a GID reference to a resource used by a data object. */ + public static final byte TYPE_DATA_OBJECT_INTERNAL_RESOURCE_REF = (byte)0xBE; + + /** The triplet contains a GID reference to an index element structured field. */ + public static final byte TYPE_INDEX_ELEMENT_GID = (byte)0xCA; + + /** + * The triplet contains a reference to other object data which may or may + * not be defined by an IBM presentation architecture. + */ + public static final byte TYPE_OTHER_OBJECT_DATA_REF = (byte)0xCE; + + /** + * The triplet contains a reference to a resource used by a data object. + * The GID may be a filename or any other identifier associated with the + * resource and is used to located the resource object in the resource hierarchy. + * The data object that uses the resource may or may not be defined by an + * IBM presentation architecture. + */ + public static final byte TYPE_DATA_OBJECT_EXTERNAL_RESOURCE_REF = (byte)0xDE; + + + // GID Format + + /** The GID is a character encoded name. */ + public static final byte FORMAT_CHARSTR = (byte)0x00; + + /** the GID is a ASN.1 object identifier (OID). */ + public static final byte FORMAT_OID = (byte)0x10; + + /** the GID is a uniform resource locator (URL). */ + public static final byte FORMAT_URL = (byte)0x20; + + /** the fully qualified name type */ + private final byte type; + + /** the fully qualified name format */ + private final byte format; + + /** the actual fully qualified name */ + private final String fqName; + + /** + * Main constructor + * + * @param type the fully qualified name type + * @param format the fully qualified name format + * @param fqName the fully qualified name + */ + public FullyQualifiedNameTriplet(byte type, byte format, String fqName) { + super(FULLY_QUALIFIED_NAME); + this.type = type; + this.format = format; + this.fqName = fqName; + } + + /** + * Returns the actual fully qualified name + * + * @return the actual fully qualified name + */ + public String getFullyQualifiedName() { + return fqName; + } + + /** {@inheritDoc} */ + public String toString() { + return this.fqName; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 4 + fqName.length(); + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + data[2] = type; + data[3] = format; + + // FQName + byte[] fqNameBytes; + String encoding = AFPConstants.EBCIDIC_ENCODING; + if (format == FORMAT_URL) { + encoding = AFPConstants.US_ASCII_ENCODING; + } + try { + fqNameBytes = fqName.getBytes(encoding); + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException( + encoding + " encoding failed"); + } + System.arraycopy(fqNameBytes, 0, data, 4, fqNameBytes.length); + + os.write(data); + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/modca/triplets/MappingOptionTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/MappingOptionTriplet.java new file mode 100644 index 000000000..0d20d0227 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/MappingOptionTriplet.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.modca.triplets; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Specifies the mapping of data object presentation space to object area + */ +public class MappingOptionTriplet extends AbstractTriplet { + /** + * the data object is placed in the upper left corner, all data must be presented + * within the object area extents + */ + public static final byte POSITION = 0x00; + + /** + * the data object is placed in the upper left corner, all data that falls within + * the object area extents will be presented but data that falls outside will not be presented + */ + public static final byte POSITION_AND_TRIM = 0x10; + + /** + * the data object is centred and symmetrically scaled up or down + * while preserving aspect ratio + */ + public static final byte SCALE_TO_FIT = 0x20; + + /** + * the data object is centred, all data that falls within the object area extents + * will be presented but data that falls outside will not be presented + */ + public static final byte CENTER_AND_TRIM = 0x30; + +// public static final byte MIGRATION_MAPPING_1 = 0x41; +// public static final byte MIGRATION_MAPPING_2 = 0x42; +// public static final byte MIGRATION_MAPPING_3 = 0x50; + + /** the data object is centred, aspect ratio is not always preserved */ + public static final byte SCALE_TO_FILL = 0x60; + + /** used to map ip3i print data objects */ + public static final byte UP3I_PRINT_DATA = 0x70; + + private final byte mapValue; + + /** + * Main constructor + * + * @param mapValue the mapping option to use + */ + public MappingOptionTriplet(byte mapValue) { + super(AbstractTriplet.MAPPING_OPTION); + this.mapValue = mapValue; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 3; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + data[2] = mapValue; + + os.write(data); + } +} diff --git a/src/java/org/apache/fop/afp/modca/triplets/MeasurementUnitsTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/MeasurementUnitsTriplet.java new file mode 100644 index 000000000..68d3fc40c --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/MeasurementUnitsTriplet.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.modca.triplets; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * The Measurement Units triplet is used to specify the units of measure + * for a presentation space + */ +public class MeasurementUnitsTriplet extends AbstractTriplet { + + private static final byte TEN_INCHES = 0x00; + private static final byte TEN_CM = 0x01; + private final int xRes; + private final int yRes; + + /** + * Main constructor + * + * @param xRes units per base on the x-axis + * @param yRes units per base on the y-axis + */ + public MeasurementUnitsTriplet(int xRes, int yRes) { + super(MEASUREMENT_UNITS); + this.xRes = xRes; + this.yRes = yRes; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 8; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + + data[2] = TEN_INCHES; // XoaBase + data[3] = TEN_INCHES; // YoaBase + + byte[] xUnits = BinaryUtils.convert(xRes * 10, 2); + data[4] = xUnits[0]; // XoaUnits (x units per unit base) + data[5] = xUnits[1]; + + byte[] yUnits = BinaryUtils.convert(yRes * 10, 2); + data[6] = yUnits[0]; // YoaUnits (y units per unit base) + data[7] = yUnits[1]; + + os.write(data); + } +} diff --git a/src/java/org/apache/fop/afp/modca/triplets/ObjectAreaSizeTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/ObjectAreaSizeTriplet.java new file mode 100644 index 000000000..3d408639e --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/ObjectAreaSizeTriplet.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.modca.triplets; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * The Object Area Size triplet is used to specify the extent of an object area + * in the X and Y directions + */ +public class ObjectAreaSizeTriplet extends AbstractTriplet { + + private final int x; + private final int y; + private final byte type; + + /** + * Main constructor + * + * @param x the object area extent for the X axis + * @param y the object area extent for the Y axis + * @param type the object area size type + */ + public ObjectAreaSizeTriplet(int x, int y, byte type) { + super(AbstractTriplet.OBJECT_AREA_SIZE); + this.x = x; + this.y = y; + this.type = type; + } + + /** + * Main constructor + * + * @param x the object area extent for the X axis + * @param y the object area extent for the Y axis + */ + public ObjectAreaSizeTriplet(int x, int y) { + this(x, y, (byte)0x02); + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 9; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + + data[2] = type; // SizeType + + byte[] xOASize = BinaryUtils.convert(x, 3); + data[3] = xOASize[0]; // XoaSize - Object area extent for X axis + data[4] = xOASize[1]; + data[5] = xOASize[2]; + + byte[] yOASize = BinaryUtils.convert(y, 3); + data[6] = yOASize[0]; // YoaSize - Object area extent for Y axis + data[7] = yOASize[1]; + data[8] = yOASize[2]; + + os.write(data); + } +} diff --git a/src/java/org/apache/fop/afp/modca/triplets/ObjectByteExtentTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/ObjectByteExtentTriplet.java new file mode 100644 index 000000000..3aaa6969a --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/ObjectByteExtentTriplet.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.afp.modca.triplets; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; + +/** + * The Object Byte Extent triplet is used to specify the number of bytes contained in an object + */ +public class ObjectByteExtentTriplet extends AbstractTriplet { + + private final int byteExt; + + /** + * Main constructor + * + * @param byteExt the number of bytes contained in the object + */ + public ObjectByteExtentTriplet(int byteExt) { + super(OBJECT_BYTE_EXTENT); + this.byteExt = byteExt; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 6; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + byte[] extData = BinaryUtils.convert(byteExt, 4); + System.arraycopy(extData, 0, data, 2, extData.length); + os.write(data); + } +} diff --git a/src/java/org/apache/fop/afp/modca/triplets/ObjectClassificationTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/ObjectClassificationTriplet.java new file mode 100644 index 000000000..9c2ab7bc4 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/ObjectClassificationTriplet.java @@ -0,0 +1,214 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: $ */ + +package org.apache.fop.afp.modca.triplets; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.AFPConstants; +import org.apache.fop.afp.modca.Registry.ObjectType; +import org.apache.fop.afp.util.StringUtils; + +/** + * The Object Classification is used to classify and identify object data. + * The object data may or may not be defined by an IBM presentation architecture + */ +public class ObjectClassificationTriplet extends AbstractTriplet { + + /** + * The scope of this object is the including page or overlay + */ + public static final byte CLASS_TIME_INVARIANT_PAGINATED_PRESENTATION_OBJECT = 0x01; + + /** + * The scope of this object is not defined + */ + public static final byte CLASS_TIME_VARIANT_PRESENTATION_OBJECT = 0x10; + + /** + * This is not a presentation object, the scope of this object is not defined + */ + public static final byte CLASS_EXECUTABLE_PROGRAM = 0x20; + + /** + * Setup information file, document level. This is not a presentation object, + */ + public static final byte CLASS_SETUP_FILE = 0x30; + + /** + * This is a resource used by a presentation object that may itself be a resource. + * The scope of the resource is the object that uses the resource. + */ + public static final byte CLASS_SECONDARY_RESOURCE = 0x40; + + /** + * Data object font. This is a non-FOCA font resource used to present + * text in a data object. The scope of the resource is the object that + * uses the resource. + */ + public static final byte CLASS_DATA_OBJECT_FONT = 0x41; + + /** the object class */ + private final byte objectClass; + + /** the object type */ + private final ObjectType objectType; + + /** whether the container has an object environment group */ + private final boolean containerHasOEG; + + /** whether the data resides within the container */ + private final boolean dataInContainer; + + /** whether the data resides within the object container data */ + private final boolean dataInOCD; + + /** the object level (version) */ + private final String objectLevel; + + /** the company/organization name */ + private final String companyName; + + + /** + * Main constructor + * + * @param objectClass the object class type + * @param objectType the object type registry entry + * @param dataInContainer whether the data resides in the container + * @param containerHasOEG whether the container has an object environment group + * @param dataInOCD whether the data resides in a object container data structured field + */ + public ObjectClassificationTriplet(byte objectClass, ObjectType objectType, + boolean dataInContainer, boolean containerHasOEG, boolean dataInOCD) { + // no object level or company name specified + this(objectClass, objectType, dataInContainer, containerHasOEG, dataInOCD, null, null); + } + + /** + * Fully parameterized constructor + * + * @param objectClass the object class type + * @param objectType the object type registry entry + * @param dataInContainer whether the data resides in the container + * @param containerHasOEG whether the container has an object environment group + * @param dataInOCD whether the data resides in a object container data structured field + * @param objLev the release level or version number of the object type + * @param compName the name of the company or organization that owns the object definition + */ + public ObjectClassificationTriplet(byte objectClass, ObjectType objectType, + boolean dataInContainer, boolean containerHasOEG, boolean dataInOCD, + String objLev, String compName) { + super(OBJECT_CLASSIFICATION); + + this.objectClass = objectClass; + if (objectType == null) { + throw new IllegalArgumentException("MO:DCA Registry object type is null"); + } + this.objectType = objectType; + this.dataInContainer = dataInContainer; + this.containerHasOEG = containerHasOEG; + this.dataInOCD = dataInOCD; + this.objectLevel = objLev; + this.companyName = compName; + } + + /** + * Returns the structured field flags + * + * @param dataInContainer true if the object data in carried in the object container + * @param containerHasOEG true if the object container has an object environment group + * @param dataInOCD true if the object container data carries the object data + * + * @return the byte value of this structure + */ + public byte[] getStructureFlagsAsBytes(boolean dataInContainer, boolean containerHasOEG, + boolean dataInOCD) { + byte[] strucFlgs = new byte[2]; + // Object Container (BOC/EOC) + if (dataInContainer) { + strucFlgs[0] |= 3 << 6; + } else { + strucFlgs[0] |= 1 << 6; + } + // Object Environment Group (OEG) + if (containerHasOEG) { + strucFlgs[0] |= 3 << 4; + } else { + strucFlgs[0] |= 1 << 4; + } + // Object Container Data (OCD) structured fields + if (dataInOCD) { + strucFlgs[0] |= 3 << 2; + } else { + strucFlgs[0] |= 1 << 2; + } + strucFlgs[1] = 0x00; + return strucFlgs; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 96; + } + + private static final int OBJECT_LEVEL_LEN = 8; + private static final int OBJECT_TYPE_NAME_LEN = 32; + private static final int COMPANY_NAME_LEN = 32; + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + data[2] = 0x00; // reserved (must be zero) + data[3] = objectClass; // ObjClass + data[4] = 0x00; // reserved (must be zero) + data[5] = 0x00; // reserved (must be zero) + + // StrucFlgs - Information on the structure of the object container + byte[] structureFlagsBytes = getStructureFlagsAsBytes(dataInContainer, containerHasOEG, dataInOCD); + data[6] = structureFlagsBytes[0]; + data[7] = structureFlagsBytes[1]; + + byte[] objectIdBytes = objectType.getOID(); + // RegObjId - MOD:CA-registered ASN.1 OID for object type (8-23) + System.arraycopy(objectIdBytes, 0, data, 8, objectIdBytes.length); + + // ObjTpName - name of object type (24-55) + byte[] objectTypeNameBytes; + objectTypeNameBytes + = StringUtils.rpad(objectType.getName(), ' ', OBJECT_TYPE_NAME_LEN).getBytes( + AFPConstants.EBCIDIC_ENCODING); + System.arraycopy(objectTypeNameBytes, 0, data, 24, objectTypeNameBytes.length); + + // ObjLev - release level or version number of object type (56-63) + byte[] objectLevelBytes; + objectLevelBytes = StringUtils.rpad(objectLevel, ' ', OBJECT_LEVEL_LEN).getBytes( + AFPConstants.EBCIDIC_ENCODING); + System.arraycopy(objectLevelBytes, 0, data, 56, objectLevelBytes.length); + + // CompName - name of company or organization that owns object definition (64-95) + byte[] companyNameBytes; + companyNameBytes = StringUtils.rpad(companyName, ' ', COMPANY_NAME_LEN).getBytes( + AFPConstants.EBCIDIC_ENCODING); + System.arraycopy(companyNameBytes, 0, data, 64, companyNameBytes.length); + + os.write(data); + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/modca/triplets/PresentationSpaceMixingRulesTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/PresentationSpaceMixingRulesTriplet.java new file mode 100644 index 000000000..b93ec5477 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/PresentationSpaceMixingRulesTriplet.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.afp.modca.triplets; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * This triplet is used to specify the resulting appearance when data in a new + * presentation space is merged with data in an existing presentation space. + */ +public class PresentationSpaceMixingRulesTriplet extends AbstractTriplet { + + /** background on background mixing rule */ + public static final byte RULE_BACK_ON_BACK = 0x70; + + /** background on foreground mixing rule */ + public static final byte RULE_BACK_ON_FORE = 0x71; + + /** foreground on background mixing rule */ + public static final byte RULE_FORE_ON_BACK = 0x72; + + /** foreground on foreground mixing rule */ + public static final byte RULE_FORE_ON_FORE = 0x73; + + + /** overpaint */ + public static final byte OVERPAINT = (byte)0x01; + + /** underpaint */ + public static final byte UNDERPAINT = (byte)0x02; + + /** blend */ + public static final byte BLEND = (byte)0x03; + + /** MO:DCA default mixing */ + public static final byte DEFAULT = (byte)0xFF; + + /** the mixing rules */ + private final byte[] rules; + + /** + * Main constructor + * + * @param rules the mixing rules + */ + public PresentationSpaceMixingRulesTriplet(byte[] rules) { + super(PRESENTATION_SPACE_MIXING_RULE); + this.rules = rules; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 2 + rules.length; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + System.arraycopy(rules, 0, data, 2, rules.length); + os.write(data); + } +} diff --git a/src/java/org/apache/fop/afp/modca/triplets/PresentationSpaceResetMixingTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/PresentationSpaceResetMixingTriplet.java new file mode 100644 index 000000000..cecd40910 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/PresentationSpaceResetMixingTriplet.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.afp.modca.triplets; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * This triplet is used to specify the resulting appearance when data in a new + * presentation space is merged with data in an existing presentation space. + */ +public class PresentationSpaceResetMixingTriplet extends AbstractTriplet { + + /** + * Do not reset to the color of the medium prior to + * placing data into this MO:DCA presentation space. + */ + public static final byte NOT_RESET = 0x00; + + /** + * Reset to the color of the medium prior to placing + * data into this MO:DCA presentation space. + */ + public static final byte RESET = 0x01; + + private final byte backgroundMixFlag; + + /** + * Main constructor + * + * @param backgroundMixFlag the background mixing flag + */ + public PresentationSpaceResetMixingTriplet(byte backgroundMixFlag) { + super(PRESENTATION_SPACE_RESET_MIXING); + this.backgroundMixFlag = backgroundMixFlag; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 3; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + data[2] = backgroundMixFlag; + os.write(data); + } +} diff --git a/src/java/org/apache/fop/afp/modca/triplets/ResourceObjectTypeTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/ResourceObjectTypeTriplet.java new file mode 100644 index 000000000..e4b13177d --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/ResourceObjectTypeTriplet.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.afp.modca.triplets; + +import java.io.IOException; +import java.io.OutputStream; + +/** A Resource Object Type Triplet */ +public class ResourceObjectTypeTriplet extends AbstractTriplet { + + private static final byte RESOURCE_OBJECT = 0x21; + + /** the resource object type */ + private final byte objectType; + + /** + * Main constructor + * + * @param objectType the resource object type + */ + public ResourceObjectTypeTriplet(byte objectType) { + super(RESOURCE_OBJECT); + this.objectType = objectType; + } + + /** {@inheritDoc} */ + public int getDataLength() { + return 10; + } + + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + byte[] data = getData(); + data[2] = objectType; + os.write(data); + } +} diff --git a/src/java/org/apache/fop/afp/modca/triplets/package.html b/src/java/org/apache/fop/afp/modca/triplets/package.html new file mode 100644 index 000000000..99ae55a45 --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/package.html @@ -0,0 +1,23 @@ +<!-- + 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.html 643433 2008-04-01 15:08:24Z acumiskey $ --> +<HTML> +<TITLE>org.apache.fop.afp.modca.triplets Package</TITLE> +<BODY> +<P>Contains a collection of AFP Mixed Object Document Content Architecture (MO:DCA) triplet classes.</P> +</BODY> +</HTML>
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/package.html b/src/java/org/apache/fop/afp/package.html new file mode 100644 index 000000000..d67498159 --- /dev/null +++ b/src/java/org/apache/fop/afp/package.html @@ -0,0 +1,23 @@ +<!-- + 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.html 643433 2008-04-01 15:08:24Z acumiskey $ --> +<HTML> +<TITLE>org.apache.fop.afp Package</TITLE> +<BODY> +<P>Contains an AFP library.</P> +</BODY> +</HTML>
\ No newline at end of file diff --git a/src/java/org/apache/fop/afp/svg/AFPBridgeContext.java b/src/java/org/apache/fop/afp/svg/AFPBridgeContext.java new file mode 100644 index 000000000..48c1001ef --- /dev/null +++ b/src/java/org/apache/fop/afp/svg/AFPBridgeContext.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.svg; + +import java.awt.geom.AffineTransform; + +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.bridge.DocumentLoader; +import org.apache.batik.bridge.UserAgent; +import org.apache.batik.gvt.TextPainter; +import org.apache.fop.afp.AFPGraphics2D; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.svg.AbstractFOPBridgeContext; +import org.apache.xmlgraphics.image.loader.ImageManager; +import org.apache.xmlgraphics.image.loader.ImageSessionContext; + +/** + * An AFP specific implementation of a Batik BridgeContext + */ +public class AFPBridgeContext extends AbstractFOPBridgeContext { + + private final AFPGraphics2D g2d; + + /** + * Constructs a new bridge context. + * + * @param userAgent the user agent + * @param fontInfo the font list for the text painter, may be null + * in which case text is painted as shapes + * @param imageManager an image manager + * @param imageSessionContext an image session context + * @param linkTransform AffineTransform to properly place links, + * may be null + * @param g2d an AFPGraphics 2D implementation + */ + public AFPBridgeContext(UserAgent userAgent, FontInfo fontInfo, + ImageManager imageManager, ImageSessionContext imageSessionContext, + AffineTransform linkTransform, AFPGraphics2D g2d) { + super(userAgent, fontInfo, imageManager, imageSessionContext, linkTransform); + this.g2d = g2d; + } + + /** + * Constructs a new bridge context. + * @param userAgent the user agent + * @param loader the Document Loader to use for referenced documents. + * @param fontInfo the font list for the text painter, may be null + * in which case text is painted as shapes + * @param linkTransform AffineTransform to properly place links, + * may be null + * @param imageManager an image manager + * @param imageSessionContext an image session context + * @param linkTransform AffineTransform to properly place links, + * may be null + * @param an AFPGraphics 2D implementation + */ + public AFPBridgeContext(UserAgent userAgent, DocumentLoader documentLoader, + FontInfo fontInfo, ImageManager imageManager, + ImageSessionContext imageSessionContext, + AffineTransform linkTransform, AFPGraphics2D g2d) { + super(userAgent, documentLoader, fontInfo, imageManager, imageSessionContext, linkTransform); + this.g2d = g2d; + } + + /** {@inheritDoc} */ + public void registerSVGBridges() { + super.registerSVGBridges(); + + if (fontInfo != null) { + AFPTextHandler textHandler = new AFPTextHandler(fontInfo); + g2d.setCustomTextHandler(textHandler); + + TextPainter textPainter = new AFPTextPainter(textHandler); + setTextPainter(textPainter); + + putBridge(new AFPTextElementBridge(textPainter)); + } + + putBridge(new AFPImageElementBridge()); + } + + /** {@inheritDoc} */ + public BridgeContext createBridgeContext() { + return new AFPBridgeContext(getUserAgent(), getDocumentLoader(), + fontInfo, + getImageManager(), + getImageSessionContext(), + linkTransform, g2d); + } + +} diff --git a/src/java/org/apache/fop/afp/svg/AFPGraphicsConfiguration.java b/src/java/org/apache/fop/afp/svg/AFPGraphicsConfiguration.java new file mode 100644 index 000000000..76d6396e3 --- /dev/null +++ b/src/java/org/apache/fop/afp/svg/AFPGraphicsConfiguration.java @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.svg; + +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 (this still works for now, + * but it should be fixed...). + * + * @return the bounds of the 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 final GraphicsDevice graphicsDevice = new AFPGraphicsDevice(this);; + + /** + * 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()"); + return graphicsDevice; + } +} diff --git a/src/java/org/apache/fop/afp/svg/AFPGraphicsDevice.java b/src/java/org/apache/fop/afp/svg/AFPGraphicsDevice.java new file mode 100644 index 000000000..daa25aaa0 --- /dev/null +++ b/src/java/org/apache/fop/afp/svg/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.afp.svg; + +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/afp/svg/AFPImageElementBridge.java b/src/java/org/apache/fop/afp/svg/AFPImageElementBridge.java new file mode 100644 index 000000000..63661940d --- /dev/null +++ b/src/java/org/apache/fop/afp/svg/AFPImageElementBridge.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.svg; + +import org.apache.fop.svg.AbstractFOPImageElementBridge; +import org.apache.xmlgraphics.image.loader.ImageFlavor; + +/** + * An AFP specific implementation of a Batik SVGImageElementBridge + */ +public class AFPImageElementBridge extends AbstractFOPImageElementBridge { + + private final ImageFlavor[] supportedFlavors = new ImageFlavor[] + {ImageFlavor.RAW_JPEG, + ImageFlavor.RAW_CCITTFAX, + ImageFlavor.GRAPHICS2D, + ImageFlavor.XML_DOM}; + + /** {@inheritDoc} */ + protected ImageFlavor[] getSupportedFlavours() { + return supportedFlavors; + } +} diff --git a/src/java/org/apache/fop/afp/svg/AFPTextElementBridge.java b/src/java/org/apache/fop/afp/svg/AFPTextElementBridge.java new file mode 100644 index 000000000..31aa3fe60 --- /dev/null +++ b/src/java/org/apache/fop/afp/svg/AFPTextElementBridge.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.afp.svg; + +import org.apache.batik.gvt.TextPainter; +import org.apache.fop.svg.AbstractFOPTextElementBridge; + +/** + * 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 AbstractFOPTextElementBridge { + + /** + * Constructs a new bridge for the <text> element. + * + * @param textPainter the text painter to use + */ + public AFPTextElementBridge(TextPainter textPainter) { + super(textPainter); + } + +} + diff --git a/src/java/org/apache/fop/afp/svg/AFPTextHandler.java b/src/java/org/apache/fop/afp/svg/AFPTextHandler.java new file mode 100644 index 000000000..f44fde269 --- /dev/null +++ b/src/java/org/apache/fop/afp/svg/AFPTextHandler.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.svg; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.afp.AFPGraphics2D; +import org.apache.fop.afp.AFPPaintingState; +import org.apache.fop.afp.fonts.AFPFont; +import org.apache.fop.afp.fonts.AFPFontAttributes; +import org.apache.fop.afp.fonts.AFPPageFonts; +import org.apache.fop.afp.modca.GraphicsObject; +import org.apache.fop.fonts.Font; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.svg.FOPTextHandler; + +/** + * Specialized TextHandler implementation that the AFPGraphics2D class delegates to to paint text + * using AFP GOCA text operations. + */ +public class AFPTextHandler implements FOPTextHandler { + + /** logging instance */ + private static Log log = LogFactory.getLog(AFPTextHandler.class); + + /** Overriding FontState */ + protected Font overrideFont = null; + + /** Font information */ + private final FontInfo fontInfo; + + /** + * Main constructor. + * + * @param fontInfo the AFPGraphics2D instance + */ + public AFPTextHandler(FontInfo fontInfo) { + this.fontInfo = fontInfo; + } + + /** + * Return the font information associated with this object + * + * @return the FontInfo object + */ + public FontInfo getFontInfo() { + return fontInfo; + } + + /** + * Registers a page font + * + * @param internalFontName the internal font name + * @param internalFontName the internal font name + * @param fontSize the font size + * @return a font reference + */ + private int registerPageFont(AFPPageFonts pageFonts, String internalFontName, int fontSize) { + FontInfo fontInfo = getFontInfo(); + AFPFont afpFont = (AFPFont)fontInfo.getFonts().get(internalFontName); + // register if necessary + AFPFontAttributes afpFontAttributes = pageFonts.registerFont( + internalFontName, + afpFont, + fontSize + ); + return afpFontAttributes.getFontReference(); + } + + /** {@inheritDoc} */ + public void drawString(String text, float x, float y) throws IOException { + // TODO Remove me after removing the deprecated method in TextHandler. + throw new UnsupportedOperationException("Deprecated method!"); + } + + /** + * Add a text string to the current data object of the AFP datastream. + * The text is painted using text operations. + * + * {@inheritDoc} + */ + public void drawString(Graphics2D g, String str, float x, float y) throws IOException { + log.debug("drawString() str=" + str + ", x=" + x + ", y=" + y); + AFPGraphics2D g2d = (AFPGraphics2D)g; + GraphicsObject graphicsObj = g2d.getGraphicsObject(); + Color color = g2d.getColor(); + + // set the color + AFPPaintingState paintingState = g2d.getPaintingState(); + if (paintingState.setColor(color)) { + graphicsObj.setColor(color); + } + + // set the character set + int fontReference = 0; + AFPPageFonts pageFonts = paintingState.getPageFonts(); + if (overrideFont != null) { + String internalFontName = overrideFont.getFontName(); + int fontSize = overrideFont.getFontSize(); + fontReference = registerPageFont(pageFonts, internalFontName, fontSize); + } else { + java.awt.Font awtFont = g2d.getFont(); +// AffineTransform fontTransform = awtFont.getTransform(); + FontInfo fontInfo = getFontInfo(); + Font fopFont = fontInfo.getFontInstanceForAWTFont(awtFont); + String internalFontName = fopFont.getFontName(); + int fontSize = fopFont.getFontSize(); + fontReference = registerPageFont(pageFonts, internalFontName, fontSize); + } + graphicsObj.setCharacterSet(fontReference); + + // add the character string + graphicsObj.addString(str, Math.round(x), 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/afp/svg/AFPTextPainter.java b/src/java/org/apache/fop/afp/svg/AFPTextPainter.java new file mode 100644 index 000000000..c6a38b1b5 --- /dev/null +++ b/src/java/org/apache/fop/afp/svg/AFPTextPainter.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.afp.svg; + +import org.apache.fop.svg.AbstractFOPTextPainter; +import org.apache.fop.svg.FOPTextHandler; + + +/** + * 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 extends AbstractFOPTextPainter { + + /** + * Create a new text painter with the given font information. + * @param nativeTextHandler the NativeTextHandler instance used for text painting + */ + public AFPTextPainter(FOPTextHandler nativeTextHandler) { + super(nativeTextHandler); + } + +} diff --git a/src/java/org/apache/fop/afp/svg/package.html b/src/java/org/apache/fop/afp/svg/package.html new file mode 100644 index 000000000..bd24b246f --- /dev/null +++ b/src/java/org/apache/fop/afp/svg/package.html @@ -0,0 +1,23 @@ +<!-- + 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.html 643433 2008-04-01 15:08:24Z acumiskey $ --> +<HTML> +<TITLE>org.apache.fop.afp.modca.svg Package</TITLE> +<BODY> +<P>Contains a collection of AFP specific Batik bridges.</P> +</BODY> +</HTML>
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/tools/BinaryUtils.java b/src/java/org/apache/fop/afp/util/BinaryUtils.java index 31ba45bcf..2b2649415 100644 --- a/src/java/org/apache/fop/render/afp/tools/BinaryUtils.java +++ b/src/java/org/apache/fop/afp/util/BinaryUtils.java @@ -17,7 +17,7 @@ /* $Id$ */ -package org.apache.fop.render.afp.tools; +package org.apache.fop.afp.util; import java.io.ByteArrayOutputStream; diff --git a/src/java/org/apache/fop/render/afp/tools/DTDEntityResolver.java b/src/java/org/apache/fop/afp/util/DTDEntityResolver.java index e9554ecea..dcf5ad7d9 100644 --- a/src/java/org/apache/fop/render/afp/tools/DTDEntityResolver.java +++ b/src/java/org/apache/fop/afp/util/DTDEntityResolver.java @@ -17,12 +17,12 @@ /* $Id$ */ -package org.apache.fop.render.afp.tools; +package org.apache.fop.afp.util; import java.io.IOException; import java.net.URL; -import org.apache.fop.render.afp.exceptions.FontRuntimeException; +import org.apache.fop.afp.fonts.FontRuntimeException; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; diff --git a/src/java/org/apache/fop/render/afp/tools/StringUtils.java b/src/java/org/apache/fop/afp/util/StringUtils.java index c49509aa0..ce68d27be 100644 --- a/src/java/org/apache/fop/render/afp/tools/StringUtils.java +++ b/src/java/org/apache/fop/afp/util/StringUtils.java @@ -17,7 +17,7 @@ /* $Id$ */ -package org.apache.fop.render.afp.tools; +package org.apache.fop.afp.util; /** * Library of utility methods useful in dealing with strings. diff --git a/src/java/org/apache/fop/render/afp/tools/StructuredFieldReader.java b/src/java/org/apache/fop/afp/util/StructuredFieldReader.java index 48beff023..34add3bbe 100644 --- a/src/java/org/apache/fop/render/afp/tools/StructuredFieldReader.java +++ b/src/java/org/apache/fop/afp/util/StructuredFieldReader.java @@ -17,7 +17,7 @@ /* $Id$ */ -package org.apache.fop.render.afp.tools; +package org.apache.fop.afp.util; import java.io.IOException; import java.io.InputStream; diff --git a/src/java/org/apache/fop/afp/util/package.html b/src/java/org/apache/fop/afp/util/package.html new file mode 100644 index 000000000..525bdbe2a --- /dev/null +++ b/src/java/org/apache/fop/afp/util/package.html @@ -0,0 +1,23 @@ +<!-- + 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.html 643433 2008-04-01 15:08:24Z acumiskey $ --> +<HTML> +<TITLE>org.apache.fop.afp.modca.triplets Package</TITLE> +<BODY> +<P>Contains a collection of useful AFP utility classes.</P> +</BODY> +</HTML>
\ No newline at end of file diff --git a/src/java/org/apache/fop/apps/MimeConstants.java b/src/java/org/apache/fop/apps/MimeConstants.java index b8a9637a8..851690db1 100644 --- a/src/java/org/apache/fop/apps/MimeConstants.java +++ b/src/java/org/apache/fop/apps/MimeConstants.java @@ -22,50 +22,7 @@ package org.apache.fop.apps; /** * Frequently used MIME types for various file formats used when working with Apache FOP. */ -public interface MimeConstants { - - /** Portable Document Format */ - String MIME_PDF = "application/pdf"; - - /** PostScript */ - String MIME_POSTSCRIPT = "application/postscript"; - /** Encapsulated PostScript (same MIME type as PostScript) */ - String MIME_EPS = MIME_POSTSCRIPT; - - /** HP's PCL */ - String MIME_PCL = "application/x-pcl"; - /** HP's PCL (alternative MIME type) */ - String MIME_PCL_ALT = "application/vnd.hp-PCL"; - - /** IBM's AFP */ - String MIME_AFP = "application/x-afp"; - /** IBM's AFP (alternative MIME type) */ - String MIME_AFP_ALT = "application/vnd.ibm.modcap"; - - /** Plain text */ - String MIME_PLAIN_TEXT = "text/plain"; - - /** Rich text format */ - String MIME_RTF = "application/rtf"; - /** Rich text format (alternative 1) */ - String MIME_RTF_ALT1 = "text/richtext"; - /** Rich text format (alternative 2) */ - String MIME_RTF_ALT2 = "text/rtf"; - - /** FrameMaker's MIF */ - String MIME_MIF = "application/mif"; - - /** Scalable Vector Graphics */ - String MIME_SVG = "image/svg+xml"; - - /** GIF images */ - String MIME_GIF = "image/gif"; - /** PNG images */ - String MIME_PNG = "image/png"; - /** JPEG images */ - String MIME_JPEG = "image/jpeg"; - /** TIFF images */ - String MIME_TIFF = "image/tiff"; +public interface MimeConstants extends org.apache.xmlgraphics.util.MimeConstants { /** Apache FOP's AWT preview (non-standard MIME type) */ String MIME_FOP_AWT_PREVIEW = "application/X-fop-awt-preview"; @@ -75,7 +32,4 @@ public interface MimeConstants { String MIME_FOP_AREA_TREE = "application/X-fop-areatree"; /** Apache FOP's intermediate format XML */ String MIME_FOP_IF = "application/X-fop-intermediate-format"; - /** Proposed but non-registered MIME type for XSL-FO */ - String MIME_XSL_FO = "text/xsl"; - } diff --git a/src/java/org/apache/fop/area/Area.java b/src/java/org/apache/fop/area/Area.java index 1379e566d..87ba2146a 100644 --- a/src/java/org/apache/fop/area/Area.java +++ b/src/java/org/apache/fop/area/Area.java @@ -119,8 +119,10 @@ public class Area extends AreaTreeObject implements Serializable { public static final int CLASS_MAX = CLASS_SIDE_FLOAT + 1; private int areaClass = CLASS_NORMAL; + /** the area's inline-progression-dimension */ protected int ipd; + /** the area's block-progression-dimension */ protected int bpd; @@ -141,7 +143,7 @@ public class Area extends AreaTreeObject implements Serializable { * @return the area class */ public int getAreaClass() { - return areaClass; + return this.areaClass; } /** @@ -157,11 +159,11 @@ public class Area extends AreaTreeObject implements Serializable { * Set the inline progression dimension of content rectangle * for this area. * - * @param i the new inline progression dimension - * @see <a href="http://www.w3.org/TR/xsl/slice4.html#area-common">ipd</a> + * @param ipd the new inline progression dimension + * @see <a href="http://www.w3.org/TR/xsl/#inline-progression-dimension">ipd</a> */ - public void setIPD(int i) { - ipd = i; + public void setIPD(int ipd) { + this.ipd = ipd; } /** @@ -169,10 +171,10 @@ public class Area extends AreaTreeObject implements Serializable { * for this area. * * @return the inline progression dimension - * @see <a href="http://www.w3.org/TR/xsl/slice4.html#area-common">ipd</a> + * @see <a href="http://www.w3.org/TR/xsl/#inline-progression-dimension">ipd</a> */ public int getIPD() { - return ipd; + return this.ipd; } /** @@ -180,7 +182,7 @@ public class Area extends AreaTreeObject implements Serializable { * for this area. * * @param b the new block progression dimension - * @see <a href="http://www.w3.org/TR/xsl/slice4.html#area-common">bpd</a> + * @see <a href="http://www.w3.org/TR/xsl/#block-progression-dimension">bpd</a> */ public void setBPD(int b) { bpd = b; @@ -191,7 +193,7 @@ public class Area extends AreaTreeObject implements Serializable { * for this area. * * @return the block progression dimension - * @see <a href="http://www.w3.org/TR/xsl/slice4.html#area-common">bpd</a> + * @see <a href="http://www.w3.org/TR/xsl/#block-progression-dimension">bpd</a> */ public int getBPD() { return bpd; diff --git a/src/java/org/apache/fop/area/AreaTreeHandler.java b/src/java/org/apache/fop/area/AreaTreeHandler.java index 59995741b..128fc8ce9 100644 --- a/src/java/org/apache/fop/area/AreaTreeHandler.java +++ b/src/java/org/apache/fop/area/AreaTreeHandler.java @@ -101,12 +101,12 @@ public class AreaTreeHandler extends FOEventHandler { setupModel(userAgent, outputFormat, stream); - lmMaker = userAgent.getFactory().getLayoutManagerMakerOverride(); + this.lmMaker = userAgent.getFactory().getLayoutManagerMakerOverride(); if (lmMaker == null) { lmMaker = new LayoutManagerMapping(); } - idTracker = new IDTracker(); + this.idTracker = new IDTracker(); if (log.isDebugEnabled()) { statistics = new Statistics(); @@ -124,7 +124,7 @@ public class AreaTreeHandler extends FOEventHandler { */ protected void setupModel(FOUserAgent userAgent, String outputFormat, OutputStream stream) throws FOPException { - model = new RenderPagesModel(userAgent, outputFormat, fontInfo, stream); + this.model = new RenderPagesModel(userAgent, outputFormat, fontInfo, stream); } /** @@ -133,7 +133,7 @@ public class AreaTreeHandler extends FOEventHandler { * @return AreaTreeModel the model being used for this area tree */ public AreaTreeModel getAreaTreeModel() { - return model; + return this.model; } /** @@ -143,7 +143,7 @@ public class AreaTreeHandler extends FOEventHandler { * area tree */ public LayoutManagerMaker getLayoutManagerMaker() { - return lmMaker; + return this.lmMaker; } /** @@ -152,7 +152,7 @@ public class AreaTreeHandler extends FOEventHandler { * @return IDTracker used to track reference ids for items in this area tree */ public IDTracker getIDTracker() { - return idTracker; + return this.idTracker; } /** @@ -207,9 +207,9 @@ public class AreaTreeHandler extends FOEventHandler { } private void wrapAndAddExtensionAttachments(List list) { - Iterator i = list.iterator(); - while (i.hasNext()) { - ExtensionAttachment attachment = (ExtensionAttachment) i.next(); + Iterator it = list.iterator(); + while (it.hasNext()) { + ExtensionAttachment attachment = (ExtensionAttachment) it.next(); addOffDocumentItem(new OffDocumentExtensionAttachment(attachment)); } } @@ -357,7 +357,7 @@ public class AreaTreeHandler extends FOEventHandler { * * @param id the property ID of the area * @param pv a page viewport that contains the area with this ID - * @deprecated use getIdTracker().associateIDWithPageViewport(id, pv) instead + * @deprecated use getIDTracker().associateIDWithPageViewport(id, pv) instead */ public void associateIDWithPageViewport(String id, PageViewport pv) { idTracker.associateIDWithPageViewport(id, pv); @@ -369,7 +369,7 @@ public class AreaTreeHandler extends FOEventHandler { * know when an id can be resolved. * * @param id the id of the object being processed - * @deprecated use getIdTracker().signalPendingID(id) instead + * @deprecated use getIDTracker().signalPendingID(id) instead */ public void signalPendingID(String id) { idTracker.signalPendingID(id); @@ -381,7 +381,7 @@ public class AreaTreeHandler extends FOEventHandler { * ref-ids can be resolved. * * @param id the id of the formatting object which was just finished - * @deprecated use getIdTracker().signalIDProcessed(id) instead + * @deprecated use getIDTracker().signalIDProcessed(id) instead */ public void signalIDProcessed(String id) { idTracker.signalIDProcessed(id); @@ -392,7 +392,7 @@ public class AreaTreeHandler extends FOEventHandler { * * @param id the id to check * @return true if the ID has been resolved - * @deprecated use getIdTracker().alreadyResolvedID(id) instead + * @deprecated use getIDTracker().alreadyResolvedID(id) instead */ public boolean alreadyResolvedID(String id) { return idTracker.alreadyResolvedID(id); @@ -402,7 +402,7 @@ public class AreaTreeHandler extends FOEventHandler { * Tries to resolve all unresolved ID references on the given page. * * @param pv page viewport whose ID refs to resolve - * @deprecated use getIdTracker().tryIDResolution(pv) instead + * @deprecated use getIDTracker().tryIDResolution(pv) instead */ public void tryIDResolution(PageViewport pv) { idTracker.tryIDResolution(pv); @@ -413,7 +413,7 @@ public class AreaTreeHandler extends FOEventHandler { * * @param id the id to lookup * @return the list of PageViewports - * @deprecated use getIdTracker().getPageViewportsContainingID(id) instead + * @deprecated use getIDTracker().getPageViewportsContainingID(id) instead */ public List getPageViewportsContainingID(String id) { return idTracker.getPageViewportsContainingID(id); @@ -424,7 +424,7 @@ public class AreaTreeHandler extends FOEventHandler { * * @param idref the idref whose target id has not yet been located * @param res the Resolvable object needing the idref to be resolved - * @deprecated use getIdTracker().addUnresolvedIDRef(idref, res) instead + * @deprecated use getIDTracker().addUnresolvedIDRef(idref, res) instead */ public void addUnresolvedIDRef(String idref, Resolvable res) { idTracker.addUnresolvedIDRef(idref, res); diff --git a/src/java/org/apache/fop/area/AreaTreeModel.java b/src/java/org/apache/fop/area/AreaTreeModel.java index acf51b913..e5f6db17b 100644 --- a/src/java/org/apache/fop/area/AreaTreeModel.java +++ b/src/java/org/apache/fop/area/AreaTreeModel.java @@ -36,11 +36,11 @@ import org.apache.commons.logging.LogFactory; * the life of the area tree model. */ public class AreaTreeModel { - private List pageSequenceList = null; + private List/*<PageSequence>*/ pageSequenceList = null; private int currentPageSequenceIndex = -1; /** the current page sequence */ protected PageSequence currentPageSequence; - private List offDocumentItems = new java.util.ArrayList(); +// private List offDocumentItems = new java.util.ArrayList(); /** logger instance */ protected static Log log = LogFactory.getLog(AreaTreeModel.class); @@ -48,7 +48,7 @@ public class AreaTreeModel { * Create a new store pages model */ public AreaTreeModel() { - pageSequenceList = new java.util.ArrayList(); + pageSequenceList = new java.util.ArrayList/*<PageSequence>*/(); } /** @@ -83,13 +83,13 @@ public class AreaTreeModel { * Handle an OffDocumentItem * @param ext the extension to handle */ - public void handleOffDocumentItem(OffDocumentItem ext) {}; + public void handleOffDocumentItem(OffDocumentItem ext) { }; /** * Signal the end of the document for any processing. * @throws SAXException if a problem was encountered. */ - public void endDocument() throws SAXException {}; + public void endDocument() throws SAXException { }; /** * Returns the currently active page-sequence. diff --git a/src/java/org/apache/fop/area/AreaTreeObject.java b/src/java/org/apache/fop/area/AreaTreeObject.java index 83e7727db..5929e7c4e 100644 --- a/src/java/org/apache/fop/area/AreaTreeObject.java +++ b/src/java/org/apache/fop/area/AreaTreeObject.java @@ -21,6 +21,7 @@ package org.apache.fop.area; import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.Map; import org.apache.xmlgraphics.util.QName; @@ -33,6 +34,9 @@ public abstract class AreaTreeObject { /** Foreign attributes */ protected Map foreignAttributes = null; + /** Extension attachments */ + protected List/*<ExtensionAttachment>*/ extensionAttachments = null; + /** * Sets a foreign attribute. * @param name the qualified name of the attribute @@ -83,6 +87,21 @@ public abstract class AreaTreeObject { return Collections.EMPTY_MAP; } } + + /** + * Set extension attachments from a List + * @param extensionAttachments a List with extension attachments + */ + public void setExtensionAttachments(List extensionAttachments) { + this.extensionAttachments = extensionAttachments; + } - + /** @return the extension attachments associated with this area */ + public List getExtensionAttachments() { + if (this.foreignAttributes != null) { + return Collections.unmodifiableList(this.extensionAttachments); + } else { + return Collections.EMPTY_LIST; + } + } } diff --git a/src/java/org/apache/fop/area/IDTracker.java b/src/java/org/apache/fop/area/IDTracker.java index 9f9023717..b55ed7983 100644 --- a/src/java/org/apache/fop/area/IDTracker.java +++ b/src/java/org/apache/fop/area/IDTracker.java @@ -20,8 +20,6 @@ package org.apache.fop.area; import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -36,20 +34,20 @@ import org.apache.commons.logging.LogFactory; */ public class IDTracker { - private static Log log = LogFactory.getLog(IDTracker.class); + private static final Log log = LogFactory.getLog(IDTracker.class); // HashMap of ID's whose area is located on one or more consecutive // PageViewports. Each ID has an arraylist of PageViewports that // form the defined area of this ID - private Map idLocations = new HashMap(); + private Map idLocations = new java.util.HashMap(); // idref's whose target PageViewports have yet to be identified // Each idref has a HashSet of Resolvable objects containing that idref - private Map unresolvedIDRefs = new HashMap(); + private Map unresolvedIDRefs = new java.util.HashMap(); - private Set unfinishedIDs = new HashSet(); + private Set unfinishedIDs = new java.util.HashSet(); - private Set alreadyResolvedIDs = new HashSet(); + private Set alreadyResolvedIDs = new java.util.HashSet(); /** * Tie a PageViewport with an ID found on a child area of the PV. Note that @@ -198,7 +196,7 @@ public class IDTracker { public void addUnresolvedIDRef(String idref, Resolvable res) { Set todo = (Set) unresolvedIDRefs.get(idref); if (todo == null) { - todo = new HashSet(); + todo = new java.util.HashSet(); unresolvedIDRefs.put(idref, todo); } // add Resolvable object to this HashSet diff --git a/src/java/org/apache/fop/area/PageViewport.java b/src/java/org/apache/fop/area/PageViewport.java index 23d066099..a7523530b 100644 --- a/src/java/org/apache/fop/area/PageViewport.java +++ b/src/java/org/apache/fop/area/PageViewport.java @@ -89,7 +89,7 @@ public class PageViewport extends AreaTreeObject implements Resolvable, Cloneabl //Arbitrary attachments to the page from extensions that need to pass information //down to the renderers. - private List extensionAttachments = null; + private List/*<ExtensionAttachment>*/ extensionAttachments = null; /** * logging instance @@ -122,7 +122,8 @@ public class PageViewport extends AreaTreeObject implements Resolvable, Cloneabl */ public PageViewport(PageViewport original) { if (original.extensionAttachments != null) { - this.extensionAttachments = new java.util.ArrayList(original.extensionAttachments); + this.extensionAttachments + = new java.util.ArrayList/*<ExtensionAttachment>*/(original.extensionAttachments); } this.pageIndex = original.pageIndex; this.pageNumber = original.pageNumber; @@ -588,7 +589,7 @@ public class PageViewport extends AreaTreeObject implements Resolvable, Cloneabl */ public void addExtensionAttachment(ExtensionAttachment attachment) { if (this.extensionAttachments == null) { - this.extensionAttachments = new java.util.ArrayList(); + this.extensionAttachments = new java.util.ArrayList/*<ExtensionAttachment>*/(); } extensionAttachments.add(attachment); } diff --git a/src/java/org/apache/fop/area/RegionReference.java b/src/java/org/apache/fop/area/RegionReference.java index eac90ce41..bee597673 100644 --- a/src/java/org/apache/fop/area/RegionReference.java +++ b/src/java/org/apache/fop/area/RegionReference.java @@ -160,4 +160,13 @@ public class RegionReference extends Area implements Cloneable { return rr; } + /** {@inheritDoc} */ + public String toString() { + StringBuffer sb = new StringBuffer(super.toString()); + sb.append(" {regionName=").append(regionName); + sb.append(", regionClass=").append(regionClass); + sb.append(", ctm=").append(ctm); + sb.append("}"); + return sb.toString(); + } } diff --git a/src/java/org/apache/fop/area/RenderPagesModel.java b/src/java/org/apache/fop/area/RenderPagesModel.java index e75fd4e79..13995b099 100644 --- a/src/java/org/apache/fop/area/RenderPagesModel.java +++ b/src/java/org/apache/fop/area/RenderPagesModel.java @@ -50,9 +50,9 @@ public class RenderPagesModel extends AreaTreeModel { /** * Pages that have been prepared but not rendered yet. */ - protected List prepared = new java.util.ArrayList(); - private List pendingODI = new java.util.ArrayList(); - private List endDocODI = new java.util.ArrayList(); + protected List/*<PageViewport>*/ prepared = new java.util.ArrayList/*<PageViewport>*/(); + private List/*<OffDocumentItem>*/ pendingODI = new java.util.ArrayList/*<OffDocumentItem>*/(); + private List/*<OffDocumentItem>*/ endDocODI = new java.util.ArrayList/*<OffDocumentItem>*/(); /** * Create a new render pages model with the given renderer. @@ -66,7 +66,7 @@ public class RenderPagesModel extends AreaTreeModel { FontInfo fontInfo, OutputStream stream) throws FOPException { super(); - renderer = userAgent.getRendererFactory().createRenderer( + this.renderer = userAgent.getRendererFactory().createRenderer( userAgent, outputFormat); try { diff --git a/src/java/org/apache/fop/area/inline/FilledArea.java b/src/java/org/apache/fop/area/inline/FilledArea.java index 3e108db19..7df62e79b 100644 --- a/src/java/org/apache/fop/area/inline/FilledArea.java +++ b/src/java/org/apache/fop/area/inline/FilledArea.java @@ -70,10 +70,10 @@ public class FilledArea extends InlineParent { /** * Set the unit width for the areas to fill the full width. * - * @param w the unit width + * @param width the unit width */ - public void setUnitWidth(int w) { - unitWidth = w; + public void setUnitWidth(int width) { + this.unitWidth = width; } /** @@ -82,7 +82,7 @@ public class FilledArea extends InlineParent { * @return the unit width */ public int getUnitWidth() { - return unitWidth; + return this.unitWidth; } /** @@ -117,7 +117,7 @@ public class FilledArea extends InlineParent { } /** - * recursively apply the variation factor to all descendant areas + * Recursively apply the variation factor to all descendant areas * @param variationFactor the variation factor that must be applied to adjustments * @param lineStretch the total stretch of the line * @param lineShrink the total shrink of the line diff --git a/src/java/org/apache/fop/area/inline/Image.java b/src/java/org/apache/fop/area/inline/Image.java index 1fc3375e5..7d802db49 100644 --- a/src/java/org/apache/fop/area/inline/Image.java +++ b/src/java/org/apache/fop/area/inline/Image.java @@ -28,14 +28,14 @@ import org.apache.fop.area.Area; */ public class Image extends Area { private String url; - + /** * Create a new image with the given url. * - * @param u the url of the image + * @param url the url of the image */ - public Image(String u) { - url = u; + public Image(String url) { + this.url = url; } /** @@ -45,7 +45,7 @@ public class Image extends Area { * @return the url of this image */ public String getURL() { - return url; + return this.url; } } diff --git a/src/java/org/apache/fop/area/inline/InlineArea.java b/src/java/org/apache/fop/area/inline/InlineArea.java index d8936dd42..6d5d9ca98 100644 --- a/src/java/org/apache/fop/area/inline/InlineArea.java +++ b/src/java/org/apache/fop/area/inline/InlineArea.java @@ -221,7 +221,7 @@ public class InlineArea extends Area { notifyIPDVariation(ipdVariation); } - /** + /** * notify the parent area about the ipd variation of this area * or of a descendant area * @param ipdVariation the difference between new and old ipd diff --git a/src/java/org/apache/fop/area/inline/TextArea.java b/src/java/org/apache/fop/area/inline/TextArea.java index 102b0a330..f736b894c 100644 --- a/src/java/org/apache/fop/area/inline/TextArea.java +++ b/src/java/org/apache/fop/area/inline/TextArea.java @@ -63,6 +63,7 @@ public class TextArea extends AbstractTextArea { * * @param word the word string * @param offset the offset for the next area + * @param letterAdjust the letter adjustment array (may be null) */ public void addWord(String word, int offset, int[] letterAdjust) { WordArea wordArea = new WordArea(word, offset, letterAdjust); @@ -98,7 +99,7 @@ public class TextArea extends AbstractTextArea { StringBuffer text = new StringBuffer(); InlineArea child; // assemble the text - for (int i = 0; i < inlines.size(); i ++) { + for (int i = 0; i < inlines.size(); i++) { child = (InlineArea) inlines.get(i); if (child instanceof WordArea) { text.append(((WordArea) child).getWord()); @@ -109,5 +110,9 @@ public class TextArea extends AbstractTextArea { return text.toString(); } + /** {@inheritDoc} */ + public String toString() { + return "TextArea{text=" + getText() + "}"; + } } diff --git a/src/java/org/apache/fop/area/inline/Viewport.java b/src/java/org/apache/fop/area/inline/Viewport.java index fadc1ec2a..489f5afda 100644 --- a/src/java/org/apache/fop/area/inline/Viewport.java +++ b/src/java/org/apache/fop/area/inline/Viewport.java @@ -45,7 +45,7 @@ public class Viewport extends InlineArea { * @param child the child content area of this viewport */ public Viewport(Area child) { - content = child; + this.content = child; } /** @@ -54,7 +54,7 @@ public class Viewport extends InlineArea { * @param c true if this viewport should clip */ public void setClip(boolean c) { - clip = c; + this.clip = c; } /** @@ -63,7 +63,7 @@ public class Viewport extends InlineArea { * @return true if this viewport should clip */ public boolean getClip() { - return clip; + return this.clip; } /** @@ -72,7 +72,7 @@ public class Viewport extends InlineArea { * @param cp the position and size to place the content */ public void setContentPosition(Rectangle2D cp) { - contentPosition = cp; + this.contentPosition = cp; } /** @@ -81,7 +81,7 @@ public class Viewport extends InlineArea { * @return the position and size to place the content */ public Rectangle2D getContentPosition() { - return contentPosition; + return this.contentPosition; } /** @@ -98,7 +98,7 @@ public class Viewport extends InlineArea { * @return the content area */ public Area getContent() { - return content; + return this.content; } private void writeObject(java.io.ObjectOutputStream out) @@ -123,9 +123,9 @@ public class Viewport extends InlineArea { in.readFloat(), in.readFloat()); } - clip = in.readBoolean(); - props = (HashMap) in.readObject(); - content = (Area) in.readObject(); + this.clip = in.readBoolean(); + this.props = (HashMap) in.readObject(); + this.content = (Area) in.readObject(); } } diff --git a/src/java/org/apache/fop/cli/InputHandler.java b/src/java/org/apache/fop/cli/InputHandler.java index 5e38b803a..4f49ea269 100644 --- a/src/java/org/apache/fop/cli/InputHandler.java +++ b/src/java/org/apache/fop/cli/InputHandler.java @@ -51,6 +51,9 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.Fop; import org.apache.fop.apps.FopFactory; import org.apache.fop.render.awt.viewer.Renderable; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; /** * Class for handling files input from command line diff --git a/src/java/org/apache/fop/events/EventFormatter.xml b/src/java/org/apache/fop/events/EventFormatter.xml index cd956ed6a..3b3b34e36 100644 --- a/src/java/org/apache/fop/events/EventFormatter.xml +++ b/src/java/org/apache/fop/events/EventFormatter.xml @@ -23,6 +23,7 @@ <message key="rule.childOfSPM">The element must be a child of fo:simple-page-master.</message> <message key="rule.childOfDeclarations">The element must be a child of fo:declarations.</message> <message key="rule.childOfSPMorDeclarations">The element must be a child of fo:declarations or fo:simple-page-master.</message> + <message key="rule.childOfInstreamForeignObjectorExternalGraphic">The element must be a child of fo:instream-foreign-object or fo:external-graphic.</message> <message key="rule.wrapperInvalidChildForParent">An fo:wrapper is only permitted to have children that would be permitted for its parent.</message> <message key="org.apache.fop.fo.FOValidationEventProducer.tooManyNodes">For "{elementName}", only one "{offendingNode}" may be declared.{{locator}}</message> <message key="org.apache.fop.fo.FOValidationEventProducer.nodeOutOfOrder">For "{elementName}", "{tooLateNode}" must be declared before "{tooEarlyNode}"!{{locator}}</message> @@ -99,4 +100,7 @@ Any reference to it will be considered a reference to the first occurrence in th <message key="org.apache.fop.fonts.FontEventAdapter.fontSubstituted">Font "{requested}" not found. Substituting with "{effective}".</message> <message key="org.apache.fop.fonts.FontEventAdapter.fontLoadingErrorAtAutoDetection">Unable to load font file: {fontURL}.[ Reason: {e}]</message> <message key="org.apache.fop.fonts.FontEventAdapter.glyphNotAvailable">Glyph "{ch}" (0x{ch,hex}[, {ch,glyph-name}]) not available in font "{fontName}".</message> +<message key="org.apache.fop.afp.AFPEventProducer.warnDefaultFontSetup"/> +<message key="org.apache.fop.afp.AFPEventProducer.warnMissingDefaultFont"/> +<message key="org.apache.fop.afp.AFPEventProducer.characterSetEncodingError"/> </catalogue> diff --git a/src/java/org/apache/fop/fo/ElementMapping.java b/src/java/org/apache/fop/fo/ElementMapping.java index d51c21993..1651f23a6 100644 --- a/src/java/org/apache/fop/fo/ElementMapping.java +++ b/src/java/org/apache/fop/fo/ElementMapping.java @@ -39,6 +39,7 @@ public abstract class ElementMapping { /** The HashMap table of formatting objects defined by the ElementMapping */ protected HashMap foObjs = null; + //Please don't change that to java.util.Map as that can break extensions. /** The namespace for the ElementMapping */ protected String namespaceURI = null; diff --git a/src/java/org/apache/fop/fo/FObj.java b/src/java/org/apache/fop/fo/FObj.java index 3e369b934..e0624df69 100644 --- a/src/java/org/apache/fop/fo/FObj.java +++ b/src/java/org/apache/fop/fo/FObj.java @@ -573,6 +573,11 @@ public abstract class FObj extends FONode implements Constants { } } + /** @return true if this FObj has extension attachments */ + public boolean hasExtensionAttachments() { + return extensionAttachments != null; + } + /** * Adds a foreign attribute to this FObj. * @param attributeName the attribute name as a QName instance diff --git a/src/java/org/apache/fop/fo/flow/Marker.java b/src/java/org/apache/fop/fo/flow/Marker.java index 1e8b352bb..01863c0c7 100644 --- a/src/java/org/apache/fop/fo/flow/Marker.java +++ b/src/java/org/apache/fop/fo/flow/Marker.java @@ -34,6 +34,7 @@ import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.PropertyListMaker; import org.apache.fop.fo.ValidationException; import org.apache.fop.fo.properties.Property; +import org.apache.fop.fo.properties.PropertyCache; /** * Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_marker"> @@ -334,10 +335,10 @@ public class Marker extends FObjMixed { } /** Convenience inner class */ - private static final class MarkerAttribute { + public static final class MarkerAttribute { - private static Map attributeCache = - Collections.synchronizedMap(new java.util.WeakHashMap()); + private static PropertyCache attributeCache = + new PropertyCache(MarkerAttribute.class); protected String namespace; protected String qname; @@ -373,18 +374,26 @@ public class Marker extends FObjMixed { private static MarkerAttribute getInstance( String namespace, String qname, String name, String value) { - MarkerAttribute newInstance = - new MarkerAttribute(namespace, qname, name, value); - if (attributeCache.containsKey(newInstance)) { - return (MarkerAttribute) attributeCache.get(newInstance); - } else { - attributeCache.put(newInstance, newInstance); - return newInstance; - } + return attributeCache.fetch( + new MarkerAttribute(namespace, qname, name, value)); + } + + /** {@inheritDoc} */ + public int hashCode() { + int hash = 17; + hash = (37 * hash) + (this.namespace == null ? 0 : this.namespace.hashCode()); + hash = (37 * hash) + (this.qname == null ? 0 : this.qname.hashCode()); + hash = (37 * hash) + (this.name == null ? 0 : this.name.hashCode()); + hash = (37 * hash) + (this.value == null ? 0 : this.value.hashCode()); + return hash; } /** {@inheritDoc} */ public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o instanceof MarkerAttribute) { MarkerAttribute attr = (MarkerAttribute) o; return ((attr.namespace == this.namespace) diff --git a/src/java/org/apache/fop/fo/properties/PropertyCache.java b/src/java/org/apache/fop/fo/properties/PropertyCache.java index d472b574c..dc9abb023 100644 --- a/src/java/org/apache/fop/fo/properties/PropertyCache.java +++ b/src/java/org/apache/fop/fo/properties/PropertyCache.java @@ -19,6 +19,8 @@ package org.apache.fop.fo.properties; +import org.apache.fop.fo.flow.Marker; + import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; @@ -53,7 +55,7 @@ public final class PropertyCache { private Class runtimeType; - private boolean[] votesForRehash = new boolean[SEGMENT_COUNT]; + private final boolean[] votesForRehash = new boolean[SEGMENT_COUNT]; /* same hash function as used by java.util.HashMap */ private static int hash(Object x) { @@ -381,6 +383,19 @@ public final class PropertyCache { return (CommonBorderPaddingBackground.BorderInfo) fetch((Object) bi); } + /** + * Checks if the given {@link Marker.MarkerAttribute} is present + * in the cache - if so, returns a reference to the cached instance. + * Otherwise the given object is added to the cache and returned. + * + * @param ma the MarkerAttribute instance to check for + * @return the cached instance + */ + public Marker.MarkerAttribute fetch( + Marker.MarkerAttribute ma) { + return (Marker.MarkerAttribute) fetch((Object) ma); + } + /** {@inheritDoc} */ public String toString() { return super.toString() + "[runtimeType=" + this.runtimeType + "]"; diff --git a/src/java/org/apache/fop/fonts/Base14Font.java b/src/java/org/apache/fop/fonts/Base14Font.java index 04349a148..9b2e95bc7 100644 --- a/src/java/org/apache/fop/fonts/Base14Font.java +++ b/src/java/org/apache/fop/fonts/Base14Font.java @@ -19,6 +19,7 @@ package org.apache.fop.fonts; + /** * Base class for all Base 14 fonts. */ diff --git a/src/java/org/apache/fop/fonts/CIDFont.java b/src/java/org/apache/fop/fonts/CIDFont.java index eac794514..8f468f7a4 100644 --- a/src/java/org/apache/fop/fonts/CIDFont.java +++ b/src/java/org/apache/fop/fonts/CIDFont.java @@ -76,4 +76,4 @@ public abstract class CIDFont extends CustomFont { return true; } -}
\ No newline at end of file +} diff --git a/src/java/org/apache/fop/fonts/CustomFont.java b/src/java/org/apache/fop/fonts/CustomFont.java index 0b40dfecc..4cf24ae16 100644 --- a/src/java/org/apache/fop/fonts/CustomFont.java +++ b/src/java/org/apache/fop/fonts/CustomFont.java @@ -26,6 +26,7 @@ import java.util.Set; import javax.xml.transform.Source; + /** * Abstract base class for custom fonts loaded from files, for example. */ diff --git a/src/java/org/apache/fop/fonts/Font.java b/src/java/org/apache/fop/fonts/Font.java index ebd45457d..e9740c00c 100644 --- a/src/java/org/apache/fop/fonts/Font.java +++ b/src/java/org/apache/fop/fonts/Font.java @@ -23,6 +23,7 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.fonts.CodePointMapping; /** * This class holds font state information and provides access to the font diff --git a/src/java/org/apache/fop/fonts/FontCollection.java b/src/java/org/apache/fop/fonts/FontCollection.java index 3c9bba7f4..d481ae2f9 100644 --- a/src/java/org/apache/fop/fonts/FontCollection.java +++ b/src/java/org/apache/fop/fonts/FontCollection.java @@ -24,6 +24,7 @@ package org.apache.fop.fonts; * Sets up a set of fonts */ public interface FontCollection { + /** * Sets up fonts in a font info object. * diff --git a/src/java/org/apache/fop/fonts/FontDescriptor.java b/src/java/org/apache/fop/fonts/FontDescriptor.java index fadc73834..e7c81c9f3 100644 --- a/src/java/org/apache/fop/fonts/FontDescriptor.java +++ b/src/java/org/apache/fop/fonts/FontDescriptor.java @@ -19,6 +19,7 @@ package org.apache.fop.fonts; + /** * This interface enhances the font metrics interface with access methods to * value needed to register fonts in various target formats like PDF or diff --git a/src/java/org/apache/fop/fonts/FontEventListener.java b/src/java/org/apache/fop/fonts/FontEventListener.java index b508d7053..740a05fdc 100644 --- a/src/java/org/apache/fop/fonts/FontEventListener.java +++ b/src/java/org/apache/fop/fonts/FontEventListener.java @@ -19,7 +19,6 @@ package org.apache.fop.fonts; - /** * Event listener interface for font-related events. */ diff --git a/src/java/org/apache/fop/fonts/FontInfo.java b/src/java/org/apache/fop/fonts/FontInfo.java index 2bcc6d7e1..8f8032767 100644 --- a/src/java/org/apache/fop/fonts/FontInfo.java +++ b/src/java/org/apache/fop/fonts/FontInfo.java @@ -110,6 +110,19 @@ public class FontInfo { } /** + * Adds a series of new font triplets given an array of font family names. + * @param name internal key + * @param families an array of font family names + * @param style font style (normal, italic, oblique...) + * @param weight font weight + */ + public void addFontProperties(String name, String[] families, String style, int weight) { + for (int i = 0; i < families.length; i++) { + addFontProperties(name, families[i], style, weight); + } + } + + /** * Adds a new font triplet. * @param internalFontKey internal font key * @param triplet the font triplet to associate with the internal key @@ -193,7 +206,8 @@ public class FontInfo { private FontTriplet fontLookup(String family, String style, int weight, boolean substitutable) { if (log.isTraceEnabled()) { - log.trace("Font lookup: " + family + " " + style + " " + weight); + log.trace("Font lookup: " + family + " " + style + " " + weight + + (substitutable ? " substitutable" : "")); } FontTriplet startKey = createFontKey(family, style, weight); @@ -215,7 +229,7 @@ public class FontInfo { } private FontTriplet fuzzyFontLookup(String family, String style, - int weight, FontTriplet startKey, boolean substFont) { + int weight, FontTriplet startKey, boolean substitutable) { FontTriplet key; String internalFontKey = null; if (!family.equals(startKey.getName())) { @@ -232,7 +246,8 @@ public class FontInfo { internalFontKey = getInternalFontKey(key); } - if (!substFont && internalFontKey == null) { + // return null if not found and not substitutable + if (!substitutable && internalFontKey == null) { return null; } @@ -263,18 +278,18 @@ public class FontInfo { // fallback 2: try the same font-family with default style and weight /* obsolete: replaced by the loop above - if (f == null) { + if (internalFontKey == null) { key = createFontKey(family, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - f = getInternalFontKey(key); + internalFontKey = getInternalFontKey(key); }*/ - // fallback 3: try any family with orig style/weight + // fallback 3: try any family with original style/weight if (internalFontKey == null) { return fuzzyFontLookup("any", style, weight, startKey, false); } // last resort: use default - if (internalFontKey == null) { + if (key == null && internalFontKey == null) { key = Font.DEFAULT_FONT; internalFontKey = getInternalFontKey(key); } @@ -303,6 +318,7 @@ public class FontInfo { /** * Retrieves a (possibly cached) Font instance based on a FontTriplet and a font size. + * * @param triplet the font triplet designating the requested font * @param fontSize the font size * @return the requested Font instance @@ -326,6 +342,57 @@ public class FontInfo { return font; } + private List/*<FontTriplet>*/ getTripletsForName(String fontName) { + List/*<FontTriplet>*/ matchedTriplets = new java.util.ArrayList/*<FontTriplet>*/(); + Iterator it = triplets.keySet().iterator(); + while (it.hasNext()) { + FontTriplet triplet = (FontTriplet)it.next(); + String tripletName = triplet.getName(); + if (tripletName.toLowerCase().equals(fontName.toLowerCase())) { + matchedTriplets.add(triplet); + } + } + return matchedTriplets; + } + + /** + * Returns a suitable internal font given an AWT Font instance. + * + * @param awtFont the AWT font + * @return a best matching internal Font + */ + public Font getFontInstanceForAWTFont(java.awt.Font awtFont) { + String awtFontName = awtFont.getName(); + String awtFontFamily = awtFont.getFamily(); + String awtFontStyle = awtFont.isItalic() ? Font.STYLE_ITALIC : Font.STYLE_NORMAL; + int awtFontWeight = awtFont.isBold() ? Font.WEIGHT_BOLD : Font.WEIGHT_NORMAL; + + FontTriplet matchedTriplet = null; + List/*<FontTriplet>*/ triplets = getTripletsForName(awtFontName); + if (!triplets.isEmpty()) { + Iterator it = triplets.iterator(); + while (it.hasNext()) { + FontTriplet triplet = (FontTriplet)it.next(); + boolean styleMatched = triplet.getStyle().equals(awtFontStyle); + boolean weightMatched = triplet.getWeight() == awtFontWeight; + if (styleMatched && weightMatched) { + matchedTriplet = triplet; + break; + } + } + } + + // not matched on font name so do a lookup using family + if (matchedTriplet == null) { + if (awtFontFamily.equals("sanserif")) { + awtFontFamily = "sans-serif"; + } + matchedTriplet = fontLookup(awtFontFamily, awtFontStyle, awtFontWeight); + } + int fontSize = Math.round(awtFont.getSize2D() * 1000); + return getFontInstance(matchedTriplet, fontSize); + } + /** * Lookup a font. * <br> @@ -345,7 +412,7 @@ public class FontInfo { private List/*<FontTriplet>*/ fontLookup(String[] families, String style, int weight, boolean substitutable) { - List matchingTriplets = new java.util.ArrayList(); + List/*<FontTriplet>*/ matchingTriplets = new java.util.ArrayList/*<FontTriplet>*/(); FontTriplet triplet = null; for (int i = 0; i < families.length; i++) { triplet = fontLookup(families[i], style, weight, substitutable); @@ -555,7 +622,7 @@ public class FontInfo { List/*<FontTriplet>*/ foundTriplets = new java.util.ArrayList(); for (Iterator iter = triplets.entrySet().iterator(); iter.hasNext();) { Map.Entry tripletEntry = (Map.Entry) iter.next(); - if (fontName.equals(((String)tripletEntry.getValue()))) { + if (fontName.equals((tripletEntry.getValue()))) { foundTriplets.add(tripletEntry.getKey()); } } diff --git a/src/java/org/apache/fop/fonts/FontMetrics.java b/src/java/org/apache/fop/fonts/FontMetrics.java index 7d5588690..29ade1ef3 100644 --- a/src/java/org/apache/fop/fonts/FontMetrics.java +++ b/src/java/org/apache/fop/fonts/FontMetrics.java @@ -23,6 +23,7 @@ import java.util.Map; import java.util.Set; + /** * Main interface for access to font metrics. */ diff --git a/src/java/org/apache/fop/fonts/FontTriplet.java b/src/java/org/apache/fop/fonts/FontTriplet.java index 8e0acd8f2..f5cfe442a 100644 --- a/src/java/org/apache/fop/fonts/FontTriplet.java +++ b/src/java/org/apache/fop/fonts/FontTriplet.java @@ -21,6 +21,7 @@ package org.apache.fop.fonts; import java.io.Serializable; + /** * FontTriplet contains information on name, style and weight of one font */ diff --git a/src/java/org/apache/fop/fonts/FontType.java b/src/java/org/apache/fop/fonts/FontType.java index 0abe06a10..95b594ca4 100644 --- a/src/java/org/apache/fop/fonts/FontType.java +++ b/src/java/org/apache/fop/fonts/FontType.java @@ -19,12 +19,10 @@ package org.apache.fop.fonts; -import org.apache.avalon.framework.ValuedEnum; - /** * This class enumerates all supported font types. */ -public class FontType extends ValuedEnum { +public class FontType { /** * Collective identifier for "other" font types @@ -51,12 +49,16 @@ public class FontType extends ValuedEnum { */ public static final FontType TRUETYPE = new FontType("TrueType", 5); + private final String name; + private final int value; + /** * @see org.apache.avalon.framework.Enum#Enum(String) */ protected FontType(String name, int value) { - super(name, value); + this.name = name; + this.value = value; } @@ -107,4 +109,22 @@ public class FontType extends ValuedEnum { } } + /** + * Returns the name + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Returns the value + * + * @return the value + */ + public int getValue() { + return value; + } + } diff --git a/src/java/org/apache/fop/fonts/FontUtil.java b/src/java/org/apache/fop/fonts/FontUtil.java index 6ec89631f..49f23c12f 100644 --- a/src/java/org/apache/fop/fonts/FontUtil.java +++ b/src/java/org/apache/fop/fonts/FontUtil.java @@ -19,6 +19,7 @@ package org.apache.fop.fonts; + /** * Font utilities. */ diff --git a/src/java/org/apache/fop/fonts/MultiByteFont.java b/src/java/org/apache/fop/fonts/MultiByteFont.java index f25ca4e7e..b22b92e2f 100644 --- a/src/java/org/apache/fop/fonts/MultiByteFont.java +++ b/src/java/org/apache/fop/fonts/MultiByteFont.java @@ -23,6 +23,7 @@ package org.apache.fop.fonts; import java.text.DecimalFormat; import java.util.Map; + /** * Generic MultiByte (CID) font */ diff --git a/src/java/org/apache/fop/fonts/MutableFont.java b/src/java/org/apache/fop/fonts/MutableFont.java index 5939bfed4..a5acf51b3 100644 --- a/src/java/org/apache/fop/fonts/MutableFont.java +++ b/src/java/org/apache/fop/fonts/MutableFont.java @@ -23,6 +23,7 @@ import java.util.Map; import java.util.Set; + /** * This interface is used to set the values of a font during configuration time. */ diff --git a/src/java/org/apache/fop/fonts/Typeface.java b/src/java/org/apache/fop/fonts/Typeface.java index 2fa8f1888..f4e317de3 100644 --- a/src/java/org/apache/fop/fonts/Typeface.java +++ b/src/java/org/apache/fop/fonts/Typeface.java @@ -139,4 +139,9 @@ public abstract class Typeface implements FontMetrics { } } } + + /** {@inheritDoc} */ + public String toString() { + return getFullName(); + } } diff --git a/src/java/org/apache/fop/fonts/package.html b/src/java/org/apache/fop/fonts/package.html index 33e1e2cb3..fee0bf827 100644 --- a/src/java/org/apache/fop/fonts/package.html +++ b/src/java/org/apache/fop/fonts/package.html @@ -1,3 +1,20 @@ +<!-- + 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.html 643433 2008-04-01 15:08:24Z acumiskey $ --> <HTML> <TITLE>org.apache.fop.fonts Package</TITLE> <BODY> diff --git a/src/java/org/apache/fop/image/loader/batik/BatikUtil.java b/src/java/org/apache/fop/image/loader/batik/BatikUtil.java index 558c3b043..20a7bf767 100644 --- a/src/java/org/apache/fop/image/loader/batik/BatikUtil.java +++ b/src/java/org/apache/fop/image/loader/batik/BatikUtil.java @@ -19,6 +19,11 @@ package org.apache.fop.image.loader.batik; +import org.w3c.dom.Document; + +import org.apache.batik.dom.AbstractDocument; +import org.apache.batik.dom.util.DOMUtilities; + /** * Helper utilities for Apache Batik. */ @@ -38,4 +43,18 @@ public class BatikUtil { return false; } + /** + * Clones an SVG DOM document. This is used for making SVG production thread-safe when the + * SVG document is cached and re-used. + * @param doc the SVG DOM to be cloned + * @return the cloned SVG DOM + */ + public static Document cloneSVGDocument(Document doc) { + Document clonedDoc = DOMUtilities.deepCloneDocument(doc, doc.getImplementation()); + if (clonedDoc instanceof AbstractDocument) { + ((AbstractDocument)clonedDoc).setDocumentURI(((AbstractDocument)doc).getDocumentURI()); + } + return clonedDoc; + } + } diff --git a/src/java/org/apache/fop/image/loader/batik/Graphics2DImagePainterImpl.java b/src/java/org/apache/fop/image/loader/batik/Graphics2DImagePainterImpl.java new file mode 100644 index 000000000..ea92f748b --- /dev/null +++ b/src/java/org/apache/fop/image/loader/batik/Graphics2DImagePainterImpl.java @@ -0,0 +1,67 @@ +package org.apache.fop.image.loader.batik; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; + +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.gvt.GraphicsNode; + +import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; + +/** + * A generic graphics 2D image painter implementation + */ +public class Graphics2DImagePainterImpl implements Graphics2DImagePainter { + + private final GraphicsNode root; + /** the Batik bridge context */ + protected final BridgeContext ctx; + /** the intrinsic size of the image */ + protected final Dimension imageSize; + + /** + * Main constructor + * + * @param root the graphics node root + * @param ctx the bridge context + * @param imageSize the image size + */ + public Graphics2DImagePainterImpl(GraphicsNode root, BridgeContext ctx, Dimension imageSize) { + this.root = root; + this.imageSize = imageSize; + this.ctx = ctx; + } + + /** {@inheritDoc} */ + public Dimension getImageSize() { + return imageSize; + } + + private void prepare(Graphics2D g2d, Rectangle2D area) { + // If no viewbox is defined in the svg file, a viewbox of 100x100 is + // assumed, as defined in SVGUserAgent.getViewportSize() + double tx = area.getX(); + double ty = area.getY(); + if (tx != 0 || ty != 0) { + g2d.translate(tx, ty); + } + + float iw = (float) ctx.getDocumentSize().getWidth(); + float ih = (float) ctx.getDocumentSize().getHeight(); + float w = (float) area.getWidth(); + float h = (float) area.getHeight(); + float sx = w / iw; + float sy = h / ih; + if (sx != 1.0 || sy != 1.0) { + g2d.scale(sx, sy); + } + } + + /** {@inheritDoc} */ + public void paint(Graphics2D g2d, Rectangle2D area) { + prepare(g2d, area); + root.paint(g2d); + } + +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java b/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java index 9ea333af0..2bb521dc9 100644 --- a/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java +++ b/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java @@ -20,11 +20,11 @@ package org.apache.fop.image.loader.batik; import java.awt.Dimension; -import java.awt.Graphics2D; import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; import java.util.Map; +import org.w3c.dom.Document; + import org.apache.batik.bridge.BridgeContext; import org.apache.batik.bridge.GVTBuilder; import org.apache.batik.bridge.UserAgent; @@ -32,10 +32,11 @@ 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.svg.SimpleSVGUserAgent; + import org.apache.xmlgraphics.image.loader.Image; import org.apache.xmlgraphics.image.loader.ImageException; import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.ImageInfo; import org.apache.xmlgraphics.image.loader.ImageProcessingHints; import org.apache.xmlgraphics.image.loader.XMLNamespaceEnabledImageFlavor; import org.apache.xmlgraphics.image.loader.impl.AbstractImageConverter; @@ -44,6 +45,8 @@ import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; import org.apache.xmlgraphics.util.UnitConv; +import org.apache.fop.svg.SimpleSVGUserAgent; + /** * This ImageConverter converts SVG images to Java2D. * <p> @@ -58,7 +61,7 @@ public class ImageConverterSVG2G2D extends AbstractImageConverter { private static Log log = LogFactory.getLog(ImageConverterSVG2G2D.class); /** {@inheritDoc} */ - public Image convert(Image src, Map hints) throws ImageException { + public Image convert(final Image src, Map hints) throws ImageException { checkSourceFlavor(src); final ImageXMLDOM svg = (ImageXMLDOM)src; if (!SVGDOMImplementation.SVG_NAMESPACE_URI.equals(svg.getRootNamespace())) { @@ -76,37 +79,28 @@ public class ImageConverterSVG2G2D extends AbstractImageConverter { GVTBuilder builder = new GVTBuilder(); final BridgeContext ctx = new BridgeContext(ua); + Document doc = svg.getDocument(); + //Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine) + //to it. + Document clonedDoc = BatikUtil.cloneSVGDocument(doc); + //Build the GVT tree final GraphicsNode root; try { - root = builder.build(ctx, svg.getDocument()); + root = builder.build(ctx, clonedDoc); } catch (Exception e) { throw new ImageException("GVT tree could not be built for SVG graphic", e); } //Create the painter - Graphics2DImagePainter painter = new Graphics2DImagePainter() { - - public void paint(Graphics2D g2d, Rectangle2D area) { - // If no viewbox is defined in the svg file, a viewbox of 100x100 is - // assumed, as defined in SVGUserAgent.getViewportSize() - float iw = (float) ctx.getDocumentSize().getWidth(); - float ih = (float) ctx.getDocumentSize().getHeight(); - float w = (float) area.getWidth(); - float h = (float) area.getHeight(); - g2d.translate(area.getX(), area.getY()); - g2d.scale(w / iw, h / ih); - - root.paint(g2d); - } - - public Dimension getImageSize() { - return new Dimension(svg.getSize().getWidthMpt(), svg.getSize().getHeightMpt()); - } - - }; - - ImageGraphics2D g2dImage = new ImageGraphics2D(src.getInfo(), painter); + int width = svg.getSize().getWidthMpt(); + int height = svg.getSize().getHeightMpt(); + Dimension imageSize = new Dimension(width, height); + Graphics2DImagePainter painter = createPainter(ctx, root, imageSize); + + //Create g2d image + ImageInfo imageInfo = src.getInfo(); + ImageGraphics2D g2dImage = new ImageGraphics2D(imageInfo, painter); return g2dImage; } @@ -129,6 +123,19 @@ public class ImageConverterSVG2G2D extends AbstractImageConverter { }; } + /** + * Creates a Graphics 2D image painter + * + * @param ctx the bridge context + * @param root the graphics node root + * @param imageSize the image size + * @return the newly created graphics 2d image painter + */ + protected Graphics2DImagePainter createPainter( + BridgeContext ctx, GraphicsNode root, Dimension imageSize) { + return new Graphics2DImagePainterImpl(root, ctx, imageSize); + } + /** {@inheritDoc} */ public ImageFlavor getSourceFlavor() { return XMLNamespaceEnabledImageFlavor.SVG_DOM; diff --git a/src/java/org/apache/fop/layoutmgr/TraitSetter.java b/src/java/org/apache/fop/layoutmgr/TraitSetter.java index 154d32e96..9cab6322b 100644 --- a/src/java/org/apache/fop/layoutmgr/TraitSetter.java +++ b/src/java/org/apache/fop/layoutmgr/TraitSetter.java @@ -29,6 +29,7 @@ import org.apache.fop.datatypes.SimplePercentBaseContext; import org.apache.fop.fo.Constants; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.CommonMarginBlock; +import org.apache.fop.fo.properties.CommonMarginBlock; import org.apache.fop.fo.properties.CommonTextDecoration; import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo; import org.apache.fop.fonts.Font; diff --git a/src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java index 6b0e88cbb..dc8a020ae 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java @@ -20,12 +20,12 @@ package org.apache.fop.layoutmgr.inline; import org.apache.fop.fo.flow.PageNumber; -import org.apache.fop.area.inline.InlineArea; -import org.apache.fop.area.inline.TextArea; -import org.apache.fop.area.Trait; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontTriplet; +import org.apache.fop.area.inline.InlineArea; +import org.apache.fop.area.inline.TextArea; +import org.apache.fop.area.Trait; import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.TraitSetter; import org.apache.fop.traits.MinOptMax; diff --git a/src/java/org/apache/fop/pdf/PDFDocument.java b/src/java/org/apache/fop/pdf/PDFDocument.java index 598fd433e..9bc4c0d2e 100644 --- a/src/java/org/apache/fop/pdf/PDFDocument.java +++ b/src/java/org/apache/fop/pdf/PDFDocument.java @@ -29,9 +29,12 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -42,7 +45,7 @@ import org.apache.commons.logging.LogFactory; /* font support based on work by Takayuki Takeuchi */ /** - * class representing a PDF document. + * Class representing a PDF document. * * The document is built up by calling various methods and then finally * output to given filehandle using output method. @@ -72,53 +75,38 @@ public class PDFDocument { /** Integer constant to represent PDF 1.4 */ public static final int PDF_VERSION_1_4 = 4; - /** - * the encoding to use when converting strings to PDF commandos. - */ + /** the encoding to use when converting strings to PDF commands */ public static final String ENCODING = "ISO-8859-1"; + /** the counter for object numbering */ + protected int objectcount = 0; + + /** the logger instance */ private Log log = LogFactory.getLog("org.apache.fop.pdf"); - /** - * the current character position - */ - protected int position = 0; + /** the current character position */ + private int position = 0; - /** - * the character position of each object - */ - protected List location = new java.util.ArrayList(); + /** character position of xref table */ + private int xref; - /** List of objects to write in the trailer */ - private List trailerObjects = new java.util.ArrayList(); + /** the character position of each object */ + private List location = new ArrayList(); - /** - * the counter for object numbering - */ - protected int objectcount = 0; - - /** - * the objects themselves - */ - protected List objects = new java.util.LinkedList(); + /** List of objects to write in the trailer */ + private List trailerObjects = new ArrayList(); - /** - * character position of xref table - */ - protected int xref; + /** the objects themselves */ + private List objects = new LinkedList(); /** Indicates what PDF version is active */ - protected int pdfVersion = PDF_VERSION_1_4; + private int pdfVersion = PDF_VERSION_1_4; - /** - * Indicates which PDF profiles are active (PDF/A, PDF/X etc.) - */ - protected PDFProfile pdfProfile = new PDFProfile(this); + /** Indicates which PDF profiles are active (PDF/A, PDF/X etc.) */ + private PDFProfile pdfProfile = new PDFProfile(this); - /** - * the /Root object - */ - protected PDFRoot root; + /** the /Root object */ + private PDFRoot root; /** The root outline object */ private PDFOutline outlineRoot = null; @@ -126,107 +114,67 @@ public class PDFDocument { /** The /Pages object (mark-fop@inomial.com) */ private PDFPages pages; - /** - * the /Info object - */ - protected PDFInfo info; + /** the /Info object */ + private PDFInfo info; - /** - * the /Resources object - */ - protected PDFResources resources; + /** the /Resources object */ + private PDFResources resources; - /** - * the documents encryption, if exists - */ - protected PDFEncryption encryption; + /** the document's encryption, if it exists */ + private PDFEncryption encryption; - /** - * the colorspace (0=RGB, 1=CMYK) - */ - protected PDFDeviceColorSpace colorspace = + /** the colorspace (0=RGB, 1=CMYK) */ + private PDFDeviceColorSpace colorspace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB); - /** - * the counter for Pattern name numbering (e.g. 'Pattern1') - */ - protected int patternCount = 0; + /** the counter for Pattern name numbering (e.g. 'Pattern1') */ + private int patternCount = 0; - /** - * the counter for Shading name numbering - */ - protected int shadingCount = 0; + /** the counter for Shading name numbering */ + private int shadingCount = 0; - /** - * the counter for XObject numbering - */ - protected int xObjectCount = 0; + /** the counter for XObject numbering */ + private int xObjectCount = 0; - /** - * the XObjects Map. - * Should be modified (works only for image subtype) - */ - protected Map xObjectsMap = new java.util.HashMap(); + /** the {@link PDFXObject}s map */ + /* TODO: Should be modified (works only for image subtype) */ + private Map xObjectsMap = new HashMap(); - /** - * the Font Map. - */ - protected Map fontMap = new java.util.HashMap(); + /** The {@link PDFFont} map */ + private Map fontMap = new HashMap(); - /** - * The filter map. - */ - protected Map filterMap = new java.util.HashMap(); + /** The {@link PDFFilter} map */ + private Map filterMap = new HashMap(); - /** - * List of PDFGState objects. - */ - protected List gstates = new java.util.ArrayList(); + /** List of {@link PDFGState}s. */ + private List gstates = new ArrayList(); - /** - * List of functions. - */ - protected List functions = new java.util.ArrayList(); + /** List of {@link PDFFunction}s. */ + private List functions = new ArrayList(); - /** - * List of shadings. - */ - protected List shadings = new java.util.ArrayList(); + /** List of {@link PDFShading}s. */ + private List shadings = new ArrayList(); - /** - * List of patterns. - */ - protected List patterns = new java.util.ArrayList(); + /** List of {@link PDFPattern}s. */ + private List patterns = new ArrayList(); - /** - * List of Links. - */ - protected List links = new java.util.ArrayList(); + /** List of {@link PDFLink}s. */ + private List links = new ArrayList(); - /** - * List of Destinations. - */ - protected List destinations; + /** List of {@link PDFDestination}s. */ + private List destinations; - /** - * List of FileSpecs. - */ - protected List filespecs = new java.util.ArrayList(); + /** List of {@link PDFFileSpec}s. */ + private List filespecs = new ArrayList(); - /** - * List of GoToRemotes. - */ - protected List gotoremotes = new java.util.ArrayList(); + /** List of {@link PDFGoToRemote}s. */ + private List gotoremotes = new ArrayList(); - /** - * List of GoTos. - */ - protected List gotos = new java.util.ArrayList(); + /** List of {@link PDFGoTo}s. */ + private List gotos = new ArrayList(); - /** - * List of PDFLaunch objects. - */ - protected List launches = new java.util.ArrayList(); + /** List of {@link PDFLaunch}es. */ + private List launches = new ArrayList(); /** * The PDFDests object for the name dictionary. @@ -258,7 +206,7 @@ public class PDFDocument { this.pages = getFactory().makePages(); // Create the Root object - this.root = getFactory().makeRoot(pages); + this.root = getFactory().makeRoot(this.pages); // Create the Resources object this.resources = getFactory().makeResources(); @@ -268,7 +216,8 @@ public class PDFDocument { } /** - * @return the integer representing the active PDF version (one of PDFDocument.PDF_VERSION_*) + * @return the integer representing the active PDF version + * (one of PDFDocument.PDF_VERSION_*) */ public int getPDFVersion() { return this.pdfVersion; @@ -293,7 +242,8 @@ public class PDFDocument { /** * Returns the factory for PDF objects. - * @return PDFFactory the factory + * + * @return the {@link PDFFactory} object */ public PDFFactory getFactory() { return this.factory; @@ -303,7 +253,8 @@ public class PDFDocument { * Indicates whether stream encoding on-the-fly is enabled. If enabled * stream can be serialized without the need for a buffer to merely * calculate the stream length. - * @return boolean true if on-the-fly encoding is enabled + * + * @return <code>true</code> if on-the-fly encoding is enabled */ public boolean isEncodingOnTheFly() { return this.encodingOnTheFly; @@ -311,8 +262,9 @@ public class PDFDocument { /** * Converts text to a byte array for writing to a PDF file. + * * @param text text to convert/encode - * @return byte[] the resulting byte array + * @return the resulting <code>byte</code> array */ public static byte[] encode(String text) { try { @@ -327,6 +279,7 @@ public class PDFDocument { * buffered to reduce the number of calls to the encoding converter so don't forget * to <code>flush()</code> the Writer after use or before writing directly to the * underlying OutputStream. + * * @param out the OutputStream to write to * @return the requested Writer */ @@ -339,7 +292,7 @@ public class PDFDocument { } /** - * set the producer of the document + * Sets the producer of the document. * * @param producer string indicating application producing the PDF */ @@ -348,16 +301,16 @@ public class PDFDocument { } /** - * Set the creation date of the document. + * Sets the creation date of the document. * * @param date Date to be stored as creation date in the PDF. */ public void setCreationDate(Date date) { - info.setCreationDate(date); + this.info.setCreationDate(date); } /** - * Set the creator of the document. + * Sets the creator of the document. * * @param creator string indicating application creating the document */ @@ -366,7 +319,7 @@ public class PDFDocument { } /** - * Set the filter map to use for filters in this document. + * Sets the filter map to use for filters in this document. * * @param map the map of filter lists for each stream type */ @@ -375,7 +328,7 @@ public class PDFDocument { } /** - * Get the filter map used for filters in this document. + * Returns the {@link PDFFilter}s map used for filters in this document. * * @return the map of filters being used */ @@ -384,36 +337,38 @@ public class PDFDocument { } /** - * Returns the PDFPages object associated with the root object. - * @return the PDFPages object + * Returns the {@link PDFPages} object associated with the root object. + * + * @return the {@link PDFPages} object */ public PDFPages getPages() { return this.pages; } /** - * Get the PDF root object. + * Get the {@link PDFRoot} object for this document. * - * @return the PDFRoot object + * @return the {@link PDFRoot} object */ public PDFRoot getRoot() { return this.root; } /** - * Get the pdf info object for this document. + * Get the {@link PDFInfo} object for this document. * - * @return the PDF Info object for this document + * @return the {@link PDFInfo} object */ public PDFInfo getInfo() { - return info; + return this.info; } /** - * Registers a PDFObject in this PDF document. The PDF is assigned a new - * object number. - * @param obj PDFObject to add - * @return PDFObject the PDFObject added (its object number set) + * Registers a {@link PDFObject} in this PDF document. + * The object is assigned a new object number. + * + * @param obj {@link PDFObject} to add + * @return the added {@link PDFObject} added (with its object number set) */ public PDFObject registerObject(PDFObject obj) { assignObjectNumber(obj); @@ -422,9 +377,10 @@ public class PDFDocument { } /** - * Assigns the PDFObject a object number and sets the parent of the - * PDFObject to this PDFDocument. - * @param obj PDFObject to assign a number to + * Assigns the {@link PDFObject} an object number, + * and sets the parent of the {@link PDFObject} to this document. + * + * @param obj {@link PDFObject} to assign a number to */ public void assignObjectNumber(PDFObject obj) { if (obj == null) { @@ -450,9 +406,10 @@ public class PDFDocument { } /** - * Adds an PDFObject to this document. The object must have a object number - * assigned. - * @param obj PDFObject to add + * Adds a {@link PDFObject} to this document. + * The object <em>MUST</em> have an object number assigned. + * + * @param obj {@link PDFObject} to add */ public void addObject(PDFObject obj) { if (obj == null) { @@ -521,6 +478,7 @@ public class PDFDocument { /** * Apply the encryption filter to a PDFStream if encryption is enabled. + * * @param stream PDFStream to encrypt */ public void applyEncryption(AbstractPDFStream stream) { @@ -531,13 +489,14 @@ public class PDFDocument { /** * Enables PDF encryption. + * * @param params The encryption parameters for the pdf file */ public void setEncryption(PDFEncryptionParams params) { getProfile().verifyEncryptionAllowed(); this.encryption = PDFEncryptionManager.newInstance(++this.objectcount, params); - if (encryption != null) { - PDFObject pdfObject = (PDFObject)encryption; + if (this.encryption != null) { + PDFObject pdfObject = (PDFObject)this.encryption; pdfObject.setDocument(this); addTrailerObject(pdfObject); } else { @@ -549,6 +508,7 @@ public class PDFDocument { /** * Indicates whether encryption is active for this PDF or not. + * * @return boolean True if encryption is active */ public boolean isEncryptionActive() { @@ -557,10 +517,11 @@ public class PDFDocument { /** * Returns the active Encryption object. + * * @return the Encryption object */ public PDFEncryption getEncryption() { - return encryption; + return this.encryption; } private Object findPDFObject(List list, PDFObject compare) { @@ -576,21 +537,23 @@ public class PDFDocument { /** * Looks through the registered functions to see if one that is equal to * a reference object exists + * * @param compare reference object * @return the function if it was found, null otherwise */ protected PDFFunction findFunction(PDFFunction compare) { - return (PDFFunction)findPDFObject(functions, compare); + return (PDFFunction)findPDFObject(this.functions, compare); } /** * Looks through the registered shadings to see if one that is equal to * a reference object exists + * * @param compare reference object * @return the shading if it was found, null otherwise */ protected PDFShading findShading(PDFShading compare) { - return (PDFShading)findPDFObject(shadings, compare); + return (PDFShading)findPDFObject(this.shadings, compare); } /** @@ -598,24 +561,27 @@ public class PDFDocument { * The problem with this is for tiling patterns the pattern * data stream is stored and may use up memory, usually this * would only be a small amount of data. + * * @param compare reference object * @return the shading if it was found, null otherwise */ protected PDFPattern findPattern(PDFPattern compare) { - return (PDFPattern)findPDFObject(patterns, compare); + return (PDFPattern)findPDFObject(this.patterns, compare); } /** * Finds a font. + * * @param fontname name of the font * @return PDFFont the requested font, null if it wasn't found */ protected PDFFont findFont(String fontname) { - return (PDFFont)fontMap.get(fontname); + return (PDFFont)this.fontMap.get(fontname); } /** * Finds a named destination. + * * @param compare reference object to use as search template * @return the link if found, null otherwise */ @@ -630,58 +596,64 @@ public class PDFDocument { /** * Finds a link. + * * @param compare reference object to use as search template * @return the link if found, null otherwise */ protected PDFLink findLink(PDFLink compare) { - return (PDFLink)findPDFObject(links, compare); + return (PDFLink)findPDFObject(this.links, compare); } /** * Finds a file spec. + * * @param compare reference object to use as search template * @return the file spec if found, null otherwise */ protected PDFFileSpec findFileSpec(PDFFileSpec compare) { - return (PDFFileSpec)findPDFObject(filespecs, compare); + return (PDFFileSpec)findPDFObject(this.filespecs, compare); } /** * Finds a goto remote. + * * @param compare reference object to use as search template * @return the goto remote if found, null otherwise */ protected PDFGoToRemote findGoToRemote(PDFGoToRemote compare) { - return (PDFGoToRemote)findPDFObject(gotoremotes, compare); + return (PDFGoToRemote)findPDFObject(this.gotoremotes, compare); } /** * Finds a goto. + * * @param compare reference object to use as search template * @return the goto if found, null otherwise */ protected PDFGoTo findGoTo(PDFGoTo compare) { - return (PDFGoTo)findPDFObject(gotos, compare); + return (PDFGoTo)findPDFObject(this.gotos, compare); } /** * Finds a launch. + * * @param compare reference object to use as search template * @return the launch if found, null otherwise */ protected PDFLaunch findLaunch(PDFLaunch compare) { - return (PDFLaunch) findPDFObject(launches, compare); + return (PDFLaunch) findPDFObject(this.launches, compare); } /** * Looks for an existing GState to use + * * @param wanted requested features * @param current currently active features - * @return PDFGState the GState if found, null otherwise + * @return the GState if found, null otherwise */ protected PDFGState findGState(PDFGState wanted, PDFGState current) { PDFGState poss; - Iterator iter = gstates.iterator(); + Iterator iter = this.gstates.iterator(); while (iter.hasNext()) { PDFGState avail = (PDFGState)iter.next(); poss = new PDFGState(); @@ -695,7 +667,7 @@ public class PDFDocument { } /** - * Get the PDF color space object. + * Returns the PDF color space object. * * @return the color space */ @@ -704,7 +676,7 @@ public class PDFDocument { } /** - * Get the color space. + * Returns the color space. * * @return the color space */ @@ -723,12 +695,12 @@ public class PDFDocument { } /** - * Get the font map for this document. + * Returns the font map for this document. * * @return the map of fonts used in this document */ public Map getFontMap() { - return fontMap; + return this.fontMap; } /** @@ -741,7 +713,7 @@ public class PDFDocument { protected InputStream resolveURI(String uri) throws java.io.FileNotFoundException { try { - /**@todo Temporary hack to compile, improve later */ + /* TODO: Temporary hack to compile, improve later */ return new java.net.URL(uri).openStream(); } catch (Exception e) { throw new java.io.FileNotFoundException( @@ -757,8 +729,7 @@ public class PDFDocument { * @deprecated Use getXObject instead (so forms are treated in the same way) */ public PDFImageXObject getImage(String key) { - PDFImageXObject xObject = (PDFImageXObject)xObjectsMap.get(key); - return xObject; + return (PDFImageXObject)this.xObjectsMap.get(key); } /** @@ -768,8 +739,7 @@ public class PDFDocument { * @return the PDFXObject for the key if found */ public PDFXObject getXObject(String key) { - PDFXObject xObject = (PDFXObject)xObjectsMap.get(key); - return xObject; + return (PDFXObject)this.xObjectsMap.get(key); } /** @@ -778,7 +748,7 @@ public class PDFDocument { * @return the PDFDests object (which represents the /Dests entry). */ public PDFDests getDests() { - return dests; + return this.dests; } /** @@ -787,7 +757,7 @@ public class PDFDocument { */ public void addDestination(PDFDestination destination) { if (this.destinations == null) { - this.destinations = new java.util.ArrayList(); + this.destinations = new ArrayList(); } this.destinations.add(destination); } @@ -799,7 +769,7 @@ public class PDFDocument { */ public List getDestinationList() { if (hasDestinations()) { - return destinations; + return this.destinations; } else { return Collections.EMPTY_LIST; } @@ -818,7 +788,7 @@ public class PDFDocument { * Add an image to the PDF document. * This adds an image to the PDF objects. * If an image with the same key already exists it will return the - * old PDFXObject. + * old {@link PDFXObject}. * * @param res the PDF resource context to add to, may be null * @param img the PDF image to add @@ -827,7 +797,7 @@ public class PDFDocument { public PDFImageXObject addImage(PDFResourceContext res, PDFImage img) { // check if already created String key = img.getKey(); - PDFImageXObject xObject = (PDFImageXObject)xObjectsMap.get(key); + PDFImageXObject xObject = (PDFImageXObject)this.xObjectsMap.get(key); if (xObject != null) { if (res != null) { res.getPDFResources().addXObject(xObject); @@ -852,7 +822,7 @@ public class PDFDocument { * Add a form XObject to the PDF document. * This adds a Form XObject to the PDF objects. * If a Form XObject with the same key already exists it will return the - * old PDFFormXObject. + * old {@link PDFFormXObject}. * * @param res the PDF resource context to add to, may be null * @param cont the PDF Stream contents of the Form XObject @@ -896,19 +866,19 @@ public class PDFDocument { * @return the PDF Outline root object */ public PDFOutline getOutlineRoot() { - if (outlineRoot != null) { - return outlineRoot; + if (this.outlineRoot != null) { + return this.outlineRoot; } - outlineRoot = new PDFOutline(null, null, true); - assignObjectNumber(outlineRoot); - addTrailerObject(outlineRoot); - root.setRootOutline(outlineRoot); - return outlineRoot; + this.outlineRoot = new PDFOutline(null, null, true); + assignObjectNumber(this.outlineRoot); + addTrailerObject(this.outlineRoot); + this.root.setRootOutline(this.outlineRoot); + return this.outlineRoot; } /** - * get the /Resources object for the document + * Get the /Resources object for the document * * @return the /Resources object */ @@ -919,16 +889,18 @@ public class PDFDocument { /** * Ensure there is room in the locations xref for the number of * objects that have been created. + * @param objidx the object's index + * @param position the position */ private void setLocation(int objidx, int position) { - while (location.size() <= objidx) { - location.add(LOCATION_PLACEHOLDER); + while (this.location.size() <= objidx) { + this.location.add(LOCATION_PLACEHOLDER); } - location.set(objidx, new Integer(position)); + this.location.set(objidx, new Integer(position)); } /** - * write the entire document out + * Writes out the entire document * * @param stream the OutputStream to output the document to * @throws IOException if there is an exception writing to the output stream @@ -1009,23 +981,23 @@ public class PDFDocument { } /** - * write the trailer + * Write the trailer * * @param stream the OutputStream to write the trailer to * @throws IOException if there is an exception writing to the output stream */ public void outputTrailer(OutputStream stream) throws IOException { if (hasDestinations()) { - Collections.sort(destinations, new DestinationComparator()); - dests = getFactory().makeDests(destinations); + Collections.sort(this.destinations, new DestinationComparator()); + this.dests = getFactory().makeDests(this.destinations); if (this.root.getNames() == null) { this.root.setNames(getFactory().makeNames()); } this.root.getNames().setDests(dests); } output(stream); - for (int count = 0; count < trailerObjects.size(); count++) { - PDFObject o = (PDFObject)trailerObjects.get(count); + for (int count = 0; count < this.trailerObjects.size(); count++) { + PDFObject o = (PDFObject)this.trailerObjects.get(count); this.location.set( o.getObjectNumber() - 1, new Integer(this.position)); @@ -1036,39 +1008,36 @@ public class PDFDocument { this.position += outputXref(stream); /* construct the trailer */ - String pdf = - "trailer\n" - + "<<\n" - + "/Size " - + (this.objectcount + 1) - + "\n" - + "/Root " - + this.root.referencePDF() - + "\n" - + "/Info " - + this.info.referencePDF() - + "\n"; - if (this.encryption != null) { - pdf += this.encryption.getTrailerEntry(); + StringBuffer pdf = new StringBuffer(128); + pdf.append("trailer\n<<\n/Size ") + .append(this.objectcount + 1) + .append("\n/Root ") + .append(this.root.referencePDF()) + .append("\n/Info ") + .append(this.info.referencePDF()) + .append('\n'); + + if (this.isEncryptionActive()) { + pdf.append(this.encryption.getTrailerEntry()); } else { - pdf += getIDEntry(); + pdf.append(this.getIDEntry()); } - pdf += "\n" - + ">>\n" - + "startxref\n" - + this.xref - + "\n" - + "%%EOF\n"; + + pdf.append("\n>>\nstartxref\n") + .append(this.xref) + .append("\n%%EOF\n"); /* write the trailer */ - stream.write(encode(pdf)); + stream.write(encode(pdf.toString())); } /** - * write the xref table + * Write the xref table * * @param stream the OutputStream to write the xref table to * @return the number of characters written + * @throws IOException in case of an error writing the result to + * the parameter stream */ private int outputXref(OutputStream stream) throws IOException { @@ -1077,18 +1046,20 @@ public class PDFDocument { /* construct initial part of xref */ StringBuffer pdf = new StringBuffer(128); - pdf.append( - "xref\n0 " + (this.objectcount + 1) + "\n0000000000 65535 f \n"); + pdf.append("xref\n0 "); + pdf.append(this.objectcount + 1); + pdf.append("\n0000000000 65535 f \n"); + String s, loc; for (int count = 0; count < this.location.size(); count++) { - String x = this.location.get(count).toString(); + final String padding = "0000000000"; + s = this.location.get(count).toString(); /* contruct xref entry for object */ - String padding = "0000000000"; - String loc = padding.substring(x.length()) + x; + loc = padding.substring(s.length()) + s; /* append to xref table */ - pdf = pdf.append(loc + " 00000 n \n"); + pdf = pdf.append(loc).append(" 00000 n \n"); } /* write the xref table and return the character length */ diff --git a/src/java/org/apache/fop/pdf/PDFPaintingState.java b/src/java/org/apache/fop/pdf/PDFPaintingState.java new file mode 100644 index 000000000..11dfc635a --- /dev/null +++ b/src/java/org/apache/fop/pdf/PDFPaintingState.java @@ -0,0 +1,229 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.pdf; + +import java.awt.Paint; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.geom.GeneralPath; +import java.util.Iterator; + +import org.apache.fop.util.AbstractPaintingState; + +/** + * This keeps information about the current painting state when writing to pdf. + * It allows for creating new graphics states with the q operator. + * This class is only used to store the information about the state + * the caller needs to handle the actual pdf operators. + * + * When setting the state for pdf there are three possible ways of + * handling the situation. + * The values can be set to override previous or default values. + * A new state can be added and then the values set. + * The current state can be popped and values will return to a + * previous state then the necessary values can be overridden. + * The current transform behaves differently to other values as the + * matrix is combined with the current resolved value. + * It is impossible to optimise the result without analysing the all + * the possible combinations after completing. + */ +public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState { + + private static final long serialVersionUID = 5384726143906371279L; + + /** + * PDF State for storing graphics state. + */ + public PDFPaintingState() { + } + + /** + * Set the current paint. + * This checks if the paint will change and then sets the current paint. + * + * @param p the new paint + * @return true if the new paint changes the current paint + */ + public boolean setPaint(Paint p) { + Paint paint = ((PDFData)getData()).paint; + if (paint == null) { + if (p != null) { + ((PDFData)getData()).paint = p; + return true; + } + } else if (!paint.equals(p)) { + ((PDFData)getData()).paint = p; + return true; + } + return false; + } + + /** + * Check if the clip will change the current state. + * A clip is assumed to be used in a situation where it will add + * to any clip in the current or parent states. + * A clip cannot be cleared, this can only be achieved by going to + * a parent level with the correct clip. + * If the clip is different then it may start a new state so that + * it can return to the previous clip. + * + * @param cl the clip shape to check + * @return true if the clip will change the current clip. + */ + public boolean checkClip(Shape cl) { + Shape clip = ((PDFData)getData()).clip; + if (clip == null) { + if (cl != null) { + return true; + } + } else if (!new Area(clip).equals(new Area(cl))) { + return true; + } + //TODO check for clips that are larger than the current + return false; + } + + /** + * Set the current clip. + * This either sets a new clip or sets the clip to the intersect of + * the old clip and the new clip. + * + * @param cl the new clip in the current state + */ + public void setClip(Shape cl) { + Shape clip = ((PDFData)getData()).clip; + if (clip != null) { + Area newClip = new Area(clip); + newClip.intersect(new Area(cl)); + ((PDFData)getData()).clip = new GeneralPath(newClip); + } else { + ((PDFData)getData()).clip = cl; + } + } + + /** + * Get the current stack level. + * + * @return the current stack level + */ + public int getStackLevel() { + return getStateStack().size(); + } + + /** + * Get the graphics state. + * This gets the combination of all graphic states for + * the current context. + * This is the graphic state set with the gs operator not + * the other graphic state changes. + * + * @return the calculated ExtGState in the current context + */ + public PDFGState getGState() { + PDFGState defaultState = PDFGState.DEFAULT; + + PDFGState state; + PDFGState newState = new PDFGState(); + newState.addValues(defaultState); + for (Iterator it = getStateStack().iterator(); it.hasNext();) { + PDFData data = (PDFData)it.next(); + state = data.gstate; + if (state != null) { + newState.addValues(state); + } + } + if (((PDFData)getData()).gstate != null) { + newState.addValues(((PDFData)getData()).gstate); + } + return newState; + } + + /** {@inheritDoc} */ + protected AbstractData instantiateData() { + return new PDFData(); + } + + /** {@inheritDoc} */ + protected AbstractPaintingState instantiate() { + return new PDFPaintingState(); + } + + /** + * Push the current state onto the stack. + * This call should be used when the q operator is used + * so that the state is known when popped. + */ + public void save() { + AbstractData data = getData(); + AbstractData copy = (AbstractData)data.clone(); + data.clearTransform(); + getStateStack().add(copy); + } + + private class PDFData extends org.apache.fop.util.AbstractPaintingState.AbstractData { + + private static final long serialVersionUID = 3527950647293177764L; + + private Paint paint = null; + private Paint backPaint = null; + private int lineCap = 0; + private int lineJoin = 0; + private float miterLimit = 0; + private boolean text = false; + private int dashOffset = 0; + private Shape clip = null; + private PDFGState gstate = null; + + /** {@inheritDoc} */ + public Object clone() { + PDFData obj = (PDFData)super.clone(); + obj.paint = this.paint; + obj.backPaint = this.paint; + obj.lineCap = this.lineCap; + obj.lineJoin = this.lineJoin; + obj.miterLimit = this.miterLimit; + obj.text = this.text; + obj.dashOffset = this.dashOffset; + obj.clip = this.clip; + obj.gstate = this.gstate; + return obj; + } + + /** {@inheritDoc} */ + public String toString() { + return super.toString() + + ", paint=" + paint + + ", backPaint=" + backPaint + + ", lineCap=" + lineCap + + ", miterLimit=" + miterLimit + + ", text=" + text + + ", dashOffset=" + dashOffset + + ", clip=" + clip + + ", gstate=" + gstate; + } + + /** {@inheritDoc} */ + protected AbstractData instantiate() { + return new PDFData(); + } + } + +} + diff --git a/src/java/org/apache/fop/pdf/PDFState.java b/src/java/org/apache/fop/pdf/PDFState.java deleted file mode 100644 index 2e9bd6074..000000000 --- a/src/java/org/apache/fop/pdf/PDFState.java +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.pdf; - -import java.io.Serializable; -import java.util.List; -import java.util.Iterator; - -import java.awt.Color; -import java.awt.Paint; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.GeneralPath; - -/** - * This keeps information about the current state when writing to pdf. - * It allows for creating new graphics states with the q operator. - * This class is only used to store the information about the state - * the caller needs to handle the actual pdf operators. - * - * When setting the state for pdf there are three possible ways of - * handling the situation. - * The values can be set to override previous or default values. - * A new state can be added and then the values set. - * The current state can be popped and values will return to a - * previous state then the necessary values can be overridden. - * The current transform behaves differently to other values as the - * matrix is combined with the current resolved value. - * It is impossible to optimise the result without analysing the all - * the possible combinations after completing. - */ -public class PDFState { - - private Data data = new Data(); - - private List stateStack = new java.util.ArrayList(); - - /** - * PDF State for storing graphics state. - */ - public PDFState() { - - } - - /** - * Push the current state onto the stack. - * This call should be used when the q operator is used - * so that the state is known when popped. - */ - public void push() { - Data copy; - try { - copy = (Data)getData().clone(); - getData().resetTransform(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e.getMessage()); - } - stateStack.add(copy); - } - - /** - * @return the currently valid state - */ - public Data getData() { - return data; - } - - /** - * Pop the state from the stack and set current values to popped state. - * This should be called when a Q operator is used so - * the state is restored to the correct values. - * @return the restored state, null if the stack is empty - */ - public Data pop() { - if (getStackLevel() > 0) { - Data popped = (Data)stateStack.remove(stateStack.size() - 1); - - data = popped; - return popped; - } else { - return null; - } - } - - /** - * Get the current stack level. - * - * @return the current stack level - */ - public int getStackLevel() { - return stateStack.size(); - } - - /** - * Restore the state to a particular level. - * this can be used to restore to a known level without making - * multiple pop calls. - * - * @param stack the level to restore to - */ - /* - public void restoreLevel(int stack) { - int pos = stack; - while (stateStack.size() > pos + 1) { - stateStack.remove(stateStack.size() - 1); - } - if (stateStack.size() > pos) { - pop(); - } - }*/ - - /** - * Set the current line dash. - * Check if setting the line dash to the given values - * will make a change and then set the state to the new values. - * - * @param array the line dash array - * @param offset the line dash start offset - * @return true if the line dash has changed - */ - /* - public boolean setLineDash(int[] array, int offset) { - return false; - }*/ - - /** - * Set the current line width. - * @param width the line width in points - * @return true if the line width has changed - */ - public boolean setLineWidth(float width) { - if (getData().lineWidth != width) { - getData().lineWidth = width; - return true; - } else { - return false; - } - } - - /** - * Set the current color. - * Check if the new color is a change and then set the current color. - * - * @param col the color to set - * @return true if the color has changed - */ - public boolean setColor(Color col) { - if (!col.equals(getData().color)) { - getData().color = col; - return true; - } else { - return false; - } - } - - /** - * Set the current background color. - * Check if the background color will change and then set the new color. - * - * @param col the new background color - * @return true if the background color has changed - */ - public boolean setBackColor(Color col) { - if (!col.equals(getData().backcolor)) { - getData().backcolor = col; - return true; - } else { - return false; - } - } - - /** - * Set the current paint. - * This checks if the paint will change and then sets the current paint. - * - * @param p the new paint - * @return true if the new paint changes the current paint - */ - public boolean setPaint(Paint p) { - if (getData().paint == null) { - if (p != null) { - getData().paint = p; - return true; - } - } else if (!data.paint.equals(p)) { - getData().paint = p; - return true; - } - return false; - } - - /** - * Check if the clip will change the current state. - * A clip is assumed to be used in a situation where it will add - * to any clip in the current or parent states. - * A clip cannot be cleared, this can only be achieved by going to - * a parent level with the correct clip. - * If the clip is different then it may start a new state so that - * it can return to the previous clip. - * - * @param cl the clip shape to check - * @return true if the clip will change the current clip. - */ - public boolean checkClip(Shape cl) { - if (getData().clip == null) { - if (cl != null) { - return true; - } - } else if (!new Area(getData().clip).equals(new Area(cl))) { - return true; - } - //TODO check for clips that are larger than the current - return false; - } - - /** - * Set the current clip. - * This either sets a new clip or sets the clip to the intersect of - * the old clip and the new clip. - * - * @param cl the new clip in the current state - */ - public void setClip(Shape cl) { - if (getData().clip != null) { - Area newClip = new Area(getData().clip); - newClip.intersect(new Area(cl)); - getData().clip = new GeneralPath(newClip); - } else { - getData().clip = cl; - } - } - - /** - * Check the current transform. - * The transform for the current state is the combination of all - * transforms in the current state. The parameter is compared - * against this current transform. - * - * @param tf the transform the check against - * @return true if the new transform is different then the current transform - */ - public boolean checkTransform(AffineTransform tf) { - return !tf.equals(getData().transform); - } - - /** - * Set a new transform. - * This transform is appended to the transform of - * the current graphic state. - * - * @param tf the transform to concatonate to the current level transform - * @deprecated This method name is misleading. Use concatenate(AffineTransform) instead! - */ - public void setTransform(AffineTransform tf) { - concatenate(tf); - } - - /** - * Concatenates the given AffineTransform to the current one. - * @param tf the transform to concatenate to the current level transform - */ - public void concatenate(AffineTransform tf) { - getData().concatenate(tf); - } - - /** - * Get the current transform. - * This gets the combination of all transforms in the - * current state. - * - * @return the calculate combined transform for the current state - */ - public AffineTransform getTransform() { - AffineTransform tf; - AffineTransform at = new AffineTransform(); - for (Iterator iter = stateStack.iterator(); iter.hasNext();) { - Data d = (Data)iter.next(); - tf = d.transform; - at.concatenate(tf); - } - at.concatenate(getData().transform); - return at; - } - - /** - * Get a copy of the base transform for the page. Used to translate - * IPP/BPP values into X,Y positions when positioning is "fixed". - * - * @return the base transform, or null if the state stack is empty - */ - public AffineTransform getBaseTransform() { - if (stateStack.size() == 0) { - return null; - } else { - Data baseData = (Data) stateStack.get(0); - return (AffineTransform) baseData.transform.clone(); - } - } - - /** - * Get the graphics state. - * This gets the combination of all graphic states for - * the current context. - * This is the graphic state set with the gs operator not - * the other graphic state changes. - * - * @return the calculated ExtGState in the current context - */ - public PDFGState getGState() { - PDFGState defaultState = PDFGState.DEFAULT; - - PDFGState state; - PDFGState newstate = new PDFGState(); - newstate.addValues(defaultState); - for (Iterator iter = stateStack.iterator(); iter.hasNext();) { - Data d = (Data)iter.next(); - state = d.gstate; - if (state != null) { - newstate.addValues(state); - } - } - if (getData().gstate != null) { - newstate.addValues(getData().gstate); - } - - return newstate; - } - - public class Data implements Cloneable, Serializable { - - public Color color = Color.black; - public Color backcolor = Color.black; - public Paint paint = null; - public Paint backPaint = null; - public int lineCap = 0; - public int lineJoin = 0; - public float lineWidth = 1; - public float miterLimit = 0; - public boolean text = false; - public int dashOffset = 0; - public int[] dashArray = new int[0]; - public AffineTransform transform = new AffineTransform(); - public float fontSize = 0; - public String fontName = ""; - public Shape clip = null; - public PDFGState gstate = null; - - - /** {@inheritDoc} */ - public Object clone() throws CloneNotSupportedException { - Data obj = new Data(); - obj.color = this.color; - obj.backcolor = this.backcolor; - obj.paint = this.paint; - obj.backPaint = this.paint; - obj.lineCap = this.lineCap; - obj.lineJoin = this.lineJoin; - obj.lineWidth = this.lineWidth; - obj.miterLimit = this.miterLimit; - obj.text = this.text; - obj.dashOffset = this.dashOffset; - obj.dashArray = this.dashArray; - obj.transform = new AffineTransform(this.transform); - obj.fontSize = this.fontSize; - obj.fontName = this.fontName; - obj.clip = this.clip; - obj.gstate = this.gstate; - return obj; - } - - /** - * Get the current Transform. - */ - public AffineTransform getTransform() { - return transform; - } - - public void resetTransform() { - transform = new AffineTransform(); - } - - /** - * Concatenate the given AffineTransform with the current thus creating - * a new viewport. Note that all concatenation operations are logged - * so they can be replayed if necessary (ex. for block-containers with - * "fixed" positioning. - * @param at Transformation to perform - */ - public void concatenate(AffineTransform at) { - transform.concatenate(at); - } - - /** {@inheritDoc} */ - public String toString() { - return super.toString() + ", " + this.transform; - } - } -} - diff --git a/src/java/org/apache/fop/pdf/package.html b/src/java/org/apache/fop/pdf/package.html index e86318adc..383f78da1 100644 --- a/src/java/org/apache/fop/pdf/package.html +++ b/src/java/org/apache/fop/pdf/package.html @@ -1,3 +1,20 @@ +<!-- + 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.html 643433 2008-04-01 15:08:24Z acumiskey $ --> <HTML> <TITLE>org.apache.fop.pdf Package</TITLE> <BODY> diff --git a/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java b/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java index fb62e653d..731f0bae2 100644 --- a/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java +++ b/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java @@ -21,9 +21,7 @@ package org.apache.fop.render; // Java import java.awt.Dimension; -import java.awt.Graphics2D; import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; import java.io.IOException; import org.w3c.dom.Document; @@ -37,7 +35,11 @@ import org.apache.batik.gvt.GraphicsNode; import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; import org.apache.xmlgraphics.util.QName; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.events.EventBroadcaster; import org.apache.fop.fo.extensions.ExtensionElementMapping; +import org.apache.fop.image.loader.batik.BatikUtil; +import org.apache.fop.image.loader.batik.Graphics2DImagePainterImpl; import org.apache.fop.render.RendererContext.RendererContextWrapper; import org.apache.fop.svg.SVGEventProducer; import org.apache.fop.svg.SVGUserAgent; @@ -54,6 +56,9 @@ public abstract class AbstractGenericSVGHandler implements XMLHandler, RendererC protected static final QName CONVERSION_MODE = new QName( ExtensionElementMapping.URI, null, "conversion-mode"); + /** "bitmap" value for the "conversion-mode" extension attribute. */ + protected static final String BITMAP = "bitmap"; + /** {@inheritDoc} */ public void handleXML(RendererContext context, Document doc, String ns) throws Exception { @@ -64,65 +69,101 @@ public abstract class AbstractGenericSVGHandler implements XMLHandler, RendererC } /** - * Render the SVG document. - * @param context the renderer context - * @param doc the SVG document - * @throws IOException In case of an I/O error while painting the image + * Creates a graphics 2D image painter implementation + * + * @param root the batik graphics node root + * @param ctx the batik bridge context + * @param imageSize the image size + * @return a new graphics 2D image painter implementation */ - protected void renderSVGDocument(final RendererContext context, - final Document doc) throws IOException { - updateRendererContext(context); - final RendererContextWrapper wrappedContext = RendererContext.wrapRendererContext(context); - int x = wrappedContext.getCurrentXPosition(); - int y = wrappedContext.getCurrentYPosition(); + protected Graphics2DImagePainter createGraphics2DImagePainter( + GraphicsNode root, BridgeContext ctx, Dimension imageSize) { + return new Graphics2DImagePainterImpl(root, ctx, imageSize); + } - //Prepare - SVGUserAgent ua = new SVGUserAgent( - context.getUserAgent(), - new AffineTransform()); + /** + * Builds the GVT root + * + * @param rendererContext the renderer context + * @param ctx the batik bridge context + * @param doc the document + * @return a built GVT root tree + */ + protected GraphicsNode buildGraphicsNode( + FOUserAgent userAgent, BridgeContext ctx, Document doc) { GVTBuilder builder = new GVTBuilder(); - final BridgeContext ctx = new BridgeContext(ua); - - //Build the GVT tree final GraphicsNode root; try { root = builder.build(ctx, doc); } catch (Exception e) { - SVGEventProducer eventProducer = SVGEventProducer.Provider.get( - context.getUserAgent().getEventBroadcaster()); - eventProducer.svgNotBuilt(this, e, getDocumentURI(doc)); - return; + EventBroadcaster eventBroadcaster + = userAgent.getEventBroadcaster(); + SVGEventProducer eventProducer = SVGEventProducer.Provider.get(eventBroadcaster); + final String uri = getDocumentURI(doc); + eventProducer.svgNotBuilt(this, e, uri); + return null; } + return root; + } - //Create the painter - Graphics2DImagePainter painter = new Graphics2DImagePainter() { + /** + * Returns the image size + * @param wrappedContext renderer context wrapper + * + * @return the image size + */ + protected Dimension getImageSize(RendererContextWrapper wrappedContext) { + final int width = wrappedContext.getWidth(); + final int height = wrappedContext.getHeight(); + return new Dimension(width, height); + } - public void paint(Graphics2D g2d, Rectangle2D area) { - // If no viewbox is defined in the svg file, a viewbox of 100x100 is - // assumed, as defined in SVGUserAgent.getViewportSize() - float iw = (float) ctx.getDocumentSize().getWidth(); - float ih = (float) ctx.getDocumentSize().getHeight(); - float w = (float) area.getWidth(); - float h = (float) area.getHeight(); - g2d.scale(w / iw, h / ih); + /** + * Render the SVG document. + * + * @param rendererContext the renderer context + * @param doc the SVG document + * @throws IOException In case of an I/O error while painting the image + */ + protected void renderSVGDocument(final RendererContext rendererContext, + final Document doc) throws IOException { + updateRendererContext(rendererContext); + + //Prepare + FOUserAgent userAgent = rendererContext.getUserAgent(); + SVGUserAgent svgUserAgent = new SVGUserAgent(userAgent, new AffineTransform()); + + //Create Batik BridgeContext + final BridgeContext bridgeContext = new BridgeContext(svgUserAgent); - root.paint(g2d); - } + //Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine) + //to it. + Document clonedDoc = BatikUtil.cloneSVGDocument(doc); - public Dimension getImageSize() { - return new Dimension(wrappedContext.getWidth(), wrappedContext.getHeight()); - } + //Build the GVT tree + final GraphicsNode root = buildGraphicsNode(userAgent, bridgeContext, clonedDoc); - }; + // Create Graphics2DImagePainter + final RendererContextWrapper wrappedContext = RendererContext.wrapRendererContext( + rendererContext); + Dimension imageSize = getImageSize(wrappedContext); + final Graphics2DImagePainter painter = createGraphics2DImagePainter( + root, bridgeContext, imageSize); //Let the painter paint the SVG on the Graphics2D instance - Graphics2DAdapter adapter = context.getRenderer().getGraphics2DAdapter(); - adapter.paintImage(painter, context, - x, y, wrappedContext.getWidth(), wrappedContext.getHeight()); + Graphics2DAdapter g2dAdapter = rendererContext.getRenderer().getGraphics2DAdapter(); + + //Paint the image + final int x = wrappedContext.getCurrentXPosition(); + final int y = wrappedContext.getCurrentYPosition(); + final int width = wrappedContext.getWidth(); + final int height = wrappedContext.getHeight(); + g2dAdapter.paintImage(painter, rendererContext, x, y, width, height); } /** * Gets the document URI from a Document instance if possible. + * * @param doc the Document * @return the URI or null */ @@ -138,6 +179,7 @@ public abstract class AbstractGenericSVGHandler implements XMLHandler, RendererC /** * Override this method to update the renderer context if it needs special settings for * certain conditions. + * * @param context the renderer context */ protected void updateRendererContext(RendererContext context) { diff --git a/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java b/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java index 5861fb042..ee18dff0d 100644 --- a/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java +++ b/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java @@ -54,8 +54,8 @@ public abstract class AbstractGraphics2DAdapter implements Graphics2DAdapter { protected BufferedImage paintToBufferedImage( org.apache.xmlgraphics.java2d.Graphics2DImagePainter painter, RendererContextWrapper context, int resolution, boolean gray, boolean withAlpha) { - int bmw = (int)Math.ceil(UnitConv.mpt2px(context.getWidth(), resolution)); - int bmh = (int)Math.ceil(UnitConv.mpt2px(context.getHeight(), resolution)); + int bmw = mpt2px(context.getWidth(), resolution); + int bmh = mpt2px(context.getHeight(), resolution); BufferedImage bi; if (gray) { if (withAlpha) { @@ -102,6 +102,17 @@ public abstract class AbstractGraphics2DAdapter implements Graphics2DAdapter { return bi; } + /** + * Converts millipoints to pixels + * + * @param unit the unit to convert in mpts + * @param resolution the target resolution + * @return the converted unit in pixels + */ + protected int mpt2px(int unit, int resolution) { + return (int)Math.ceil(UnitConv.mpt2px(unit, resolution)); + } + private static BufferedImage createGrayBufferedImageWithAlpha(int width, int height) { BufferedImage bi; boolean alphaPremultiplied = true; diff --git a/src/java/org/apache/fop/render/AbstractImageHandlerRegistry.java b/src/java/org/apache/fop/render/AbstractImageHandlerRegistry.java new file mode 100644 index 000000000..4196a1b19 --- /dev/null +++ b/src/java/org/apache/fop/render/AbstractImageHandlerRegistry.java @@ -0,0 +1,209 @@ +/* + * 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; + +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.xmlgraphics.image.loader.Image; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.util.Service; + +/** + * This class holds references to various image handlers used by the renderers. It also + * supports automatic discovery of additional handlers available through + * the class path. + */ +public abstract class AbstractImageHandlerRegistry { + + /** the logger */ + private static Log log = LogFactory.getLog(AbstractImageHandlerRegistry.class); + + private static final Comparator HANDLER_COMPARATOR = new Comparator() { + public int compare(Object o1, Object o2) { + ImageHandlerBase h1 = (ImageHandlerBase)o1; + ImageHandlerBase h2 = (ImageHandlerBase)o2; + return h1.getPriority() - h2.getPriority(); + } + }; + + /** Map containing image handlers for various MIME types */ + private final Map/*<Class, ImageHandler>*/ handlers + = new java.util.HashMap/*<Class, ImageHandler>*/(); + + /** List containing the same handlers as above but ordered by priority */ + private final List/*<ImageHandler>*/ handlerList + = new java.util.LinkedList/*<ImageHandler>*/(); + + /** Sorted Set of registered handlers */ + private ImageFlavor[] supportedFlavors = new ImageFlavor[0]; + + private int handlerRegistrations; + private int lastSync; + + /** + * Default constructor. + */ + public AbstractImageHandlerRegistry() { + discoverHandlers(); + } + + /** + * Add an ImageHandler. The handler itself is inspected to find out what it supports. + * @param classname the fully qualified class name + */ + public void addHandler(String classname) { + try { + ImageHandlerBase handlerInstance + = (ImageHandlerBase)Class.forName(classname).newInstance(); + addHandler(handlerInstance); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Could not find " + + classname); + } catch (InstantiationException e) { + throw new IllegalArgumentException("Could not instantiate " + + classname); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException("Could not access " + + classname); + } catch (ClassCastException e) { + throw new IllegalArgumentException(classname + + " is not an " + + getHandlerClass().getName()); + } + } + + /** + * Add an image handler. The handler itself is inspected to find out what it supports. + * @param handler the ImageHandler instance + */ + public synchronized void addHandler(ImageHandlerBase handler) { + this.handlers.put(handler.getSupportedImageClass(), handler); + + //Sorted insert + ListIterator iter = this.handlerList.listIterator(); + while (iter.hasNext()) { + ImageHandlerBase h = (ImageHandlerBase)iter.next(); + if (getHandlerComparator().compare(handler, h) < 0) { + iter.previous(); + break; + } + } + iter.add(handler); + this.handlerRegistrations++; + } + + /** + * Returns an ImageHandler which handles an specific image type given the MIME type + * of the image. + * @param img the Image to be handled + * @return the ImageHandler responsible for handling the image or null if none is available + */ + public ImageHandlerBase getHandler(Image img) { + return getHandler(img.getClass()); + } + + /** + * Returns an ImageHandler which handles an specific image type given the MIME type + * of the image. + * @param imageClass the Image subclass for which to get a handler + * @return the ImageHandler responsible for handling the image or null if none is available + */ + public synchronized ImageHandlerBase getHandler(Class imageClass) { + ImageHandlerBase handler = null; + Class cl = imageClass; + while (cl != null) { + handler = (ImageHandlerBase)handlers.get(cl); + if (handler != null) { + break; + } + cl = cl.getSuperclass(); + } + return handler; + } + + /** + * Returns the ordered array of supported image flavors. + * @return the array of image flavors + */ + public synchronized ImageFlavor[] getSupportedFlavors() { + if (this.lastSync != this.handlerRegistrations) { + //Extract all ImageFlavors into a single array + List flavors = new java.util.ArrayList(); + Iterator iter = this.handlerList.iterator(); + while (iter.hasNext()) { + ImageFlavor[] f = ((ImageHandlerBase)iter.next()).getSupportedImageFlavors(); + for (int i = 0; i < f.length; i++) { + flavors.add(f[i]); + } + } + this.supportedFlavors = (ImageFlavor[])flavors.toArray(new ImageFlavor[flavors.size()]); + this.lastSync = this.handlerRegistrations; + } + return this.supportedFlavors; + } + + /** + * Discovers ImageHandler implementations through the classpath and dynamically + * registers them. + */ + private void discoverHandlers() { + // add mappings from available services + Class imageHandlerClass = getHandlerClass(); + Iterator providers = Service.providers(imageHandlerClass); + if (providers != null) { + while (providers.hasNext()) { + ImageHandlerBase handler = (ImageHandlerBase)providers.next(); + try { + if (log.isDebugEnabled()) { + log.debug("Dynamically adding ImageHandler: " + + handler.getClass().getName()); + } + addHandler(handler); + } catch (IllegalArgumentException e) { + log.error("Error while adding ImageHandler", e); + } + + } + } + } + + /** + * Returns the ImageHandler comparator + * + * @return the ImageHandler comparator + */ + public Comparator getHandlerComparator() { + return HANDLER_COMPARATOR; + } + + /** + * Returns the ImageHandler implementing class + * + * @return the ImageHandler implementing class + */ + public abstract Class getHandlerClass(); +} diff --git a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java index c57a9d566..2e04f2d85 100644 --- a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java +++ b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java @@ -26,13 +26,7 @@ import java.awt.geom.Rectangle2D; import java.util.List; import java.util.Map; -import org.w3c.dom.Document; - import org.apache.batik.parser.AWTTransformProducer; - -import org.apache.xmlgraphics.image.loader.ImageSize; -import org.apache.xmlgraphics.util.QName; - import org.apache.fop.area.Area; import org.apache.fop.area.Block; import org.apache.fop.area.BlockViewport; @@ -48,7 +42,10 @@ import org.apache.fop.fo.Constants; import org.apache.fop.fo.extensions.ExtensionElementMapping; import org.apache.fop.fonts.FontMetrics; import org.apache.fop.traits.BorderProps; +import org.apache.xmlgraphics.image.loader.ImageSize; +import org.apache.xmlgraphics.util.QName; import org.apache.xmlgraphics.util.UnitConv; +import org.w3c.dom.Document; /** * Abstract base class for renderers like PDF and PostScript where many painting operations @@ -270,6 +267,11 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { drawBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd); } + private static final int BEFORE = 0; + private static final int END = 1; + private static final int AFTER = 2; + private static final int START = 3; + /** * Draws borders. * @param borderRect the border rectangle @@ -280,45 +282,46 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { */ protected void drawBorders(Rectangle2D.Float borderRect, BorderProps bpsBefore, BorderProps bpsAfter, BorderProps bpsStart, BorderProps bpsEnd) { + //TODO generalize each of the four conditions into using a parameterized drawBorder() + boolean[] border = new boolean[] { + (bpsBefore != null), (bpsEnd != null), + (bpsAfter != null), (bpsStart != null)}; float startx = borderRect.x; float starty = borderRect.y; float width = borderRect.width; float height = borderRect.height; - boolean[] b = new boolean[] { - (bpsBefore != null), (bpsEnd != null), - (bpsAfter != null), (bpsStart != null)}; - if (!b[0] && !b[1] && !b[2] && !b[3]) { - return; - } - float[] bw = new float[] { - (b[0] ? bpsBefore.width / 1000f : 0.0f), - (b[1] ? bpsEnd.width / 1000f : 0.0f), - (b[2] ? bpsAfter.width / 1000f : 0.0f), - (b[3] ? bpsStart.width / 1000f : 0.0f)}; + float[] borderWidth = new float[] { + (border[BEFORE] ? bpsBefore.width / 1000f : 0.0f), + (border[END] ? bpsEnd.width / 1000f : 0.0f), + (border[AFTER] ? bpsAfter.width / 1000f : 0.0f), + (border[START] ? bpsStart.width / 1000f : 0.0f)}; float[] clipw = new float[] { BorderProps.getClippedWidth(bpsBefore) / 1000f, BorderProps.getClippedWidth(bpsEnd) / 1000f, BorderProps.getClippedWidth(bpsAfter) / 1000f, BorderProps.getClippedWidth(bpsStart) / 1000f}; - starty += clipw[0]; - height -= clipw[0]; - height -= clipw[2]; - startx += clipw[3]; - width -= clipw[3]; - width -= clipw[1]; + starty += clipw[BEFORE]; + height -= clipw[BEFORE]; + height -= clipw[AFTER]; + startx += clipw[START]; + width -= clipw[START]; + width -= clipw[END]; boolean[] slant = new boolean[] { - (b[3] && b[0]), (b[0] && b[1]), (b[1] && b[2]), (b[2] && b[3])}; + (border[START] && border[BEFORE]), + (border[BEFORE] && border[END]), + (border[END] && border[AFTER]), + (border[AFTER] && border[START])}; if (bpsBefore != null) { endTextObject(); float sx1 = startx; - float sx2 = (slant[0] ? sx1 + bw[3] - clipw[3] : sx1); + float sx2 = (slant[BEFORE] ? sx1 + borderWidth[START] - clipw[START] : sx1); float ex1 = startx + width; - float ex2 = (slant[1] ? ex1 - bw[1] + clipw[1] : ex1); - float outery = starty - clipw[0]; - float clipy = outery + clipw[0]; - float innery = outery + bw[0]; + float ex2 = (slant[END] ? ex1 - borderWidth[END] + clipw[END] : ex1); + float outery = starty - clipw[BEFORE]; + float clipy = outery + clipw[BEFORE]; + float innery = outery + borderWidth[BEFORE]; saveGraphicsState(); moveTo(sx1, clipy); @@ -326,10 +329,10 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { float ex1a = ex1; if (bpsBefore.mode == BorderProps.COLLAPSE_OUTER) { if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) { - sx1a -= clipw[3]; + sx1a -= clipw[START]; } if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) { - ex1a += clipw[1]; + ex1a += clipw[END]; } lineTo(sx1a, outery); lineTo(ex1a, outery); @@ -347,12 +350,12 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { endTextObject(); float sy1 = starty; - float sy2 = (slant[1] ? sy1 + bw[0] - clipw[0] : sy1); + float sy2 = (slant[END] ? sy1 + borderWidth[BEFORE] - clipw[BEFORE] : sy1); float ey1 = starty + height; - float ey2 = (slant[2] ? ey1 - bw[2] + clipw[2] : ey1); - float outerx = startx + width + clipw[1]; - float clipx = outerx - clipw[1]; - float innerx = outerx - bw[1]; + float ey2 = (slant[AFTER] ? ey1 - borderWidth[AFTER] + clipw[AFTER] : ey1); + float outerx = startx + width + clipw[END]; + float clipx = outerx - clipw[END]; + float innerx = outerx - borderWidth[END]; saveGraphicsState(); moveTo(clipx, sy1); @@ -360,10 +363,10 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { float ey1a = ey1; if (bpsEnd.mode == BorderProps.COLLAPSE_OUTER) { if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) { - sy1a -= clipw[0]; + sy1a -= clipw[BEFORE]; } if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) { - ey1a += clipw[2]; + ey1a += clipw[AFTER]; } lineTo(outerx, sy1a); lineTo(outerx, ey1a); @@ -380,12 +383,12 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { endTextObject(); float sx1 = startx; - float sx2 = (slant[3] ? sx1 + bw[3] - clipw[3] : sx1); + float sx2 = (slant[START] ? sx1 + borderWidth[AFTER] - clipw[AFTER] : sx1); float ex1 = startx + width; - float ex2 = (slant[2] ? ex1 - bw[1] + clipw[1] : ex1); - float outery = starty + height + clipw[2]; - float clipy = outery - clipw[2]; - float innery = outery - bw[2]; + float ex2 = (slant[AFTER] ? ex1 - borderWidth[END] + clipw[END] : ex1); + float outery = starty + height + clipw[AFTER]; + float clipy = outery - clipw[AFTER]; + float innery = outery - borderWidth[AFTER]; saveGraphicsState(); moveTo(ex1, clipy); @@ -393,10 +396,10 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { float ex1a = ex1; if (bpsAfter.mode == BorderProps.COLLAPSE_OUTER) { if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) { - sx1a -= clipw[3]; + sx1a -= clipw[START]; } if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) { - ex1a += clipw[1]; + ex1a += clipw[END]; } lineTo(ex1a, outery); lineTo(sx1a, outery); @@ -413,12 +416,12 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { endTextObject(); float sy1 = starty; - float sy2 = (slant[0] ? sy1 + bw[0] - clipw[0] : sy1); + float sy2 = (slant[BEFORE] ? sy1 + borderWidth[BEFORE] - clipw[BEFORE] : sy1); float ey1 = sy1 + height; - float ey2 = (slant[3] ? ey1 - bw[2] + clipw[2] : ey1); - float outerx = startx - clipw[3]; - float clipx = outerx + clipw[3]; - float innerx = outerx + bw[3]; + float ey2 = (slant[START] ? ey1 - borderWidth[AFTER] + clipw[AFTER] : ey1); + float outerx = startx - clipw[START]; + float clipx = outerx + clipw[START]; + float innerx = outerx + borderWidth[START]; saveGraphicsState(); moveTo(clipx, ey1); @@ -426,10 +429,10 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { float ey1a = ey1; if (bpsStart.mode == BorderProps.COLLAPSE_OUTER) { if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) { - sy1a -= clipw[0]; + sy1a -= clipw[BEFORE]; } if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) { - ey1a += clipw[2]; + ey1a += clipw[AFTER]; } lineTo(outerx, ey1a); lineTo(outerx, sy1a); @@ -451,10 +454,6 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { * rendered */ protected void renderInlineAreaBackAndBorders(InlineArea area) { - float x = currentIPPosition / 1000f; - float y = (currentBPPosition + area.getOffset()) / 1000f; - float width = area.getIPD() / 1000f; - float height = area.getBPD() / 1000f; float borderPaddingStart = area.getBorderAndPaddingWidthStart() / 1000f; float borderPaddingBefore = area.getBorderAndPaddingWidthBefore() / 1000f; float bpwidth = borderPaddingStart @@ -462,12 +461,15 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { float bpheight = borderPaddingBefore + (area.getBorderAndPaddingWidthAfter() / 1000f); + float height = area.getBPD() / 1000f; if (height != 0.0f || bpheight != 0.0f && bpwidth != 0.0f) { + float x = currentIPPosition / 1000f; + float y = (currentBPPosition + area.getOffset()) / 1000f; + float width = area.getIPD() / 1000f; drawBackAndBorders(area, x, y - borderPaddingBefore , width + bpwidth , height + bpheight); } - } /** Constant for the fox:transform extension attribute */ @@ -483,26 +485,24 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { int saveBP = currentBPPosition; CTM ctm = bv.getCTM(); - int borderPaddingStart = bv.getBorderAndPaddingWidthStart(); int borderPaddingBefore = bv.getBorderAndPaddingWidthBefore(); - //This is the content-rect - float width = bv.getIPD() / 1000f; - float height = bv.getBPD() / 1000f; - if (bv.getPositioning() == Block.ABSOLUTE - || bv.getPositioning() == Block.FIXED) { + int positioning = bv.getPositioning(); + if (positioning == Block.ABSOLUTE || positioning == Block.FIXED) { //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) { + if (positioning == Block.FIXED) { breakOutList = breakOutOfStateStack(); } AffineTransform positionTransform = new AffineTransform(); positionTransform.translate(bv.getXOffset(), bv.getYOffset()); + int borderPaddingStart = bv.getBorderAndPaddingWidthStart(); + //"left/"top" (bv.getX/YOffset()) specify the position of the content rectangle positionTransform.translate(-borderPaddingStart, -borderPaddingBefore); @@ -514,39 +514,62 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { positionTransform.concatenate(freeTransform); } - saveGraphicsState(); //Viewport position - concatenateTransformationMatrix(UnitConv.mptToPt(positionTransform)); + if (!positionTransform.isIdentity()) { + establishTransformationMatrix(positionTransform); + } + + //This is the content-rect + float width = bv.getIPD() / 1000f; + float height = bv.getBPD() / 1000f; //Background and borders - float bpwidth = (borderPaddingStart + bv.getBorderAndPaddingWidthEnd()) / 1000f; - float bpheight = (borderPaddingBefore + bv.getBorderAndPaddingWidthAfter()) / 1000f; - drawBackAndBorders(bv, 0, 0, width + bpwidth, height + bpheight); + float borderPaddingWidth + = (borderPaddingStart + bv.getBorderAndPaddingWidthEnd()) / 1000f; + float borderPaddingHeight + = (borderPaddingBefore + bv.getBorderAndPaddingWidthAfter()) / 1000f; + drawBackAndBorders(bv, 0, 0, width + borderPaddingWidth, height + borderPaddingHeight); //Shift to content rectangle after border painting AffineTransform contentRectTransform = new AffineTransform(); contentRectTransform.translate(borderPaddingStart, borderPaddingBefore); - concatenateTransformationMatrix(UnitConv.mptToPt(contentRectTransform)); + + if (!contentRectTransform.isIdentity()) { + establishTransformationMatrix(contentRectTransform); + } //Clipping if (bv.getClip()) { clipRect(0f, 0f, width, height); } - saveGraphicsState(); //Set up coordinate system for content rectangle AffineTransform contentTransform = ctm.toAffineTransform(); - concatenateTransformationMatrix(UnitConv.mptToPt(contentTransform)); + if (!contentTransform.isIdentity()) { + establishTransformationMatrix(contentTransform); + } currentIPPosition = 0; currentBPPosition = 0; renderBlocks(bv, children); - restoreGraphicsState(); - restoreGraphicsState(); + if (!contentTransform.isIdentity()) { + restoreGraphicsState(); + } + + if (!contentRectTransform.isIdentity()) { + restoreGraphicsState(); + } + + if (!positionTransform.isIdentity()) { + restoreGraphicsState(); + } - if (breakOutList != null) { - restoreStateStackAfterBreakOut(breakOutList); + //For FIXED, we need to restore break out now we are done + if (positioning == Block.FIXED) { + if (breakOutList != null) { + restoreStateStackAfterBreakOut(breakOutList); + } } currentIPPosition = saveIP; @@ -599,8 +622,7 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { at.translate(0, block.getSpaceBefore()); if (!at.isIdentity()) { - saveGraphicsState(); - concatenateTransformationMatrix(UnitConv.mptToPt(at)); + establishTransformationMatrix(at); } currentIPPosition = 0; @@ -632,8 +654,7 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { at.translate(currentIPPosition, currentBPPosition); if (!at.isIdentity()) { - saveGraphicsState(); - concatenateTransformationMatrix(UnitConv.mptToPt(at)); + establishTransformationMatrix(at); } currentIPPosition = 0; @@ -845,4 +866,16 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { renderDocument(doc, ns, pos, fo.getForeignAttributes()); } + /** + * Establishes a new coordinate system with the given transformation matrix. + * The current graphics state is saved and the new coordinate system is concatenated. + * @param block + * + * @param at the transformation matrix + */ + protected void establishTransformationMatrix(AffineTransform at) { + saveGraphicsState(); + concatenateTransformationMatrix(UnitConv.mptToPt(at)); + } + } diff --git a/src/java/org/apache/fop/render/AbstractRenderer.java b/src/java/org/apache/fop/render/AbstractRenderer.java index 2be9150b0..943c8c9da 100644 --- a/src/java/org/apache/fop/render/AbstractRenderer.java +++ b/src/java/org/apache/fop/render/AbstractRenderer.java @@ -29,11 +29,8 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -import org.w3c.dom.Document; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.area.Area; @@ -69,6 +66,7 @@ import org.apache.fop.area.inline.WordArea; import org.apache.fop.events.ResourceEventProducer; import org.apache.fop.fo.Constants; import org.apache.fop.fonts.FontInfo; +import org.w3c.dom.Document; /** * Abstract base class for all renderers. The Abstract renderer does all the @@ -505,7 +503,7 @@ public abstract class AbstractRenderer */ protected void renderBlocks(Block parent, List blocks) { int saveIP = currentIPPosition; - int saveBP = currentBPPosition; +// int saveBP = currentBPPosition; // Calculate the position of the content rectangle. if (parent != null && !parent.getTraitAsBoolean(Trait.IS_VIEWPORT_AREA)) { diff --git a/src/java/org/apache/fop/render/ImageHandler.java b/src/java/org/apache/fop/render/ImageHandler.java index 42ae5fd49..ec5f576aa 100644 --- a/src/java/org/apache/fop/render/ImageHandler.java +++ b/src/java/org/apache/fop/render/ImageHandler.java @@ -23,26 +23,11 @@ import java.awt.Rectangle; import java.io.IOException; import org.apache.xmlgraphics.image.loader.Image; -import org.apache.xmlgraphics.image.loader.ImageFlavor; /** - * This interface is used for handling all sorts of image types for PDF output. + * This interface is a service provider interface for image handlers. */ -public interface ImageHandler { - - /** - * Returns the priority for this image handler. A lower value means higher priority. This - * information is used to build the ordered/prioritized list of supported ImageFlavors. - * The built-in handlers use priorities between 100 and 999. - * @return a positive integer (>0) indicating the priority - */ - int getPriority(); - - /** - * Returns the {@link ImageFlavor}s supported by this instance - * @return the supported image flavors - */ - ImageFlavor[] getSupportedImageFlavors(); +public interface ImageHandler extends ImageHandlerBase { /** * Indicates whether the image handler is compatible with the indicated target represented @@ -58,12 +43,6 @@ public interface ImageHandler { boolean isCompatible(RenderingContext targetContext, Image image); /** - * Returns the {@link Image} subclass supported by this instance. - * @return the Image type - */ - Class getSupportedImageClass(); - - /** * Handles the given {@link Image} instance painting it at the indicated position in the * output format being generated. * @param context the rendering context diff --git a/src/java/org/apache/fop/render/ImageHandlerBase.java b/src/java/org/apache/fop/render/ImageHandlerBase.java new file mode 100644 index 000000000..f07c89671 --- /dev/null +++ b/src/java/org/apache/fop/render/ImageHandlerBase.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; + +import org.apache.xmlgraphics.image.loader.ImageFlavor; + +/** + * This interface is a service provider base interface for image handlers. It only contains + * methods necessary for registration and is extended by sub-interfaces with the actual + * image handling contract. + */ +public interface ImageHandlerBase { + + /** + * Returns the priority for this image handler. A lower value means higher priority. This + * information is used to build the ordered/prioritized list of supported ImageFlavors. + * The built-in handlers use priorities between 100 and 999. + * @return a positive integer (>0) indicating the priority + */ + int getPriority(); + + /** + * Returns the {@link ImageFlavor}s supported by this instance + * @return the supported image flavors + */ + ImageFlavor[] getSupportedImageFlavors(); + + /** + * Returns the {@link Class} subclass supported by this instance. + * @return the image Class type + */ + Class getSupportedImageClass(); +} diff --git a/src/java/org/apache/fop/render/PrintRenderer.java b/src/java/org/apache/fop/render/PrintRenderer.java index 818e31568..76f727e84 100644 --- a/src/java/org/apache/fop/render/PrintRenderer.java +++ b/src/java/org/apache/fop/render/PrintRenderer.java @@ -24,8 +24,6 @@ import java.awt.geom.Rectangle2D; import java.util.List; import java.util.Map; -import org.w3c.dom.Document; - import org.apache.fop.apps.FOPException; import org.apache.fop.area.Area; import org.apache.fop.area.Trait; @@ -37,6 +35,7 @@ import org.apache.fop.fonts.FontManager; import org.apache.fop.fonts.FontResolver; import org.apache.fop.fonts.FontTriplet; import org.apache.fop.fonts.base14.Base14FontCollection; +import org.w3c.dom.Document; /** Abstract base class of "Print" type renderers. */ public abstract class PrintRenderer extends AbstractRenderer { @@ -109,6 +108,14 @@ public abstract class PrintRenderer extends AbstractRenderer { } /** + * Instantiates a RendererContext for an image + * @return a newly created RendererContext. + */ + protected RendererContext instantiateRendererContext() { + return new RendererContext(this, getMimeType()); + } + + /** * Creates a RendererContext for an image. * @param x the x coordinate (in millipoints) * @param y the y coordinate (in millipoints) @@ -119,8 +126,7 @@ public abstract class PrintRenderer extends AbstractRenderer { */ protected RendererContext createRendererContext(int x, int y, int width, int height, Map foreignAttributes) { - RendererContext context; - context = new RendererContext(this, getMimeType()); + RendererContext context = instantiateRendererContext(); context.setUserAgent(userAgent); context.setProperty(RendererContextConstants.WIDTH, diff --git a/src/java/org/apache/fop/render/RendererContext.java b/src/java/org/apache/fop/render/RendererContext.java index 595bdd7c2..ac885a44b 100644 --- a/src/java/org/apache/fop/render/RendererContext.java +++ b/src/java/org/apache/fop/render/RendererContext.java @@ -20,9 +20,12 @@ package org.apache.fop.render; //Java +import java.util.Iterator; import java.util.Map; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fo.extensions.ExtensionElementMapping; +import org.apache.xmlgraphics.util.QName; /** * The Render Context for external handlers. This provides a rendering context @@ -30,21 +33,28 @@ import org.apache.fop.apps.FOUserAgent; * render target. */ public class RendererContext { + /** conversion-mode extension attribute */ + protected static final QName CONVERSION_MODE = new QName( + ExtensionElementMapping.URI, null, "conversion-mode"); - private String mime; - private AbstractRenderer renderer; + /** "bitmap" value for the "conversion-mode" extension attribute. */ + protected static final String BITMAP = "bitmap"; + + private final String mime; + private final AbstractRenderer renderer; private FOUserAgent userAgent; - private Map props = new java.util.HashMap(); + + private final Map/*<String,Object>*/ props = new java.util.HashMap/*<String,Object>*/(); /** - * Contructor for this class. It takes a MIME type as parameter. + * Constructor for this class. It takes a MIME type as parameter. * - * @param renderer The current renderer - * @param m The MIME type of the output that's generated. + * @param renderer the current renderer + * @param mime the MIME type of the output that's generated. */ - public RendererContext(AbstractRenderer renderer, String m) { + public RendererContext(AbstractRenderer renderer, String mime) { this.renderer = renderer; - this.mime = m; + this.mime = mime; } /** @@ -112,6 +122,19 @@ public class RendererContext { return wrapper; } + /** {@inheritDoc} **/ + public String toString() { + StringBuffer stringBuffer = new StringBuffer("RendererContext{\n"); + Iterator it = props.keySet().iterator(); + while (it.hasNext()) { + String key = (String)it.next(); + Object value = props.get(key); + stringBuffer.append("\t" + key + "=" + value + "\n"); + } + stringBuffer.append("}"); + return stringBuffer.toString(); + } + /** * Base class for a wrapper around RendererContext to access its properties in a type-safe, * renderer-specific way. @@ -158,6 +181,19 @@ public class RendererContext { public Map getForeignAttributes() { return (Map)context.getProperty(RendererContextConstants.FOREIGN_ATTRIBUTES); } + + /** {@inheritDoc} */ + public String toString() { + return "RendererContextWrapper{" + + "userAgent=" + getUserAgent() + + "x=" + getCurrentXPosition() + + "y=" + getCurrentYPosition() + + "width=" + getWidth() + + "height=" + getHeight() + + "foreignAttributes=" + getForeignAttributes() + + "}"; + + } } } diff --git a/src/java/org/apache/fop/render/afp/AFPEventProducer.xml b/src/java/org/apache/fop/render/afp/AFPEventProducer.xml index b0eeeb202..23bd9a182 100644 --- a/src/java/org/apache/fop/render/afp/AFPEventProducer.xml +++ b/src/java/org/apache/fop/render/afp/AFPEventProducer.xml @@ -1,3 +1 @@ -<?xml version="1.0" encoding="UTF-8"?><catalogue xml:lang="en"> - <message key="org.apache.fop.render.afp.AFPEventProducer.warnDefaultFontSetup">No AFP fonts configured. Using default setup.</message> -</catalogue> +<?xml version="1.0" encoding="UTF-8"?><catalogue xml:lang="en"/> diff --git a/src/java/org/apache/fop/render/afp/AFPForeignAttributeReader.java b/src/java/org/apache/fop/render/afp/AFPForeignAttributeReader.java new file mode 100644 index 000000000..2b5077fe9 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPForeignAttributeReader.java @@ -0,0 +1,128 @@ +/* + * 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.io.File; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.afp.AFPResourceInfo; +import org.apache.fop.afp.AFPResourceLevel; +import org.apache.fop.render.afp.extensions.AFPElementMapping; +import org.apache.xmlgraphics.util.QName; + +/** + * Parses any AFP foreign attributes + */ +public class AFPForeignAttributeReader { + private static final Log log = LogFactory.getLog("org.apache.xmlgraphics.afp"); + + /** the resource-name attribute */ + public static final String RESOURCE_NAME = "afp:resource-name"; + + /** the resource-level attribute */ + public static final String RESOURCE_LEVEL = "afp:resource-level"; + + /** the resource-group-file attribute */ + public static final String RESOURCE_GROUP_FILE = "afp:resource-group-file"; + + /** + * Main constructor + */ + public AFPForeignAttributeReader() { + } + + /** + * Returns the resource information + * + * @param foreignAttributes the foreign attributes + * @return the resource information + */ + public AFPResourceInfo getResourceInfo(Map/*<QName, String>*/ foreignAttributes) { + AFPResourceInfo resourceInfo = new AFPResourceInfo(); + if (foreignAttributes != null && !foreignAttributes.isEmpty()) { + QName resourceNameKey = new QName(AFPElementMapping.NAMESPACE, RESOURCE_NAME); + String resourceName = (String)foreignAttributes.get(resourceNameKey); + if (resourceName != null) { + resourceInfo.setName(resourceName); + } + AFPResourceLevel level = getResourceLevel(foreignAttributes); + if (level != null) { + resourceInfo.setLevel(level); + } + } + return resourceInfo; + } + + /** + * Returns the resource level + * + * @param foreignAttributes the foreign attributes + * @return the resource level + */ + public AFPResourceLevel getResourceLevel(Map/*<QName, String>*/ foreignAttributes) { + AFPResourceLevel resourceLevel = null; + if (foreignAttributes != null && !foreignAttributes.isEmpty()) { + QName resourceLevelKey = new QName(AFPElementMapping.NAMESPACE, RESOURCE_LEVEL); + if (foreignAttributes.containsKey(resourceLevelKey)) { + String levelString = (String)foreignAttributes.get(resourceLevelKey); + resourceLevel = AFPResourceLevel.valueOf(levelString); + // if external get resource group file attributes + if (resourceLevel != null && resourceLevel.isExternal()) { + QName resourceGroupFileKey = new QName(AFPElementMapping.NAMESPACE, + RESOURCE_GROUP_FILE); + String resourceGroupFile + = (String)foreignAttributes.get(resourceGroupFileKey); + if (resourceGroupFile == null) { + String msg = RESOURCE_GROUP_FILE + " not specified"; + log.error(msg); + throw new UnsupportedOperationException(msg); + } + File resourceExternalGroupFile = new File(resourceGroupFile); + SecurityManager security = System.getSecurityManager(); + try { + if (security != null) { + security.checkWrite(resourceExternalGroupFile.getPath()); + } + } catch (SecurityException ex) { + String msg = "unable to gain write access to external resource file: " + + resourceGroupFile; + log.error(msg); + } + + try { + boolean exists = resourceExternalGroupFile.exists(); + if (exists) { + log.warn("overwriting external resource file: " + + resourceGroupFile); + } + resourceLevel.setExternalFilePath(resourceGroupFile); + } catch (SecurityException ex) { + String msg = "unable to gain read access to external resource file: " + + resourceGroupFile; + log.error(msg); + } + } + } + } + return resourceLevel; + } +} diff --git a/src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java b/src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java index 18ac4dbb6..becafda23 100644 --- a/src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java +++ b/src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java @@ -19,40 +19,87 @@ package org.apache.fop.render.afp; +import java.awt.Dimension; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.IOException; -import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; - +import org.apache.fop.afp.AFPGraphics2D; +import org.apache.fop.afp.AFPGraphicsObjectInfo; +import org.apache.fop.afp.AFPPaintingState; +import org.apache.fop.afp.AFPResourceManager; import org.apache.fop.render.AbstractGraphics2DAdapter; import org.apache.fop.render.RendererContext; +import org.apache.fop.render.RendererContext.RendererContextWrapper; +import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; /** * Graphics2DAdapter implementation for AFP. */ public class AFPGraphics2DAdapter extends AbstractGraphics2DAdapter { + private final AFPPaintingState paintingState; + /** * Main constructor + * + * @param paintingState the AFP painting state */ - public AFPGraphics2DAdapter() { + public AFPGraphics2DAdapter(AFPPaintingState paintingState) { + this.paintingState = paintingState; } /** {@inheritDoc} */ public void paintImage(Graphics2DImagePainter painter, - RendererContext context, + RendererContext rendererContext, int x, int y, int width, int height) throws IOException { - RendererContext.RendererContextWrapper wrappedContext - = new RendererContext.RendererContextWrapper(context); - AFPRenderer afp = (AFPRenderer)context.getRenderer(); - Boolean grayObj = (Boolean)context.getProperty(AFPRendererContextConstants.AFP_GRAYSCALE); - boolean gray = (grayObj != null ? grayObj.booleanValue() : false); - //Paint to a BufferedImage - int resolution = (int)Math.round(context.getUserAgent().getTargetResolution()); - BufferedImage bi = paintToBufferedImage(painter, wrappedContext, resolution, gray, false); + AFPRendererContext afpRendererContext = (AFPRendererContext)rendererContext; + AFPInfo afpInfo = afpRendererContext.getInfo(); + + final boolean textAsShapes = false; + AFPGraphics2D g2d = afpInfo.createGraphics2D(textAsShapes); + + paintingState.save(); + + //Fallback solution: Paint to a BufferedImage + if (afpInfo.paintAsBitmap()) { - afp.drawBufferedImage(bi, resolution, x, y, width, height); + // paint image + RendererContextWrapper rendererContextWrapper + = RendererContext.wrapRendererContext(rendererContext); + float targetResolution = rendererContext.getUserAgent().getTargetResolution(); + int resolution = Math.round(targetResolution); + boolean colorImages = afpInfo.isColorSupported(); + BufferedImage bufferedImage = paintToBufferedImage( + painter, rendererContextWrapper, resolution, !colorImages, false); + + // draw image + AffineTransform at = paintingState.getData().getTransform(); + at.translate(x, y); + g2d.drawImage(bufferedImage, at, null); + } else { + AFPGraphicsObjectInfo graphicsObjectInfo = new AFPGraphicsObjectInfo(); + graphicsObjectInfo.setPainter(painter); + graphicsObjectInfo.setGraphics2D(g2d); + + // get the 'width' and 'height' attributes of the SVG document + Dimension imageSize = painter.getImageSize(); + float imw = (float)imageSize.getWidth() / 1000f; + float imh = (float)imageSize.getHeight() / 1000f; + + Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh); + graphicsObjectInfo.setArea(area); + AFPResourceManager resourceManager = afpInfo.getResourceManager(); + resourceManager.createObject(graphicsObjectInfo); + } + + paintingState.restore(); } + /** {@inheritDoc} */ + protected int mpt2px(int unit, int resolution) { + return Math.round(paintingState.getUnitConverter().mpt2units(unit)); + } } diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandler.java b/src/java/org/apache/fop/render/afp/AFPImageHandler.java new file mode 100644 index 000000000..a6d2d613d --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPImageHandler.java @@ -0,0 +1,104 @@ +/* + * 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.Point; +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.util.Map; + +import org.apache.fop.afp.AFPDataObjectInfo; +import org.apache.fop.afp.AFPObjectAreaInfo; +import org.apache.fop.afp.AFPPaintingState; +import org.apache.fop.afp.AFPResourceInfo; +import org.apache.fop.afp.AFPUnitConverter; +import org.apache.fop.render.ImageHandlerBase; + +/** + * A base abstract AFP image handler + */ +public abstract class AFPImageHandler implements ImageHandlerBase { + private static final int X = 0; + private static final int Y = 1; + + /** foreign attribute reader */ + private final AFPForeignAttributeReader foreignAttributeReader + = new AFPForeignAttributeReader(); + + /** + * Generates an intermediate AFPDataObjectInfo that is later used to construct + * the appropriate data object in the AFP DataStream. + * + * @param rendererImageInfo the renderer image info + * @return a data object info object + * @throws IOException thrown if an I/O exception of some sort has occurred. + */ + public AFPDataObjectInfo generateDataObjectInfo( + AFPRendererImageInfo rendererImageInfo) throws IOException { + AFPDataObjectInfo dataObjectInfo = createDataObjectInfo(); + + // set resource information + Map foreignAttributes = rendererImageInfo.getForeignAttributes(); + AFPResourceInfo resourceInfo + = foreignAttributeReader.getResourceInfo(foreignAttributes); + resourceInfo.setUri(rendererImageInfo.getURI()); + dataObjectInfo.setResourceInfo(resourceInfo); + + // set object area + AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo(); + + Point origin = rendererImageInfo.getOrigin(); + Rectangle2D position = rendererImageInfo.getPosition(); + float srcX = origin.x + (float)position.getX(); + float srcY = origin.y + (float)position.getY(); + + AFPRendererContext rendererContext + = (AFPRendererContext)rendererImageInfo.getRendererContext(); + AFPInfo afpInfo = rendererContext.getInfo(); + AFPPaintingState paintingState = afpInfo.getPaintingState(); + AFPUnitConverter unitConv = paintingState.getUnitConverter(); + int[] coords = unitConv.mpts2units(new float[] {srcX, srcY}); + objectAreaInfo.setX(coords[X]); + objectAreaInfo.setY(coords[Y]); + + int width = Math.round(unitConv.mpt2units((float)position.getWidth())); + objectAreaInfo.setWidth(width); + + int height = Math.round(unitConv.mpt2units((float)position.getHeight())); + objectAreaInfo.setHeight(height); + + int resolution = paintingState.getResolution(); + objectAreaInfo.setHeightRes(resolution); + objectAreaInfo.setWidthRes(resolution); + + objectAreaInfo.setRotation(paintingState.getRotation()); + + dataObjectInfo.setObjectAreaInfo(objectAreaInfo); + + return dataObjectInfo; + } + + /** + * Creates the data object information object + * + * @return the data object information object + */ + protected abstract AFPDataObjectInfo createDataObjectInfo(); +} diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java new file mode 100644 index 000000000..0780e8a59 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.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$ */ + +package org.apache.fop.render.afp; + +import java.io.IOException; + +import org.apache.fop.afp.AFPDataObjectInfo; +import org.apache.fop.afp.AFPGraphics2D; +import org.apache.fop.afp.AFPGraphicsObjectInfo; +import org.apache.fop.afp.AFPPaintingState; +import org.apache.fop.afp.AFPResourceInfo; +import org.apache.fop.afp.AFPResourceLevel; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; +import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; +import org.apache.xmlgraphics.util.MimeConstants; + +/** + * PDFImageHandler implementation which handles Graphics2D images. + */ +public class AFPImageHandlerGraphics2D extends AFPImageHandler { + + private static final ImageFlavor[] FLAVORS = new ImageFlavor[] { + ImageFlavor.GRAPHICS2D + }; + + /** {@inheritDoc} */ + public AFPDataObjectInfo generateDataObjectInfo( + AFPRendererImageInfo rendererImageInfo) throws IOException { + + AFPRendererContext rendererContext + = (AFPRendererContext)rendererImageInfo.getRendererContext(); + AFPInfo afpInfo = rendererContext.getInfo(); + ImageGraphics2D imageG2D = (ImageGraphics2D)rendererImageInfo.getImage(); + Graphics2DImagePainter painter = imageG2D.getGraphics2DImagePainter(); + + if (afpInfo.paintAsBitmap()) { + int x = afpInfo.getX(); + int y = afpInfo.getY(); + int width = afpInfo.getWidth(); + int height = afpInfo.getHeight(); + AFPPaintingState paintingState = afpInfo.getPaintingState(); + AFPGraphics2DAdapter g2dAdapter = new AFPGraphics2DAdapter(paintingState); + g2dAdapter.paintImage(painter, rendererContext, x, y, width, height); + return null; + } else { + AFPGraphicsObjectInfo graphicsObjectInfo + = (AFPGraphicsObjectInfo)super.generateDataObjectInfo(rendererImageInfo); + + AFPResourceInfo resourceInfo = graphicsObjectInfo.getResourceInfo(); + //level not explicitly set/changed so default to inline for GOCA graphic objects + // (due to a bug in the IBM AFP Workbench Viewer (2.04.01.07), hard copy works just fine) + if (!resourceInfo.levelChanged()) { + resourceInfo.setLevel(new AFPResourceLevel(AFPResourceLevel.INLINE)); + } + + // set mime type (unsupported by MOD:CA registry) + graphicsObjectInfo.setMimeType(MimeConstants.MIME_AFP_GOCA); + + // set g2d + boolean textAsShapes = false; + + AFPGraphics2D g2d = afpInfo.createGraphics2D(textAsShapes); + + graphicsObjectInfo.setGraphics2D(g2d); + + // set painter + graphicsObjectInfo.setPainter(painter); + + return graphicsObjectInfo; + } + } + + /** {@inheritDoc} */ + public int getPriority() { + return 200; + } + + /** {@inheritDoc} */ + public Class getSupportedImageClass() { + return ImageGraphics2D.class; + } + + /** {@inheritDoc} */ + public ImageFlavor[] getSupportedImageFlavors() { + return FLAVORS; + } + + /** {@inheritDoc} */ + protected AFPDataObjectInfo createDataObjectInfo() { + return new AFPGraphicsObjectInfo(); + } +} diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerRawCCITTFax.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawCCITTFax.java new file mode 100644 index 000000000..3ac1d5696 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawCCITTFax.java @@ -0,0 +1,72 @@ +/* + * 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.io.IOException; + +import org.apache.fop.afp.AFPDataObjectInfo; +import org.apache.fop.afp.AFPImageObjectInfo; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; + +/** + * AFPImageHandler implementation which handles CCITT encoded images (CCITT fax group 3/4). + */ +public class AFPImageHandlerRawCCITTFax extends AbstractAFPImageHandlerRawStream { + + private static final ImageFlavor[] FLAVORS = new ImageFlavor[] { + ImageFlavor.RAW_CCITTFAX, + }; + + /** {@inheritDoc} */ + public AFPDataObjectInfo generateDataObjectInfo( + AFPRendererImageInfo rendererImageInfo) throws IOException { + AFPImageObjectInfo imageObjectInfo + = (AFPImageObjectInfo)super.generateDataObjectInfo(rendererImageInfo); + + ImageRawCCITTFax ccitt = (ImageRawCCITTFax) rendererImageInfo.getImage(); + int compression = ccitt.getCompression(); + imageObjectInfo.setCompression(compression); + + imageObjectInfo.setBitsPerPixel(1); + return imageObjectInfo; + } + + /** {@inheritDoc} */ + protected AFPDataObjectInfo createDataObjectInfo() { + return new AFPImageObjectInfo(); + } + + /** {@inheritDoc} */ + public int getPriority() { + return 400; + } + + /** {@inheritDoc} */ + public Class getSupportedImageClass() { + return ImageRawCCITTFax.class; + } + + /** {@inheritDoc} */ + public ImageFlavor[] getSupportedImageFlavors() { + return FLAVORS; + } + +} diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java new file mode 100644 index 000000000..ded9ec9d5 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.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; + +import org.apache.fop.afp.AFPDataObjectInfo; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.impl.ImageRawStream; + +/** + * AFPImageHandler implementation which handles raw stream images. + */ +public class AFPImageHandlerRawStream extends AbstractAFPImageHandlerRawStream { + + private static final ImageFlavor[] FLAVORS = new ImageFlavor[] { + ImageFlavor.RAW_JPEG, + ImageFlavor.RAW_EPS, + }; + + /** {@inheritDoc} */ + public int getPriority() { + return 200; + } + + /** {@inheritDoc} */ + public Class getSupportedImageClass() { + return ImageRawStream.class; + } + + /** {@inheritDoc} */ + public ImageFlavor[] getSupportedImageFlavors() { + return FLAVORS; + } + + /** {@inheritDoc} */ + protected AFPDataObjectInfo createDataObjectInfo() { + return new AFPDataObjectInfo(); + } +} diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerRegistry.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerRegistry.java new file mode 100644 index 000000000..59ca6cf38 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerRegistry.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; + +import org.apache.fop.render.AbstractImageHandlerRegistry; + +/** + * This class holds references to various image handlers used by the AFP renderer. It also + * supports automatic discovery of additional handlers available through + * the class path. + */ +public class AFPImageHandlerRegistry extends AbstractImageHandlerRegistry { + + /** + * Main constructor + */ + public AFPImageHandlerRegistry() { + } + + /** {@inheritDoc} */ + public Class getHandlerClass() { + return AFPImageHandler.class; + } + +} diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java new file mode 100644 index 000000000..28c942a08 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java @@ -0,0 +1,116 @@ +/* + * 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.image.RenderedImage; +import java.io.IOException; + +import org.apache.commons.io.output.ByteArrayOutputStream; +import org.apache.fop.afp.AFPDataObjectInfo; +import org.apache.fop.afp.AFPImageObjectInfo; +import org.apache.fop.afp.AFPObjectAreaInfo; +import org.apache.fop.afp.AFPPaintingState; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.impl.ImageRendered; +import org.apache.xmlgraphics.ps.ImageEncodingHelper; +import org.apache.xmlgraphics.util.MimeConstants; + +/** + * PDFImageHandler implementation which handles RenderedImage instances. + */ +public class AFPImageHandlerRenderedImage extends AFPImageHandler { + + private static final ImageFlavor[] FLAVORS = new ImageFlavor[] { + ImageFlavor.BUFFERED_IMAGE, + ImageFlavor.RENDERED_IMAGE + }; + + /** {@inheritDoc} */ + public AFPDataObjectInfo generateDataObjectInfo( + AFPRendererImageInfo rendererImageInfo) throws IOException { + AFPImageObjectInfo imageObjectInfo + = (AFPImageObjectInfo)super.generateDataObjectInfo(rendererImageInfo); + + AFPRendererContext rendererContext + = (AFPRendererContext)rendererImageInfo.getRendererContext(); + AFPInfo afpInfo = rendererContext.getInfo(); + AFPPaintingState paintingState = afpInfo.getPaintingState(); + int resolution = paintingState.getResolution(); + + imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS45); + imageObjectInfo.setDataHeightRes(resolution); + imageObjectInfo.setDataWidthRes(resolution); + + ImageRendered imageRendered = (ImageRendered) rendererImageInfo.img; + RenderedImage renderedImage = imageRendered.getRenderedImage(); + + int dataHeight = renderedImage.getHeight(); + imageObjectInfo.setDataHeight(dataHeight); + + int dataWidth = renderedImage.getWidth(); + imageObjectInfo.setDataWidth(dataWidth); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageEncodingHelper.encodeRenderedImageAsRGB(renderedImage, baos); + byte[] imageData = baos.toByteArray(); + + boolean colorImages = paintingState.isColorImages(); + imageObjectInfo.setColor(colorImages); + + // convert to grayscale + if (!colorImages) { + baos.reset(); + int bitsPerPixel = paintingState.getBitsPerPixel(); + imageObjectInfo.setBitsPerPixel(bitsPerPixel); + ImageEncodingHelper.encodeRGBAsGrayScale( + imageData, dataWidth, dataHeight, bitsPerPixel, baos); + imageData = baos.toByteArray(); + } + imageObjectInfo.setData(imageData); + + // set object area info + AFPObjectAreaInfo objectAreaInfo = imageObjectInfo.getObjectAreaInfo(); + objectAreaInfo.setWidthRes(resolution); + objectAreaInfo.setHeightRes(resolution); + + return imageObjectInfo; + } + + /** {@inheritDoc} */ + protected AFPDataObjectInfo createDataObjectInfo() { + return new AFPImageObjectInfo(); + } + + /** {@inheritDoc} */ + public int getPriority() { + return 300; + } + + /** {@inheritDoc} */ + public Class getSupportedImageClass() { + return ImageRendered.class; + } + + /** {@inheritDoc} */ + public ImageFlavor[] getSupportedImageFlavors() { + return FLAVORS; + } + +} diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerXML.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerXML.java new file mode 100644 index 000000000..7ea1a7a10 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerXML.java @@ -0,0 +1,77 @@ +/* + * 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.geom.Rectangle2D; +import java.io.IOException; +import java.util.Map; + +import org.apache.fop.afp.AFPDataObjectInfo; +import org.apache.fop.render.RendererContext; +import org.apache.fop.render.RendererContextConstants; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; +import org.w3c.dom.Document; + +/** + * PDFImageHandler implementation which handles XML-based images. + */ +public class AFPImageHandlerXML extends AFPImageHandler { + + private static final ImageFlavor[] FLAVORS = new ImageFlavor[] { + ImageFlavor.XML_DOM, + }; + + /** {@inheritDoc} */ + public AFPDataObjectInfo generateDataObjectInfo(AFPRendererImageInfo rendererImageInfo) + throws IOException { + RendererContext rendererContext = rendererImageInfo.getRendererContext(); + AFPRenderer renderer = (AFPRenderer)rendererContext.getRenderer(); + ImageXMLDOM imgXML = (ImageXMLDOM)rendererImageInfo.getImage(); + Document doc = imgXML.getDocument(); + String ns = imgXML.getRootNamespace(); + Map foreignAttributes = (Map)rendererContext.getProperty( + RendererContextConstants.FOREIGN_ATTRIBUTES); + Rectangle2D pos = rendererImageInfo.getPosition(); + renderer.renderDocument(doc, ns, pos, foreignAttributes); + return null; + } + + /** {@inheritDoc} */ + public int getPriority() { + return 400; + } + + /** {@inheritDoc} */ + public Class getSupportedImageClass() { + return ImageXMLDOM.class; + } + + /** {@inheritDoc} */ + public ImageFlavor[] getSupportedImageFlavors() { + return FLAVORS; + } + + /** {@inheritDoc} */ + protected AFPDataObjectInfo createDataObjectInfo() { + return null; + } + +} 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..fb1ec87a8 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPInfo.java @@ -0,0 +1,310 @@ +/* + * 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.afp.AFPGraphics2D; +import org.apache.fop.afp.AFPPaintingState; +import org.apache.fop.afp.AFPResourceInfo; +import org.apache.fop.afp.AFPResourceManager; +import org.apache.fop.fonts.FontInfo; + +/** + * AFP information structure for drawing the XML document. + */ +public final class AFPInfo { + /** see WIDTH */ + private int width; + + /** see HEIGHT */ + private int height; + + /** see XPOS */ + private int x; + + /** see YPOS */ + private int y; + + /** see HANDLER_CONFIGURATION */ + private Configuration handlerConfiguration; + + /** see AFP_FONT_INFO */ + private FontInfo fontInfo; + + /** See AFP_PAINTING_STATE */ + private AFPPaintingState paintingState; + + /** See AFP_RESOURCE_MANAGER */ + private AFPResourceManager resourceManager; + + /** See AFP_RESOURCE_INFO */ + private AFPResourceInfo resourceInfo; + + /** true if SVG should be rendered as a bitmap instead of natively */ + private boolean paintAsBitmap; + + /** + * 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; + } + + /** + * Returns the handler configuration + * + * @return the handler configuration + */ + public Configuration getHandlerConfiguration() { + return this.handlerConfiguration; + } + + /** + * Sets the handler configuration + * + * @param cfg the handler configuration + */ + public void setHandlerConfiguration(Configuration cfg) { + this.handlerConfiguration = cfg; + } + + /** + * Return the font info + * + * @return the font info + */ + public FontInfo getFontInfo() { + return this.fontInfo; + } + + /** + * Returns the current AFP state + * + * @return the current AFP state + */ + public AFPPaintingState getPaintingState() { + return this.paintingState; + } + + /** + * Returns the AFPResourceManager + * + * @return the AFPResourceManager + */ + public AFPResourceManager getResourceManager() { + return this.resourceManager; + } + + /** + * Returns true if supports color + * + * @return true if supports color + */ + public boolean isColorSupported() { + return getPaintingState().isColorImages(); + } + + /** + * Returns the current x position coordinate + * + * @return the current x position coordinate + */ + protected int getX() { + return x; + } + + /** + * Returns the current y position coordinate + * + * @return the current y position coordinate + */ + protected int getY() { + return y; + } + + /** + * Returns the resolution + * + * @return the resolution + */ + protected int getResolution() { + return getPaintingState().getResolution(); + } + + /** + * Returns the number of bits per pixel to use + * @return the number of bits per pixel to use + */ + protected int getBitsPerPixel() { + return getPaintingState().getBitsPerPixel(); + } + + /** + * Sets the current x position coordinate + * + * @param x the current x position coordinate + */ + protected void setX(int x) { + this.x = x; + } + + /** + * Sets the current y position coordinate + * + * @param y the current y position coordinate + */ + protected void setY(int y) { + this.y = y; + } + + /** + * Sets the current font info + * + * @param fontInfo the current font info + */ + protected void setFontInfo(FontInfo fontInfo) { + this.fontInfo = fontInfo; + } + + /** + * Sets the AFP state + * + * @param paintingState the AFP state + */ + public void setPaintingState(AFPPaintingState paintingState) { + this.paintingState = paintingState; + } + + /** + * Sets the AFPResourceManager + * + * @param resourceManager the AFPResourceManager + */ + public void setResourceManager(AFPResourceManager resourceManager) { + this.resourceManager = resourceManager; + } + + /** + * Sets true if SVG should be rendered as a bitmap instead of natively + * + * @param b boolean value + */ + public void setPaintAsBitmap(boolean b) { + this.paintAsBitmap = b; + } + + /** + * Returns true if SVG should be rendered as a bitmap instead of natively + * + * @return true if SVG should be rendered as a bitmap instead of natively + */ + public boolean paintAsBitmap() { + return this.paintAsBitmap; + } + + /** + * Returns true if text should be stroked when painted + * + * @return true if text should be stroked when painted + */ + public boolean strokeText() { + boolean strokeText = false; + if (handlerConfiguration != null) { + strokeText = handlerConfiguration.getChild("stroke-text", true).getValueAsBoolean(strokeText); + } + return strokeText; + } + + /** + * Sets the resource information + * + * @param resourceInfo the resource information + */ + public void setResourceInfo(AFPResourceInfo resourceInfo) { + this.resourceInfo = resourceInfo; + } + + /** + * Returns the resource information + * + * @return the resource information + */ + public AFPResourceInfo getResourceInfo() { + return resourceInfo; + } + + /** + * Creates an AFPGraphics2D implementation + * + * @param textAsShapes true when text is painted as shapes + * @return a newly created AFPGraphics2D + */ + public AFPGraphics2D createGraphics2D(boolean textAsShapes) { + AFPGraphics2D g2d = new AFPGraphics2D( + textAsShapes, paintingState, resourceManager, resourceInfo, fontInfo); + g2d.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext()); + return g2d; + } + + /** {@inheritDoc} */ + public String toString() { + return "AFPInfo{width=" + width + + ", height=" + height + + ", x=" + x + + ", y=" + y + + ", cfg=" + handlerConfiguration + + ", fontInfo=" + fontInfo + + ", resourceManager=" + resourceManager + + ", paintingState=" + paintingState + + ", paintAsBitmap=" + paintAsBitmap + + ", resourceInfo=" + resourceInfo + + "}"; + } + +}
\ 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 d5129f167..8035a9490 100644 --- a/src/java/org/apache/fop/render/afp/AFPRenderer.java +++ b/src/java/org/apache/fop/render/afp/AFPRenderer.java @@ -23,56 +23,46 @@ import java.awt.Color; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.RenderedImage; import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import org.apache.commons.io.IOUtils; -import org.apache.commons.io.output.ByteArrayOutputStream; - -import org.apache.xmlgraphics.image.codec.tiff.TIFFImage; -import org.apache.xmlgraphics.image.loader.ImageException; -import org.apache.xmlgraphics.image.loader.ImageFlavor; -import org.apache.xmlgraphics.image.loader.ImageInfo; -import org.apache.xmlgraphics.image.loader.ImageManager; -import org.apache.xmlgraphics.image.loader.ImageSessionContext; -import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; -import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; -import org.apache.xmlgraphics.image.loader.impl.ImageRendered; -import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; -import org.apache.xmlgraphics.image.loader.util.ImageUtil; -import org.apache.xmlgraphics.ps.ImageEncodingHelper; - +import org.apache.fop.afp.AFPBorderPainter; +import org.apache.fop.afp.AFPDataObjectInfo; +import org.apache.fop.afp.AFPEventProducer; +import org.apache.fop.afp.AFPPaintingState; +import org.apache.fop.afp.AFPRectanglePainter; +import org.apache.fop.afp.AFPResourceManager; +import org.apache.fop.afp.AFPTextDataInfo; +import org.apache.fop.afp.AFPUnitConverter; +import org.apache.fop.afp.BorderPaintingInfo; +import org.apache.fop.afp.DataStream; +import org.apache.fop.afp.RectanglePaintingInfo; +import org.apache.fop.afp.fonts.AFPFont; +import org.apache.fop.afp.fonts.AFPFontAttributes; +import org.apache.fop.afp.fonts.AFPFontCollection; +import org.apache.fop.afp.fonts.AFPPageFonts; +import org.apache.fop.afp.fonts.CharacterSet; +import org.apache.fop.afp.modca.PageObject; +import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; -import org.apache.fop.area.Block; -import org.apache.fop.area.BlockViewport; -import org.apache.fop.area.BodyRegion; import org.apache.fop.area.CTM; -import org.apache.fop.area.NormalFlow; +import org.apache.fop.area.LineArea; import org.apache.fop.area.OffDocumentItem; import org.apache.fop.area.PageViewport; -import org.apache.fop.area.RegionReference; -import org.apache.fop.area.RegionViewport; import org.apache.fop.area.Trait; import org.apache.fop.area.inline.Image; import org.apache.fop.area.inline.Leader; -import org.apache.fop.area.inline.SpaceArea; import org.apache.fop.area.inline.TextArea; -import org.apache.fop.area.inline.WordArea; import org.apache.fop.datatypes.URISpecification; import org.apache.fop.events.ResourceEventProducer; -import org.apache.fop.fo.Constants; import org.apache.fop.fo.extensions.ExtensionAttachment; import org.apache.fop.fonts.FontCollection; import org.apache.fop.fonts.FontInfo; @@ -82,13 +72,13 @@ import org.apache.fop.render.Graphics2DAdapter; import org.apache.fop.render.RendererContext; import org.apache.fop.render.afp.extensions.AFPElementMapping; import org.apache.fop.render.afp.extensions.AFPPageSetup; -import org.apache.fop.render.afp.fonts.AFPFont; -import org.apache.fop.render.afp.fonts.AFPFontCollection; -import org.apache.fop.render.afp.modca.AFPConstants; -import org.apache.fop.render.afp.modca.AFPDataStream; -import org.apache.fop.render.afp.modca.ImageObject; -import org.apache.fop.render.afp.modca.PageObject; -import org.apache.fop.util.ColorUtil; +import org.apache.xmlgraphics.image.loader.ImageException; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageManager; +import org.apache.xmlgraphics.image.loader.ImageSessionContext; +import org.apache.xmlgraphics.image.loader.util.ImageUtil; +import org.apache.xmlgraphics.ps.ImageEncodingHelper; /** * This is an implementation of a FOP Renderer that renders areas to AFP. @@ -139,140 +129,55 @@ import org.apache.fop.util.ColorUtil; * 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 - */ - private static final int DEFAULT_DPI_RESOLUTION = 240; - - /** - * The afp factor for calculating resolutions (e.g. 72000/240 = 300) - */ - private static final int DPI_CONVERSION_FACTOR = 72000; - - /** - * The afp data stream object responsible for generating afp data - */ - private AFPDataStream afpDataStream = null; + private static final int X = 0; + private static final int Y = 1; - /** - * The map of afp root extensions - */ - // UNUSED - // private HashMap rootExtensionMap = null; - /** - * The map of page segments - */ - private HashMap pageSegmentsMap = null; + /** the resource manager */ + private AFPResourceManager resourceManager; - /** - * The fonts on the current page - */ - private HashMap currentPageFonts = null; + /** the painting state */ + private final AFPPaintingState paintingState; - /** - * The current color object - */ - private Color currentColor = null; + /** unit converter */ + private final AFPUnitConverter unitConv; - /** - * The page font number counter, used to determine the next font reference - */ - private int pageFontCounter = 0; + /** the line painter */ + private AFPBorderPainter borderPainter; - /** - * The current font family - */ - // UNUSED - // private String currentFontFamily = ""; - /** - * The current font size - */ - private int currentFontSize = 0; + /** the map of page segments */ + private final Map/*<String,String>*/pageSegmentMap + = new java.util.HashMap/*<String,String>*/(); - /** - * The Options to be set on the AFPRenderer - */ - // UNUSED - // private Map afpOptions = null; - /** - * The page width - */ - private int pageWidth = 0; + /** the map of saved incomplete pages */ + private final Map pages = new java.util.HashMap/*<PageViewport,PageObject>*/(); - /** - * The page height - */ - private int pageHeight = 0; + /** the AFP datastream */ + private DataStream dataStream; - /** - * The current page sequence id - */ - // UNUSED - // private String pageSequenceId = null; - /** - * The portrait rotation - */ - private int portraitRotation = 0; + /** the image handler registry */ + private final AFPImageHandlerRegistry imageHandlerRegistry; - /** - * The landscape rotation - */ - 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; - - /** - * Flag to the set the output object type for images - */ - private boolean colorImages = false; - - /** - * Default value for image depth - */ - private int bitsPerPixel = 8; - - /** - * The output resolution - */ - private int resolution = DEFAULT_DPI_RESOLUTION; + private AFPRectanglePainter rectanglePainter; /** * Constructor for AFPRenderer. */ public AFPRenderer() { super(); + this.imageHandlerRegistry = new AFPImageHandlerRegistry(); + this.resourceManager = new AFPResourceManager(); + this.paintingState = new AFPPaintingState(); + this.unitConv = paintingState.getUnitConverter(); } - /** - * Set up the font info - * - * @param inFontInfo font info to set up - */ + /** {@inheritDoc} */ public void setupFontInfo(FontInfo inFontInfo) { this.fontInfo = inFontInfo; FontManager fontManager = userAgent.getFactory().getFontManager(); @@ -282,885 +187,272 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { fontManager.setup(getFontInfo(), fontCollections); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void setUserAgent(FOUserAgent agent) { super.setUserAgent(agent); } - /** - * {@inheritDoc} - */ + /** {@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); + paintingState.setColor(Color.WHITE); + + this.dataStream = resourceManager.createDataStream(paintingState, outputStream); + this.borderPainter = new AFPBorderPainter(paintingState, dataStream); + this.rectanglePainter = new AFPRectanglePainter(paintingState, dataStream); + + dataStream.startDocument(); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void stopRenderer() throws IOException { - afpDataStream.endDocument(); + dataStream.endDocument(); + resourceManager.writeToStream(); + resourceManager = null; } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ + public void startPageSequence(LineArea seqTitle) { + try { + dataStream.startPageGroup(); + } catch (IOException e) { + log.error(e.getMessage()); + } + } + + /** {@inheritDoc} */ public boolean supportsOutOfOrder() { - //return false; - return true; + return false; } - /** - * 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} - */ + /** {@inheritDoc} */ public void preparePage(PageViewport page) { - // initializeRootExtensions(page); - - // this.currentFontFamily = ""; - this.currentFontSize = 0; - this.pageFontCounter = 0; - this.currentPageFonts.clear(); - // this.lineCache = new HashSet(); - - 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()); + int pageRotation = paintingState.getPageRotation(); + int pageWidth = paintingState.getPageWidth(); + int pageHeight = paintingState.getPageHeight(); + int resolution = paintingState.getResolution(); + dataStream.startPage(pageWidth, pageHeight, pageRotation, + resolution, resolution); renderPageObjectExtensions(page); - if (this.pages == null) { - this.pages = new HashMap(); - } - this.pages.put(page, afpDataStream.savePage()); - + PageObject currentPage = dataStream.savePage(); + pages.put(page, currentPage); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void processOffDocumentItem(OffDocumentItem odi) { // TODO + log.debug("NYI processOffDocumentItem(" + odi + ")"); } /** {@inheritDoc} */ public Graphics2DAdapter getGraphics2DAdapter() { - return new AFPGraphics2DAdapter(); + return new AFPGraphics2DAdapter(paintingState); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void startVParea(CTM ctm, Rectangle2D clippingRect) { - // dummy not used - } - - /** - * {@inheritDoc} - */ - public void endVParea() { - // dummy not used - } - - /** - * 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) { - Rectangle2D view = port.getViewArea(); - // The CTM will transform coordinates relative to - // this region-reference area into page coords, so - // set origin for the region to 0,0. - currentBPPosition = 0; - currentIPPosition = 0; - - RegionReference regionReference = port.getRegionReference(); - handleRegionTraits(port); - - /* - _afpDataStream.startOverlay(mpts2units(view.getX()) - , mpts2units(view.getY()) - , mpts2units(view.getWidth()) - , mpts2units(view.getHeight()) - , rotation); - */ - - pushViewPortPos(new ViewPortPos(view, regionReference.getCTM())); - - if (regionReference.getRegionClass() == FO_REGION_BODY) { - renderBodyRegion((BodyRegion) regionReference); - } else { - renderRegion(regionReference); - } - /* - _afpDataStream.endOverlay(); - */ - popViewPortPos(); + saveGraphicsState(); + if (ctm != null) { + AffineTransform at = ctm.toAffineTransform(); + concatenateTransformationMatrix(at); } - } - - /** {@inheritDoc} */ - protected void renderBlockViewport(BlockViewport bv, List children) { - // clip and position viewport if necessary - - // save positions - int saveIP = currentIPPosition; - int saveBP = currentBPPosition; - - CTM ctm = bv.getCTM(); - int borderPaddingStart = bv.getBorderAndPaddingWidthStart(); - int borderPaddingBefore = bv.getBorderAndPaddingWidthBefore(); - //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) { - - //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(); - } - - AffineTransform positionTransform = new AffineTransform(); - positionTransform.translate(bv.getXOffset(), bv.getYOffset()); - - //"left/"top" (bv.getX/YOffset()) specify the position of the content rectangle - positionTransform.translate(-borderPaddingStart, -borderPaddingBefore); - - //skipping fox:transform here - - //saveGraphicsState(); - //Viewport position - //concatenateTransformationMatrix(mptToPt(positionTransform)); - - //Background and borders - float bpwidth = (borderPaddingStart + bv.getBorderAndPaddingWidthEnd()) / 1000f; - float bpheight = (borderPaddingBefore + bv.getBorderAndPaddingWidthAfter()) / 1000f; - Point2D ptSrc = new Point(0, 0); - Point2D ptDst = positionTransform.transform(ptSrc, null); - Rectangle2D borderRect = new Rectangle2D.Double(ptDst.getX(), ptDst.getY(), - 1000 * (width + bpwidth), 1000 * (height + bpheight)); - pushViewPortPos(new ViewPortPos(borderRect, new CTM(positionTransform))); - drawBackAndBorders(bv, 0, 0, width + bpwidth, height + bpheight); - - //Shift to content rectangle after border painting - AffineTransform contentRectTransform = new AffineTransform(); - contentRectTransform.translate(borderPaddingStart, borderPaddingBefore); - //concatenateTransformationMatrix(mptToPt(contentRectTransform)); - ptSrc = new Point(0, 0); - ptDst = contentRectTransform.transform(ptSrc, null); - Rectangle2D contentRect = new Rectangle2D.Double(ptDst.getX(), ptDst.getY(), - 1000 * width, 1000 * height); - pushViewPortPos(new ViewPortPos(contentRect, new CTM(contentRectTransform))); - - //Clipping is not supported, yet - //Rectangle2D clippingRect = null; - //clippingRect = new Rectangle(0, 0, bv.getIPD(), bv.getBPD()); - - //saveGraphicsState(); - //Set up coordinate system for content rectangle - AffineTransform contentTransform = ctm.toAffineTransform(); - //concatenateTransformationMatrix(mptToPt(contentTransform)); - contentRect = new Rectangle2D.Double(0, 0, 1000 * width, 1000 * height); - pushViewPortPos(new ViewPortPos(contentRect, new CTM(contentTransform))); - - currentIPPosition = 0; - currentBPPosition = 0; - renderBlocks(bv, children); - - popViewPortPos(); - popViewPortPos(); - //restoreGraphicsState(); - popViewPortPos(); - //restoreGraphicsState(); - - if (breakOutList != null) { - restoreStateStackAfterBreakOut(breakOutList); - } - - currentIPPosition = saveIP; - currentBPPosition = saveBP; - } else { - - currentBPPosition += bv.getSpaceBefore(); - - //borders and background in the old coordinate system - handleBlockTraits(bv); - - //Advance to start of content area - currentIPPosition += bv.getStartIndent(); - - CTM tempctm = new CTM(containingIPPosition, currentBPPosition); - ctm = tempctm.multiply(ctm); - - //Now adjust for border/padding - currentBPPosition += borderPaddingBefore; - - Rectangle2D clippingRect = null; - clippingRect = new Rectangle(currentIPPosition, currentBPPosition, - bv.getIPD(), bv.getBPD()); - - //startVParea(ctm, clippingRect); - pushViewPortPos(new ViewPortPos(clippingRect, ctm)); - - currentIPPosition = 0; - currentBPPosition = 0; - renderBlocks(bv, children); - //endVParea(); - popViewPortPos(); - - currentIPPosition = saveIP; - currentBPPosition = saveBP; - - currentBPPosition += (int)(bv.getAllocBPD()); + if (clippingRect != null) { + clipRect((float)clippingRect.getX() / 1000f, + (float)clippingRect.getY() / 1000f, + (float)clippingRect.getWidth() / 1000f, + (float)clippingRect.getHeight() / 1000f); } } /** {@inheritDoc} */ - protected void renderReferenceArea(Block block) { - //TODO Remove this method once concatenateTransformationMatrix() is implemented - - // save position and offset - int saveIP = currentIPPosition; - int saveBP = currentBPPosition; - - //Establish a new coordinate system - AffineTransform at = new AffineTransform(); - at.translate(currentIPPosition, currentBPPosition); - at.translate(block.getXOffset(), block.getYOffset()); - at.translate(0, block.getSpaceBefore()); - - if (!at.isIdentity()) { - Rectangle2D contentRect - = new Rectangle2D.Double(at.getTranslateX(), at.getTranslateY(), - block.getAllocIPD(), block.getAllocBPD()); - pushViewPortPos(new ViewPortPos(contentRect, new CTM(at))); - } - - currentIPPosition = 0; - currentBPPosition = 0; - handleBlockTraits(block); - - List children = block.getChildAreas(); - if (children != null) { - renderBlocks(block, children); - } - - if (!at.isIdentity()) { - popViewPortPos(); - } - - // stacked and relative blocks effect stacking - currentIPPosition = saveIP; - currentBPPosition = saveBP; + public void endVParea() { + restoreGraphicsState(); } /** {@inheritDoc} */ - protected void renderFlow(NormalFlow flow) { - // save position and offset - int saveIP = currentIPPosition; - int saveBP = currentBPPosition; - - //Establish a new coordinate system - AffineTransform at = new AffineTransform(); - at.translate(currentIPPosition, currentBPPosition); - - if (!at.isIdentity()) { - Rectangle2D contentRect - = new Rectangle2D.Double(at.getTranslateX(), at.getTranslateY(), - flow.getAllocIPD(), flow.getAllocBPD()); - pushViewPortPos(new ViewPortPos(contentRect, new CTM(at))); - } - - currentIPPosition = 0; - currentBPPosition = 0; - super.renderFlow(flow); - + protected void concatenateTransformationMatrix(AffineTransform at) { if (!at.isIdentity()) { - popViewPortPos(); + paintingState.concatenate(at); } - - // stacked and relative blocks effect stacking - currentIPPosition = saveIP; - currentBPPosition = saveBP; - } - - - /** {@inheritDoc} */ - protected void concatenateTransformationMatrix(AffineTransform at) { - //Not used here since AFPRenderer defines its own renderBlockViewport() method. - throw new UnsupportedOperationException("NYI"); } /** - * {@inheritDoc} + * Returns the base AFP transform + * + * @return the base AFP transform */ - public void renderPage(PageViewport pageViewport) { - - // initializeRootExtensions(page); + private AffineTransform getBaseTransform() { + AffineTransform baseTransform = new AffineTransform(); + double scale = unitConv.mpt2units(1); + baseTransform.scale(scale, scale); + return baseTransform; + } - // this.currentFontFamily = ""; - this.currentFontSize = 0; - this.pageFontCounter = 0; - this.currentPageFonts.clear(); - // this.lineCache = new HashSet(); + /** {@inheritDoc} */ + public void renderPage(PageViewport pageViewport) throws IOException, FOPException { + paintingState.clear(); Rectangle2D bounds = pageViewport.getViewArea(); - this.pageWidth = mpts2units(bounds.getWidth()); - this.pageHeight = mpts2units(bounds.getHeight()); - - if (pages != null && pages.containsKey(pageViewport)) { - - this.afpDataStream.restorePage((PageObject) pages.remove(pageViewport)); + AffineTransform baseTransform = getBaseTransform(); + paintingState.concatenate(baseTransform); + if (pages.containsKey(pageViewport)) { + dataStream.restorePage( + (PageObject)pages.remove(pageViewport)); } else { - // renderPageGroupExtensions(page); - - final int pageRotation = 0; - this.afpDataStream.startPage(pageWidth, pageHeight, pageRotation, - getResolution(), getResolution()); - - renderPageObjectExtensions(pageViewport); - - } - - pushViewPortPos(new ViewPortPos()); + int pageWidth + = Math.round(unitConv.mpt2units((float)bounds.getWidth())); + paintingState.setPageWidth(pageWidth); - renderPageAreas(pageViewport.getPage()); + int pageHeight + = Math.round(unitConv.mpt2units((float)bounds.getHeight())); + paintingState.setPageHeight(pageHeight); - Iterator i = currentPageFonts.values().iterator(); - while (i.hasNext()) { - AFPFontAttributes afpFontAttributes = (AFPFontAttributes) i.next(); + int pageRotation = paintingState.getPageRotation(); - afpDataStream.createFont( - (byte)afpFontAttributes.getFontReference(), - afpFontAttributes.getFont(), - afpFontAttributes.getPointSize()); + int resolution = paintingState.getResolution(); - } + dataStream.startPage(pageWidth, pageHeight, pageRotation, + resolution, resolution); - try { - afpDataStream.endPage(); - } catch (IOException ioex) { - // TODO What shall we do? + renderPageObjectExtensions(pageViewport); } - popViewPortPos(); - - } - - /** - * {@inheritDoc} - */ - public void clip() { - // TODO - } + super.renderPage(pageViewport); - /** - * {@inheritDoc} - */ - public void clipRect(float x, float y, float width, float height) { - // TODO - } + AFPPageFonts pageFonts = paintingState.getPageFonts(); + if (pageFonts != null && !pageFonts.isEmpty()) { + dataStream.addFontsToCurrentPage(pageFonts); + } - /** - * {@inheritDoc} - */ - public void moveTo(float x, float y) { - // TODO + dataStream.endPage(); } - /** - * {@inheritDoc} - */ - public void lineTo(float x, float y) { - // TODO - } - - /** - * {@inheritDoc} - */ - public void closePath() { - // TODO + /** {@inheritDoc} */ + public void drawBorderLine(float x1, float y1, float x2, float y2, + boolean horz, boolean startOrBefore, int style, Color col) { + BorderPaintingInfo borderPaintInfo = new BorderPaintingInfo(x1, y1, x2, y2, horz, style, col); + borderPainter.paint(borderPaintInfo); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ 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.createLine( - pts2units(x), - pts2units(y), - pts2units(x + width), - pts2units(y), - pts2units(height), - currentColor); + RectanglePaintingInfo rectanglePaintInfo = new RectanglePaintingInfo(x, y, width, height); + rectanglePainter.paint(rectanglePaintInfo); } - /** - * {@inheritDoc} - */ - public void drawBorderLine(float x1, float y1, float x2, float y2, - boolean horz, boolean startOrBefore, int style, Color col) { - float w = x2 - x1; - float h = y2 - y1; - if ((w < 0) || (h < 0)) { - log.error("Negative extent received. Border won't be painted."); - 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 - ); - } - 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; - } - } - 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_GROOVE: - case Constants.EN_RIDGE: - { - float colFactor = (style == EN_GROOVE ? 0.4f : -0.4f); - if (horz) { - Color uppercol = ColorUtil.lightenColor(col, -colFactor); - Color lowercol = ColorUtil.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 = ColorUtil.lightenColor(col, -colFactor); - Color rightcol = ColorUtil.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 instantiateRendererContext() { + return new AFPRendererContext(this, getMimeType()); } - /** - * {@inheritDoc} - */ - protected RendererContext createRendererContext(int x, int y, int width, int height, - Map foreignAttributes) { + /** {@inheritDoc} */ + protected RendererContext createRendererContext(int x, int y, int width, + int height, Map foreignAttributes) { RendererContext context; - context = super.createRendererContext(x, y, width, height, foreignAttributes); - context.setProperty(AFPRendererContextConstants.AFP_GRAYSCALE, - Boolean.valueOf(!this.colorImages)); + context = super.createRendererContext(x, y, width, height, + foreignAttributes); + context.setProperty(AFPRendererContextConstants.AFP_FONT_INFO, + this.fontInfo); + context.setProperty(AFPRendererContextConstants.AFP_RESOURCE_MANAGER, + this.resourceManager); + context.setProperty(AFPRendererContextConstants.AFP_PAINTING_STATE, paintingState); return context; } - private static final ImageFlavor[] FLAVORS = new ImageFlavor[] - {ImageFlavor.RAW_CCITTFAX, - ImageFlavor.GRAPHICS2D, - ImageFlavor.BUFFERED_IMAGE, - ImageFlavor.RENDERED_IMAGE, - ImageFlavor.XML_DOM}; + private static final ImageFlavor[] NATIVE_FLAVORS = new ImageFlavor[] { + ImageFlavor.XML_DOM, + /*ImageFlavor.RAW_PNG, */ // PNG not natively supported in AFP + ImageFlavor.RAW_JPEG, ImageFlavor.RAW_CCITTFAX, ImageFlavor.RAW_EPS, + ImageFlavor.GRAPHICS2D, ImageFlavor.BUFFERED_IMAGE, ImageFlavor.RENDERED_IMAGE }; + + private static final ImageFlavor[] FLAVORS = new ImageFlavor[] { + ImageFlavor.XML_DOM, + ImageFlavor.GRAPHICS2D, ImageFlavor.BUFFERED_IMAGE, ImageFlavor.RENDERED_IMAGE }; /** {@inheritDoc} */ public void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) { uri = URISpecification.getURL(uri); - Rectangle posInt = new Rectangle( - (int)pos.getX(), - (int)pos.getY(), - (int)pos.getWidth(), - (int)pos.getHeight()); + paintingState.setImageUri(uri); + Point origin = new Point(currentIPPosition, currentBPPosition); + Rectangle posInt = new Rectangle( + (int)Math.round(pos.getX()), + (int)Math.round(pos.getY()), + (int)Math.round(pos.getWidth()), + (int)Math.round(pos.getHeight()) + ); int x = origin.x + posInt.x; int y = origin.y + posInt.y; - String name = null; - if (pageSegmentsMap != null) { - name = (String) pageSegmentsMap.get(uri); - } + String name = (String)pageSegmentMap.get(uri); if (name != null) { - afpDataStream.createIncludePageSegment(name, mpts2units(x), mpts2units(y)); + float[] srcPts = {x, y}; + int[] coords = unitConv.mpts2units(srcPts); + dataStream.createIncludePageSegment(name, coords[X], coords[Y]); } else { - ImageManager manager = getUserAgent().getFactory().getImageManager(); + ImageManager manager = userAgent.getFactory().getImageManager(); ImageInfo info = null; try { - ImageSessionContext sessionContext = getUserAgent().getImageSessionContext(); + ImageSessionContext sessionContext = userAgent + .getImageSessionContext(); info = manager.getImageInfo(uri, sessionContext); - //Only now fully load/prepare the image + // Only now fully load/prepare the image Map hints = ImageUtil.getDefaultHints(sessionContext); + + boolean nativeImagesSupported = paintingState.isNativeImagesSupported(); + ImageFlavor[] flavors = nativeImagesSupported ? NATIVE_FLAVORS : FLAVORS; + + // Load image org.apache.xmlgraphics.image.loader.Image img = manager.getImage( - info, FLAVORS, hints, sessionContext); - - //...and process the image - if (img instanceof ImageGraphics2D) { - ImageGraphics2D imageG2D = (ImageGraphics2D)img; - RendererContext context = createRendererContext( - posInt.x, posInt.y, - posInt.width, posInt.height, foreignAttributes); - getGraphics2DAdapter().paintImage(imageG2D.getGraphics2DImagePainter(), - context, - origin.x + posInt.x, origin.y + posInt.y, - posInt.width, posInt.height); - } else if (img instanceof ImageRendered) { - ImageRendered imgRend = (ImageRendered)img; - RenderedImage ri = imgRend.getRenderedImage(); - - drawBufferedImage(ri, getResolution(), - posInt.x + currentIPPosition, - posInt.y + currentBPPosition, - posInt.width, - posInt.height); - } else if (img instanceof ImageRawCCITTFax) { - ImageRawCCITTFax ccitt = (ImageRawCCITTFax)img; - int afpx = mpts2units(posInt.x + currentIPPosition); - int afpy = mpts2units(posInt.y + currentBPPosition); - int afpw = mpts2units(posInt.getWidth()); - int afph = mpts2units(posInt.getHeight()); - int afpres = getResolution(); - ImageObject io = afpDataStream.getImageObject(afpx, afpy, afpw, afph, - afpres, afpres); - io.setImageParameters( - (int) (ccitt.getSize().getDpiHorizontal() * 10), - (int) (ccitt.getSize().getDpiVertical() * 10), - ccitt.getSize().getWidthPx(), - ccitt.getSize().getHeightPx()); - int compression = ccitt.getCompression(); - switch (compression) { - case TIFFImage.COMP_FAX_G3_1D : - io.setImageEncoding((byte) 0x80); - break; - case TIFFImage.COMP_FAX_G3_2D : - io.setImageEncoding((byte) 0x81); - break; - case TIFFImage.COMP_FAX_G4_2D : - io.setImageEncoding((byte) 0x82); - break; - default: - throw new IllegalStateException( - "Invalid compression scheme: " + compression); - } - InputStream in = ccitt.createInputStream(); + info, flavors, hints, sessionContext); + + // Handle image + AFPImageHandler imageHandler + = (AFPImageHandler)imageHandlerRegistry.getHandler(img); + if (imageHandler != null) { + RendererContext rendererContext = createRendererContext( + x, y, posInt.width, posInt.height, foreignAttributes); + AFPRendererImageInfo rendererImageInfo = new AFPRendererImageInfo( + uri, pos, origin, info, img, rendererContext, foreignAttributes); + AFPDataObjectInfo dataObjectInfo = null; try { - byte[] buf = IOUtils.toByteArray(in); - io.setImageData(buf); - } finally { - IOUtils.closeQuietly(in); + dataObjectInfo = imageHandler.generateDataObjectInfo(rendererImageInfo); + // Create image + if (dataObjectInfo != null) { + resourceManager.createObject(dataObjectInfo); + } + } catch (IOException ioe) { + ResourceEventProducer eventProducer + = ResourceEventProducer.Provider.get(userAgent.getEventBroadcaster()); + eventProducer.imageWritingError(this, ioe); + throw ioe; } - } else if (img instanceof ImageXMLDOM) { - ImageXMLDOM imgXML = (ImageXMLDOM)img; - renderDocument(imgXML.getDocument(), imgXML.getRootNamespace(), - pos, foreignAttributes); } else { - throw new UnsupportedOperationException("Unsupported image type: " + img); + throw new UnsupportedOperationException( + "No AFPImageHandler available for image: " + + info + " (" + img.getClass().getName() + ")"); } } catch (ImageException ie) { - ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.imageError(this, (info != null ? info.toString() : uri), ie, null); + ResourceEventProducer eventProducer = ResourceEventProducer.Provider + .get(userAgent.getEventBroadcaster()); + eventProducer.imageError(this, (info != null ? info.toString() + : uri), ie, null); } catch (FileNotFoundException fe) { - ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.imageNotFound(this, (info != null ? info.toString() : uri), fe, null); + ResourceEventProducer eventProducer = ResourceEventProducer.Provider + .get(userAgent.getEventBroadcaster()); + eventProducer.imageNotFound(this, (info != null ? info.toString() + : uri), fe, null); } catch (IOException ioe) { - ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.imageIOError(this, (info != null ? info.toString() : uri), ioe, null); + ResourceEventProducer eventProducer = ResourceEventProducer.Provider + .get(userAgent.getEventBroadcaster()); + eventProducer.imageIOError(this, (info != null ? info.toString() + : uri), ioe, null); } - - /* - ImageFactory fact = userAgent.getFactory().getImageFactory(); - FopImage fopimage = fact.getImage(url, userAgent); - if (fopimage == null) { - return; - } - if (!fopimage.load(FopImage.DIMENSIONS)) { - return; - } - String mime = fopimage.getMimeType(); - if ("text/xml".equals(mime) || MimeConstants.MIME_SVG.equals(mime)) { - if (!fopimage.load(FopImage.ORIGINAL_DATA)) { - return; - } - Document doc = ((XMLImage) fopimage).getDocument(); - String ns = ((XMLImage) fopimage).getNameSpace(); - - renderDocument(doc, ns, pos, foreignAttributes); - } else if (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_TIFF.equals(mime) - && 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()); - io.setImageParameters( - (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.setImageData(fopimage.getRessourceBytes()); - } else if (comp == 4) { - if (!fopimage.load(FopImage.ORIGINAL_DATA)) { - return; - } - io.setImageEncoding((byte)0x82); - io.setImageData(fopimage.getRessourceBytes()); - } else { - if (!fopimage.load(FopImage.BITMAP)) { - return; - } - convertToGrayScaleImage(io, fopimage.getBitmaps(), - fopimage.getWidth(), fopimage.getHeight()); - } - } else { - if (!fopimage.load(FopImage.BITMAP)) { - return; - } - convertToGrayScaleImage(io, fopimage.getBitmaps(), - fopimage.getWidth(), fopimage.getHeight()); - } - } else { - if (!fopimage.load(FopImage.BITMAP)) { - 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(x, y, w, h, - getResolution(), getResolution()); - io.setImageParameters( - (int)(fopimage.getHorizontalResolution() * 10), - (int)(fopimage.getVerticalResolution() * 10), - fopimage.getWidth(), - fopimage.getHeight() - ); - if (colorImages) { - io.setImageIDESize((byte)24); - io.setImageData(fopimage.getBitmaps()); - } else { - convertToGrayScaleImage(io, fopimage.getBitmaps(), - fopimage.getWidth(), fopimage.getHeight()); - } - }*/ } } @@ -1173,364 +465,155 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { * the OutputStream * @throws IOException * In case of an I/O error. + * @deprecated use ImageEncodingHelper.encodeRenderedImageAsRGB(image, out) + * directly instead */ public static void writeImage(RenderedImage image, OutputStream out) throws IOException { ImageEncodingHelper.encodeRenderedImageAsRGB(image, out); } - /** - * Draws a BufferedImage to AFP. - * - * @param image - * the RenderedImage - * @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(RenderedImage image, int imageResolution, int x, - int y, int w, int h) { - int afpx = mpts2units(x); - int afpy = mpts2units(y); - int afpw = mpts2units(w); - int afph = mpts2units(h); - int afpres = getResolution(); - ByteArrayOutputStream baout = new ByteArrayOutputStream(); - try { - // Serialize image - //TODO Eventually, this should be changed not to buffer as this increases the - //memory consumption (see PostScript output) - writeImage(image, baout); - byte[] buf = baout.toByteArray(); - - // Generate image - ImageObject io = afpDataStream.getImageObject(afpx, afpy, afpw, - afph, afpres, afpres); - io.setImageParameters(imageResolution, imageResolution, - image.getWidth(), image.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, - image.getWidth(), image.getHeight(), this.bitsPerPixel); - } - } catch (IOException ioe) { - ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.imageWritingError(this, ioe); - } - } - - /** - * Establishes a new foreground or fill color. - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void updateColor(Color col, boolean fill) { if (fill) { - currentColor = col; + paintingState.setColor(col); } } /** {@inheritDoc} */ - public List breakOutOfStateStack() { - log.debug("Block.FIXED --> break out"); - List breakOutList = new java.util.ArrayList(); - //Don't pop the last ViewPortPos (created by renderPage()) - while (this.viewPortPositions.size() > 1) { - breakOutList.add(0, popViewPortPos()); - } - return breakOutList; + public void restoreStateStackAfterBreakOut(List breakOutList) { + log.debug("Block.FIXED --> restoring context after break-out"); + paintingState.saveAll(breakOutList); } /** {@inheritDoc} */ - public void restoreStateStackAfterBreakOut(List breakOutList) { - log.debug("Block.FIXED --> restoring context after break-out"); - for (int i = 0, c = breakOutList.size(); i < c; i++) { - ViewPortPos vps = (ViewPortPos)breakOutList.get(i); - pushViewPortPos(vps); - } + protected List breakOutOfStateStack() { + log.debug("Block.FIXED --> break out"); + return paintingState.restoreAll(); } - /** Saves the graphics state of the rendering engine. */ + /** {@inheritDoc} */ public void saveGraphicsState() { - + paintingState.save(); } - /** Restores the last graphics state of the rendering engine. */ + /** {@inheritDoc} */ public void restoreGraphicsState() { - + paintingState.restore(); } - /** Indicates the beginning of a text object. */ - public void beginTextObject() { - - } - - /** Indicates the end of a text object. */ - public void endTextObject() { - - } - - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void renderImage(Image image, Rectangle2D pos) { - String url = image.getURL(); - drawImage(url, pos); + drawImage(image.getURL(), pos, image.getForeignAttributes()); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ 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); + // set font size + int fontSize = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue(); + paintingState.setFontSize(fontSize); - Color col = (Color) text.getTrait(Trait.COLOR); + // register font as necessary + String internalFontName = getInternalFontNameForArea(text); + Map/*<String,FontMetrics>*/ fontMetricMap = fontInfo.getFonts(); + AFPFont font = (AFPFont)fontMetricMap.get(internalFontName); + AFPPageFonts pageFonts = paintingState.getPageFonts(); + AFPFontAttributes fontAttributes = pageFonts.registerFont(internalFontName, font, fontSize); - int vsci = mpts2units(tf.getWidth(' ', currentFontSize) / 1000 - + text.getTextWordSpaceAdjust() - + text.getTextLetterSpaceAdjust()); + // create text data info + AFPTextDataInfo textDataInfo = new AFPTextDataInfo(); - // 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 - int rx = currentIPPosition + text.getBorderAndPaddingWidthStart(); - int bl = currentBPPosition + text.getOffset() + text.getBaselineOffset(); + int fontReference = fontAttributes.getFontReference(); + textDataInfo.setFontReference(fontReference); - // Set letterSpacing - //float ls = fs.getLetterSpacing() / this.currentFontSize; + int x = (currentIPPosition + text.getBorderAndPaddingWidthStart()); + int y = (currentBPPosition + text.getOffset() + text.getBaselineOffset()); - String worddata = text.getText(); + int[] coords = unitConv.mpts2units(new float[] {x, y} ); + textDataInfo.setX(coords[X]); + textDataInfo.setY(coords[Y]); - // Create an AFPFontAttributes object from the current font details - AFPFontAttributes afpFontAttributes = new AFPFontAttributes(name, tf, currentFontSize); + Color color = (Color) text.getTrait(Trait.COLOR); + textDataInfo.setColor(color); - 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); + int textWordSpaceAdjust = text.getTextWordSpaceAdjust(); + int textLetterSpaceAdjust = text.getTextLetterSpaceAdjust(); + int textWidth = font.getWidth(' ', fontSize) / 1000; + int variableSpaceCharacterIncrement + = textWidth + textWordSpaceAdjust + textLetterSpaceAdjust; - } else { - // Use the previously stored font attributes - afpFontAttributes = (AFPFontAttributes) currentPageFonts.get( - afpFontAttributes.getFontKey()); - } + variableSpaceCharacterIncrement + = Math.round(unitConv.mpt2units(variableSpaceCharacterIncrement)); + textDataInfo.setVariableSpaceCharacterIncrement(variableSpaceCharacterIncrement); - // Try and get the encoding to use for the font - String encoding = null; + int interCharacterAdjustment + = Math.round(unitConv.mpt2units(textLetterSpaceAdjust)); + textDataInfo.setInterCharacterAdjustment(interCharacterAdjustment); - try { - encoding = tf.getCharacterSet(currentFontSize).getEncoding(); - } catch (Throwable ex) { - encoding = AFPConstants.EBCIDIC_ENCODING; - log.warn( - "renderText():: Error getting encoding for font '" - + tf.getFullName() - + "' - using default encoding " - + encoding); - } + CharacterSet charSet = font.getCharacterSet(fontSize); + String encoding = charSet.getEncoding(); + textDataInfo.setEncoding(encoding); + + String textString = text.getText(); + textDataInfo.setString(textString); try { - afpDataStream.createText( - afpFontAttributes.getFontReference(), - mpts2units(rx), - mpts2units(bl), - col, - vsci, - mpts2units(text.getTextLetterSpaceAdjust()), - worddata.getBytes(encoding)); - } catch (UnsupportedEncodingException usee) { - log.error( - "renderText:: Font " - + afpFontAttributes.getFontKey() - + " caused UnsupportedEncodingException"); + dataStream.createText(textDataInfo); + } catch (UnsupportedEncodingException e) { + AFPEventProducer eventProducer + = AFPEventProducer.Provider.get(userAgent.getEventBroadcaster()); + eventProducer.characterSetEncodingError(this, charSet.getName(), encoding); } + // 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 super.renderText(text); - renderTextDecoration(tf, currentFontSize, text, bl, rx); + renderTextDecoration(font, fontSize, text, y, x); } /** - * {@inheritDoc} - */ - public void renderWord(WordArea word) { - // UNUSED - // String name = getInternalFontNameForArea(word.getParentArea()); - // int size = ((Integer) - // word.getParentArea().getTrait(Trait.FONT_SIZE)).intValue(); - // AFPFont tf = (AFPFont) fontInfo.getFonts().get(name); - // - // String s = word.getWord(); - // - // FontMetrics metrics = fontInfo.getMetricsFor(name); - - super.renderWord(word); - } - - /** - * {@inheritDoc} - */ - public void renderSpace(SpaceArea space) { - // UNUSED - // String name = getInternalFontNameForArea(space.getParentArea()); - // int size = ((Integer) - // space.getParentArea().getTrait(Trait.FONT_SIZE)).intValue(); - // AFPFont tf = (AFPFont) fontInfo.getFonts().get(name); - // - // String s = space.getSpace(); - // - // FontMetrics metrics = fontInfo.getMetricsFor(name); - - super.renderSpace(space); - } - - /** - * 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. - * - * @param rotation - * The rotation in degrees. - */ - public void setPortraitRotation(int rotation) { - - if (rotation == 0 - || rotation == 90 - || rotation == 180 - || rotation == 270) { - portraitRotation = rotation; - } else { - throw new IllegalArgumentException("The portrait rotation must be one" - + " of the values 0, 90, 180, 270"); - - } - - } - - /** - * 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) { - landscapeRotation = rotation; - } else { - throw new IllegalArgumentException("The landscape rotation must be one" - + " of the values 0, 90, 180, 270"); - } - - } - - /** * 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; @@ -1540,46 +623,40 @@ 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) { - - pageSegmentsMap = null; + pageSegmentMap.clear(); if (pageViewport.getExtensionAttachments() != null && pageViewport.getExtensionAttachments().size() > 0) { // Extract all AFPPageSetup instances from the attachment list on // the s-p-m - Iterator i = pageViewport.getExtensionAttachments().iterator(); - while (i.hasNext()) { - ExtensionAttachment attachment = (ExtensionAttachment)i.next(); + Iterator it = pageViewport.getExtensionAttachments().iterator(); + while (it.hasNext()) { + ExtensionAttachment attachment = (ExtensionAttachment) it.next(); if (AFPPageSetup.CATEGORY.equals(attachment.getCategory())) { AFPPageSetup aps = (AFPPageSetup) attachment; String element = aps.getElementName(); if (AFPElementMapping.INCLUDE_PAGE_OVERLAY.equals(element)) { String overlay = aps.getName(); if (overlay != null) { - afpDataStream.createIncludePageOverlay(overlay); + dataStream.createIncludePageOverlay(overlay); } } else if (AFPElementMapping.INCLUDE_PAGE_SEGMENT .equals(element)) { String name = aps.getName(); String source = aps.getValue(); - if (pageSegmentsMap == null) { - pageSegmentsMap = new HashMap(); - } - pageSegmentsMap.put(source, name); + pageSegmentMap.put(source, name); } else if (AFPElementMapping.TAG_LOGICAL_ELEMENT .equals(element)) { String name = aps.getName(); String value = aps.getValue(); - if (pageSegmentsMap == null) { - pageSegmentsMap = new HashMap(); - } - afpDataStream.createTagLogicalElement(name, value); + dataStream.createTagLogicalElement(name, value); } else if (AFPElementMapping.NO_OPERATION.equals(element)) { String content = aps.getContent(); if (content != null) { - afpDataStream.createNoOperation(content); + dataStream.createNoOperation(content); } } } @@ -1589,206 +666,25 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { } /** - * Converts FOP mpt measurement to afp measurement units - * @param mpt the millipoints value - */ - private int mpts2units(int mpt) { - return mpts2units((double) mpt); - } - - /** - * Converts FOP pt measurement to afp measurement units - * @param mpt the millipoints value - */ - private int pts2units(float mpt) { - return mpts2units(mpt * 1000d); - } - - /** - * Converts FOP mpt measurement to afp measurement units + * Sets the rotation to be used for portrait pages, valid values are 0 + * (default), 90, 180, 270. * - * @param mpt - * the millipoints value - * @return afp measurement unit value + * @param rotation + * The rotation in degrees. */ - private int mpts2units(double mpt) { - return (int)Math.round(mpt / (DPI_CONVERSION_FACTOR / getResolution())); + public void setPortraitRotation(int rotation) { + paintingState.setPortraitRotation(rotation); } /** - * Converts a byte array containing 24 bit RGB image data to a grayscale - * image. + * Sets the rotation to be used for landsacpe pages, valid values are 0, 90, + * 180, 270 (default). * - * @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 + * @param rotation + * The rotation in degrees. */ - 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) { - bytewidth++; - } - byte[] bw = new byte[height * bytewidth]; - byte ib; - for (int y = 0; y < height; y++) { - 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); - 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( - "Unsupported bits per pixel: " + bitsPerPixel); - } - - if ((x % pixelsPerByte) == (pixelsPerByte - 1) - || ((x + 1) == width)) { - bw[(y * bytewidth) + (x / pixelsPerByte)] = ib; - ib = 0; - } - } - } - io.setImageIDESize((byte) bitsPerPixel); - io.setImageData(bw); - } - - private final class ViewPortPos { - private int x = 0; - - private int y = 0; - - private int rot = 0; - - private ViewPortPos() { - } - - private ViewPortPos(Rectangle2D view, CTM ctm) { - ViewPortPos currentVP = (ViewPortPos) viewPortPositions - .get(viewPortPositions.size() - 1); - int xOrigin; - int yOrigin; - int width; - int height; - switch (currentVP.rot) { - case 90: - width = mpts2units(view.getHeight()); - height = mpts2units(view.getWidth()); - xOrigin = pageWidth - width - mpts2units(view.getY()) - - currentVP.y; - yOrigin = mpts2units(view.getX()) + currentVP.x; - break; - case 180: - width = mpts2units(view.getWidth()); - height = mpts2units(view.getHeight()); - xOrigin = pageWidth - width - mpts2units(view.getX()) - - currentVP.x; - yOrigin = pageHeight - height - mpts2units(view.getY()) - - currentVP.y; - break; - case 270: - width = mpts2units(view.getHeight()); - height = mpts2units(view.getWidth()); - xOrigin = mpts2units(view.getY()) + currentVP.y; - yOrigin = pageHeight - height - mpts2units(view.getX()) - - currentVP.x; - break; - default: - xOrigin = mpts2units(view.getX()) + currentVP.x; - yOrigin = mpts2units(view.getY()) + currentVP.y; - width = mpts2units(view.getWidth()); - height = mpts2units(view.getHeight()); - break; - } - this.rot = currentVP.rot; - double[] ctmf = ctm.toArray(); - if (ctmf[0] == 0.0d && ctmf[1] == -1.0d && ctmf[2] == 1.0d - && ctmf[3] == 0.d) { - this.rot += 270; - } else if (ctmf[0] == -1.0d && ctmf[1] == 0.0d && ctmf[2] == 0.0d - && ctmf[3] == -1.0d) { - this.rot += 180; - } else if (ctmf[0] == 0.0d && ctmf[1] == 1.0d && ctmf[2] == -1.0d - && ctmf[3] == 0.0d) { - this.rot += 90; - } - this.rot %= 360; - switch (this.rot) { - /* - * case 0: this.x = mpts2units(view.getX()) + x; this.y = - * mpts2units(view.getY()) + y; break; case 90: this.x = - * mpts2units(view.getY()) + y; this.y = _pageWidth - - * mpts2units(view.getX() + view.getWidth()) - x; break; case 180: - * this.x = _pageWidth - mpts2units(view.getX() + view.getWidth()) - - * x; this.y = _pageHeight - mpts2units(view.getY() + - * view.getHeight()) - y; break; case 270: this.x = _pageHeight - - * mpts2units(view.getY() + view.getHeight()) - y; this.y = - * mpts2units(view.getX()) + x; break; - */ - case 0: - this.x = xOrigin; - this.y = yOrigin; - break; - case 90: - this.x = yOrigin; - this.y = pageWidth - width - xOrigin; - break; - case 180: - this.x = pageWidth - width - xOrigin; - this.y = pageHeight - height - yOrigin; - break; - case 270: - this.x = pageHeight - height - yOrigin; - this.y = xOrigin; - break; - default: - } - } - - public String toString() { - return "x:" + x + " y:" + y + " rot:" + rot; - } - - } - - private List viewPortPositions = new ArrayList(); - - private void pushViewPortPos(ViewPortPos vpp) { - viewPortPositions.add(vpp); - afpDataStream.setOffsets(vpp.x, vpp.y, vpp.rot); - } - - private ViewPortPos popViewPortPos() { - ViewPortPos current = (ViewPortPos)viewPortPositions.remove(viewPortPositions.size() - 1); - if (viewPortPositions.size() > 0) { - ViewPortPos vpp = (ViewPortPos)viewPortPositions.get(viewPortPositions.size() - 1); - afpDataStream.setOffsets(vpp.x, vpp.y, vpp.rot); - } - return current; + public void setLandscapeRotation(int rotation) { + paintingState.setLandscapeRotation(rotation); } /** @@ -1798,17 +694,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { * number of bits per pixel */ public void setBitsPerPixel(int bitsPerPixel) { - this.bitsPerPixel = bitsPerPixel; - switch (bitsPerPixel) { - case 1: - case 4: - case 8: - break; - default: - log.warn("Invalid bits_per_pixel value, must be 1, 4 or 8."); - bitsPerPixel = 8; - break; - } + paintingState.setBitsPerPixel(bitsPerPixel); } /** @@ -1818,7 +704,17 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { * color image output */ public void setColorImages(boolean colorImages) { - this.colorImages = colorImages; + paintingState.setColorImages(colorImages); + } + + /** + * Sets whether images are supported natively or not + * + * @param nativeImages + * native image support + */ + public void setNativeImagesSupported(boolean nativeImages) { + paintingState.setNativeImagesSupported(nativeImages); } /** @@ -1828,17 +724,73 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { * the output resolution (dpi) */ public void setResolution(int resolution) { - if (log.isDebugEnabled()) { - log.debug("renderer-resolution set to: " + resolution + "dpi"); - } - this.resolution = resolution; + paintingState.setResolution(resolution); } /** * Returns the output/device resolution. + * * @return the resolution in dpi */ public int getResolution() { - return this.resolution; + return paintingState.getResolution(); + } + + /** + * Sets the default resource group file path + * @param filePath the default resource group file path + */ + public void setDefaultResourceGroupFilePath(String filePath) { + resourceManager.setDefaultResourceGroupFilePath(filePath); + } + + /** {@inheritDoc} */ + protected void establishTransformationMatrix(AffineTransform at) { + saveGraphicsState(); + concatenateTransformationMatrix(at); } + + /** {@inheritDoc} */ + public void clip() { + // TODO +// log.debug("NYI clip()"); + } + + /** {@inheritDoc} */ + public void clipRect(float x, float y, float width, float height) { + // TODO +// log.debug("NYI clipRect(x=" + x + ",y=" + y +// + ",width=" + width + ", height=" + height + ")"); + } + + /** {@inheritDoc} */ + public void moveTo(float x, float y) { + // TODO +// log.debug("NYI moveTo(x=" + x + ",y=" + y + ")"); + } + + /** {@inheritDoc} */ + public void lineTo(float x, float y) { + // TODO +// log.debug("NYI lineTo(x=" + x + ",y=" + y + ")"); + } + + /** {@inheritDoc} */ + public void closePath() { + // TODO +// log.debug("NYI closePath()"); + } + + /** Indicates the beginning of a text object. */ + public void beginTextObject() { + //TODO PDF specific maybe? +// log.debug("NYI beginTextObject()"); + } + + /** Indicates the end of a text object. */ + public void endTextObject() { + //TODO PDF specific maybe? +// log.debug("NYI endTextObject()"); + } + } diff --git a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java index 65e39daad..5982ae5b0 100644 --- a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java +++ b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java @@ -19,10 +19,17 @@ package org.apache.fop.render.afp; +import java.io.File; import java.util.List; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; + +import org.apache.fop.afp.fonts.AFPFontInfo; +import org.apache.fop.afp.fonts.CharacterSet; +import org.apache.fop.afp.fonts.FopCharacterSet; +import org.apache.fop.afp.fonts.OutlineFont; +import org.apache.fop.afp.fonts.RasterFont; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.fonts.FontTriplet; @@ -30,11 +37,6 @@ import org.apache.fop.fonts.FontUtil; import org.apache.fop.fonts.Typeface; import org.apache.fop.render.PrintRendererConfigurator; import org.apache.fop.render.Renderer; -import org.apache.fop.render.afp.fonts.AFPFontInfo; -import org.apache.fop.render.afp.fonts.CharacterSet; -import org.apache.fop.render.afp.fonts.FopCharacterSet; -import org.apache.fop.render.afp.fonts.OutlineFont; -import org.apache.fop.render.afp.fonts.RasterFont; import org.apache.fop.util.LogUtil; /** @@ -44,6 +46,7 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator { /** * Default constructor + * * @param userAgent user agent */ public AFPRendererConfigurator(FOUserAgent userAgent) { @@ -54,16 +57,17 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator { throws ConfigurationException { Configuration[] triple = fontCfg.getChildren("font-triplet"); - List tripleList = new java.util.ArrayList(); + List/*<FontTriplet>*/ tripletList = new java.util.ArrayList/*<FontTriplet>*/(); if (triple.length == 0) { log.error("Mandatory font configuration element '<font-triplet...' is missing"); return null; } for (int j = 0; j < triple.length; j++) { int weight = FontUtil.parseCSS2FontWeight(triple[j].getAttribute("weight")); - tripleList.add(new FontTriplet(triple[j].getAttribute("name"), - triple[j].getAttribute("style"), - weight)); + FontTriplet triplet = new FontTriplet(triple[j].getAttribute("name"), + triple[j].getAttribute("style"), + weight); + tripletList.add(triplet); } //build the fonts @@ -121,7 +125,7 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator { try { Typeface tf = (Typeface)clazz.newInstance(); font.addCharacterSet(size, new FopCharacterSet( - codepage, encoding, characterset, size, tf)); + codepage, encoding, characterset, tf)); } catch (Exception ie) { String msg = "The base 14 font class " + clazz.getName() + " could not be instantiated"; @@ -137,21 +141,17 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator { codepage, encoding, characterset, path)); } } - return new AFPFontInfo(font, tripleList); + return new AFPFontInfo(font, tripletList); } else if ("outline".equalsIgnoreCase(type)) { - String characterset = afpFontCfg.getAttribute("characterset"); if (characterset == null) { log.error("Mandatory afp-font configuration attribute 'characterset=' is missing"); return null; } String name = afpFontCfg.getAttribute("name", characterset); - CharacterSet characterSet = null; - String base14 = afpFontCfg.getAttribute("base14-font", null); - if (base14 != null) { try { Class clazz = Class.forName("org.apache.fop.fonts.base14." @@ -159,7 +159,7 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator { try { Typeface tf = (Typeface)clazz.newInstance(); characterSet = new FopCharacterSet( - codepage, encoding, characterset, 1, tf); + codepage, encoding, characterset, tf); } catch (Exception ie) { String msg = "The base 14 font class " + clazz.getName() + " could not be instantiated"; @@ -175,7 +175,7 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator { } // Create a new font object OutlineFont font = new OutlineFont(name, characterSet); - return new AFPFontInfo(font, tripleList); + return new AFPFontInfo(font, tripletList); } else { log.error("No or incorrect type attribute"); } @@ -184,36 +184,45 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator { /** * Builds a list of AFPFontInfo objects for use with the setup() method. + * * @param cfg Configuration object * @return List the newly created list of fonts * @throws ConfigurationException if something's wrong with the config data */ - private List buildFontListFromConfiguration(Configuration cfg) + private List/*<AFPFontInfo>*/ buildFontListFromConfiguration(Configuration cfg) throws ConfigurationException { - List fontList = new java.util.ArrayList(); + List/*<AFPFontInfo>*/ fontList = new java.util.ArrayList(); Configuration[] font = cfg.getChild("fonts").getChildren("font"); + final String fontPath = null; for (int i = 0; i < font.length; i++) { - AFPFontInfo afi = buildFont(font[i], null); + AFPFontInfo afi = buildFont(font[i], fontPath); if (afi != null) { if (log.isDebugEnabled()) { log.debug("Adding font " + afi.getAFPFont().getFontName()); - for (int j = 0; j < afi.getFontTriplets().size(); ++j) { - FontTriplet triplet = (FontTriplet) afi.getFontTriplets().get(j); + List/*<FontTriplet>*/ fontTriplets = afi.getFontTriplets(); + for (int j = 0; j < fontTriplets.size(); ++j) { + FontTriplet triplet = (FontTriplet) fontTriplets.get(j); log.debug(" Font triplet " + triplet.getName() + ", " + triplet.getStyle() + ", " + triplet.getWeight()); } } - fontList.add(afi); } } return fontList; } + /** images are converted to grayscale bitmapped IOCA */ + private static final String IMAGES_MODE_GRAYSCALE = "b+w"; + + /** images are converted to color bitmapped IOCA */ + private static final String IMAGES_MODE_COLOR = "color"; + /** * Configure the AFP renderer. + * * @param renderer AFP renderer * @throws FOPException fop exception * @see org.apache.fop.render.PrintRendererConfigurator#configure(Renderer) @@ -223,24 +232,56 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator { if (cfg != null) { AFPRenderer afpRenderer = (AFPRenderer)renderer; try { - List fontList = buildFontListFromConfiguration(cfg); + List/*<AFPFontInfo>*/ fontList = buildFontListFromConfiguration(cfg); afpRenderer.setFontList(fontList); } catch (ConfigurationException e) { LogUtil.handleException(log, e, userAgent.getFactory().validateUserConfigStrictly()); } + // image information Configuration imagesCfg = cfg.getChild("images"); - if (!"color".equalsIgnoreCase(imagesCfg.getAttribute("mode", "b+w"))) { - afpRenderer.setBitsPerPixel(imagesCfg.getAttributeAsInteger("bits-per-pixel", 8)); - } else { + + // default to grayscale images + String imagesMode = imagesCfg.getAttribute("mode", IMAGES_MODE_GRAYSCALE); + if (IMAGES_MODE_COLOR.equals(imagesMode)) { afpRenderer.setColorImages(true); + } else { + afpRenderer.setColorImages(false); + // default to 8 bits per pixel + int bitsPerPixel = imagesCfg.getAttributeAsInteger("bits-per-pixel", 8); + afpRenderer.setBitsPerPixel(bitsPerPixel); } + // native image support + boolean nativeImageSupport = imagesCfg.getAttributeAsBoolean("native", false); + afpRenderer.setNativeImagesSupported(nativeImageSupport); + + // renderer resolution Configuration rendererResolutionCfg = cfg.getChild("renderer-resolution", false); if (rendererResolutionCfg != null) { afpRenderer.setResolution(rendererResolutionCfg.getValueAsInteger(240)); } + + // a default external resource group file setting + Configuration resourceGroupFileCfg + = cfg.getChild("resource-group-file", false); + if (resourceGroupFileCfg != null) { + String resourceGroupDest = null; + try { + resourceGroupDest = resourceGroupFileCfg.getValue(); + } catch (ConfigurationException e) { + LogUtil.handleException(log, e, + userAgent.getFactory().validateUserConfigStrictly()); + } + File resourceGroupFile = new File(resourceGroupDest); + if (resourceGroupFile.canWrite()) { + afpRenderer.setDefaultResourceGroupFilePath(resourceGroupDest); + } else { + log.warn("Unable to write to default external resource group file '" + + resourceGroupDest + "'"); + } + } } } } diff --git a/src/java/org/apache/fop/render/afp/AFPRendererContext.java b/src/java/org/apache/fop/render/afp/AFPRendererContext.java new file mode 100644 index 000000000..8d544a7c4 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPRendererContext.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; + +import java.util.Map; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.fop.afp.AFPPaintingState; +import org.apache.fop.afp.AFPResourceInfo; +import org.apache.fop.afp.AFPResourceLevel; +import org.apache.fop.afp.AFPResourceManager; +import org.apache.fop.render.AbstractRenderer; +import org.apache.fop.render.RendererContext; +import org.apache.fop.render.RendererContextConstants; + +public class AFPRendererContext extends RendererContext { + + /** + * Main constructor + * + * @param renderer the current renderer + * @param mime the MIME type of the output that's generated. + */ + public AFPRendererContext(AbstractRenderer renderer, String mime) { + super(renderer, mime); + } + + /** + * Returns a new AFPInfo for this renderer context + * + * @return an AFPInfo for this renderer context + */ + public AFPInfo getInfo() { + AFPInfo info = new AFPInfo(); + info.setWidth(((Integer)getProperty(RendererContextConstants.WIDTH)).intValue()); + info.setHeight(((Integer)getProperty(RendererContextConstants.HEIGHT)).intValue()); + info.setX(((Integer)getProperty(RendererContextConstants.XPOS)).intValue()); + info.setY(((Integer)getProperty(RendererContextConstants.YPOS)).intValue()); + info.setHandlerConfiguration((Configuration)getProperty( + RendererContextConstants.HANDLER_CONFIGURATION)); + info.setFontInfo((org.apache.fop.fonts.FontInfo)getProperty( + AFPRendererContextConstants.AFP_FONT_INFO)); + info.setPaintingState((AFPPaintingState)getProperty( + AFPRendererContextConstants.AFP_PAINTING_STATE)); + info.setResourceManager(((AFPResourceManager)getProperty( + AFPRendererContextConstants.AFP_RESOURCE_MANAGER))); + + Map foreignAttributes = (Map)getProperty(RendererContextConstants.FOREIGN_ATTRIBUTES); + if (foreignAttributes != null) { + String conversionMode = (String)foreignAttributes.get(CONVERSION_MODE); + boolean paintAsBitmap = BITMAP.equalsIgnoreCase(conversionMode); + info.setPaintAsBitmap(paintAsBitmap); + + AFPForeignAttributeReader foreignAttributeReader + = new AFPForeignAttributeReader(); + AFPResourceInfo resourceInfo + = foreignAttributeReader.getResourceInfo(foreignAttributes); + // default to inline level if painted as GOCA + if (!resourceInfo.levelChanged() && !paintAsBitmap) { + resourceInfo.setLevel(new AFPResourceLevel(AFPResourceLevel.INLINE)); + } + info.setResourceInfo(resourceInfo); + } + return info; + } +} diff --git a/src/java/org/apache/fop/render/afp/AFPRendererContextConstants.java b/src/java/org/apache/fop/render/afp/AFPRendererContextConstants.java index 428e5b1ca..3302b7f3c 100644 --- a/src/java/org/apache/fop/render/afp/AFPRendererContextConstants.java +++ b/src/java/org/apache/fop/render/afp/AFPRendererContextConstants.java @@ -32,4 +32,12 @@ public interface AFPRendererContextConstants extends RendererContextConstants { */ String AFP_GRAYSCALE = "afpGrayscale"; + /** The font information for the AFP renderer. */ + String AFP_FONT_INFO = "afpFontInfo"; + + /** The afp resource manager */ + String AFP_RESOURCE_MANAGER = "afpResourceManager"; + + /** The afp painting state */ + String AFP_PAINTING_STATE = "afpPaintingState"; } diff --git a/src/java/org/apache/fop/render/afp/AFPRendererImageInfo.java b/src/java/org/apache/fop/render/afp/AFPRendererImageInfo.java new file mode 100644 index 000000000..2687d9071 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPRendererImageInfo.java @@ -0,0 +1,162 @@ +/* + * 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.Point; +import java.awt.geom.Rectangle2D; +import java.util.Map; + +import org.apache.fop.render.RendererContext; +import org.apache.xmlgraphics.image.loader.Image; +import org.apache.xmlgraphics.image.loader.ImageInfo; + +/** + * The AFP image information + */ +public class AFPRendererImageInfo { + + /** the image uri */ + protected final String uri; + + /** the current pos */ + protected final Rectangle2D pos; + + /** the origin */ + protected final Point origin; + + /** the foreign attributes */ + protected final Map foreignAttributes; + + /** the image info */ + protected final ImageInfo info; + + /** the image */ + protected final Image img; + + /** the renderer context */ + protected RendererContext rendererContext; + + /** + * Main constructor + * + * @param uri the image uri + * @param pos the image content area + * @param origin the current position + * @param info the image info + * @param img the image + * @param rendererContext the renderer context + * @param foreignAttributes the foreign attributes + */ + public AFPRendererImageInfo(String uri, Rectangle2D pos, Point origin, + ImageInfo info, Image img, RendererContext rendererContext, Map foreignAttributes) { + this.uri = uri; + this.pos = pos; + this.origin = origin; + this.info = info; + this.img = img; + this.rendererContext = rendererContext; + this.foreignAttributes = foreignAttributes; + } + + /** + * Sets the renderer context + * + * @param rendererContext the renderer context + */ + public void setRendererContext(RendererContext rendererContext) { + this.rendererContext = rendererContext; + } + + /** + * Returns the image info + * + * @return the image info + */ + public ImageInfo getImageInfo() { + return this.info; + } + + /** + * Returns the image + * + * @return the image + */ + public Image getImage() { + return this.img; + } + + /** + * Returns the renderer context + * + * @return the renderer context + */ + public RendererContext getRendererContext() { + return this.rendererContext; + } + + /** + * Return the foreign attributes + * @return the foreign attributes + */ + public Map getForeignAttributes() { + return this.foreignAttributes; + } + + /** + * Return the uri + * + * @return the uri + */ + public String getURI() { + return this.uri; + } + + /** + * Return the origin + * + * @return the origin + */ + public Point getOrigin() { + return this.origin; + } + + /** + * Return the position + * + * @return the position + */ + public Rectangle2D getPosition() { + return this.pos; + } + + /** {@inheritDoc} */ + public String toString() { + return "AFPRendererImageInfo{\n" + + "\turi=" + uri + ",\n" + + "\tinfo=" + info + ",\n" + + "\tpos=" + pos + ",\n" + + "\torigin=" + origin + ",\n" + + "\timg=" + img + ",\n" + + "\tforeignAttributes=" + foreignAttributes + ",\n" + + "\trendererContext=" + rendererContext + "\n" + + "}"; + + } +} diff --git a/src/java/org/apache/fop/render/afp/AFPSVGHandler.java b/src/java/org/apache/fop/render/afp/AFPSVGHandler.java index 5f077fdc6..161217a54 100644 --- a/src/java/org/apache/fop/render/afp/AFPSVGHandler.java +++ b/src/java/org/apache/fop/render/afp/AFPSVGHandler.java @@ -20,9 +20,39 @@ package org.apache.fop.render.afp; // FOP +import java.awt.Dimension; +import java.awt.geom.AffineTransform; +import java.io.IOException; + +import org.w3c.dom.Document; + +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.dom.svg.SVGDOMImplementation; +import org.apache.batik.gvt.GraphicsNode; + +import org.apache.xmlgraphics.image.loader.ImageManager; +import org.apache.xmlgraphics.image.loader.ImageSessionContext; +import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; +import org.apache.xmlgraphics.util.MimeConstants; + +import org.apache.fop.afp.AFPGraphics2D; +import org.apache.fop.afp.AFPGraphicsObjectInfo; +import org.apache.fop.afp.AFPObjectAreaInfo; +import org.apache.fop.afp.AFPPaintingState; +import org.apache.fop.afp.AFPResourceInfo; +import org.apache.fop.afp.AFPResourceManager; +import org.apache.fop.afp.AFPUnitConverter; +import org.apache.fop.afp.svg.AFPBridgeContext; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.image.loader.batik.BatikUtil; +import org.apache.fop.image.loader.batik.Graphics2DImagePainterImpl; import org.apache.fop.render.AbstractGenericSVGHandler; import org.apache.fop.render.Renderer; import org.apache.fop.render.RendererContext; +import org.apache.fop.render.RendererContext.RendererContextWrapper; +import org.apache.fop.svg.SVGEventProducer; +import org.apache.fop.svg.SVGUserAgent; /** * AFP XML handler for SVG. Uses Apache Batik for SVG processing. @@ -31,6 +61,151 @@ import org.apache.fop.render.RendererContext; */ public class AFPSVGHandler extends AbstractGenericSVGHandler { + private boolean paintAsBitmap = false; + + /** {@inheritDoc} */ + public void handleXML(RendererContext context, + Document doc, String ns) throws Exception { + if (SVGDOMImplementation.SVG_NAMESPACE_URI.equals(ns)) { + renderSVGDocument(context, doc); + } + } + + /** + * Render the SVG document. + * + * @param rendererContext the renderer context + * @param doc the SVG document + * @throws IOException In case of an I/O error while painting the image + */ + protected void renderSVGDocument(final RendererContext rendererContext, + final Document doc) throws IOException { + + AFPRendererContext afpRendererContext = (AFPRendererContext)rendererContext; + AFPInfo afpInfo = afpRendererContext.getInfo(); + + this.paintAsBitmap = afpInfo.paintAsBitmap(); + + FOUserAgent userAgent = rendererContext.getUserAgent(); + + // fallback paint as bitmap + String uri = getDocumentURI(doc); + if (paintAsBitmap) { + try { + super.renderSVGDocument(rendererContext, doc); + } catch (IOException ioe) { + SVGEventProducer eventProducer = SVGEventProducer.Provider.get( + userAgent.getEventBroadcaster()); + eventProducer.svgRenderingError(this, ioe, uri); + } + return; + } + + // Create a new AFPGraphics2D + final boolean textAsShapes = afpInfo.strokeText(); + AFPGraphics2D g2d = afpInfo.createGraphics2D(textAsShapes); + + AFPPaintingState paintingState = g2d.getPaintingState(); + paintingState.setImageUri(uri); + + // Create an AFPBridgeContext + BridgeContext bridgeContext = createBridgeContext(userAgent, g2d); + + //Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine) + //to it. + Document clonedDoc = BatikUtil.cloneSVGDocument(doc); + + // Build the SVG DOM and provide the painter with it + GraphicsNode root = buildGraphicsNode(userAgent, bridgeContext, clonedDoc); + + // Create Graphics2DImagePainter + final RendererContextWrapper wrappedContext + = RendererContext.wrapRendererContext(rendererContext); + Dimension imageSize = getImageSize(wrappedContext); + Graphics2DImagePainter painter + = createGrapics2DImagePainter(bridgeContext, root, imageSize); + + // Create AFPObjectAreaInfo + RendererContextWrapper rctx = RendererContext.wrapRendererContext(rendererContext); + int x = rctx.getCurrentXPosition(); + int y = rctx.getCurrentYPosition(); + int width = afpInfo.getWidth(); + int height = afpInfo.getHeight(); + int resolution = afpInfo.getResolution(); + + paintingState.save(); // save + + AFPObjectAreaInfo objectAreaInfo + = createObjectAreaInfo(paintingState, x, y, width, height, resolution); + + // Create AFPGraphicsObjectInfo + AFPResourceInfo resourceInfo = afpInfo.getResourceInfo(); + AFPGraphicsObjectInfo graphicsObjectInfo = createGraphicsObjectInfo( + paintingState, painter, userAgent, resourceInfo, g2d); + graphicsObjectInfo.setObjectAreaInfo(objectAreaInfo); + + // Create the GOCA GraphicsObject in the DataStream + AFPResourceManager resourceManager = afpInfo.getResourceManager(); + resourceManager.createObject(graphicsObjectInfo); + + paintingState.restore(); // resume + } + + private AFPObjectAreaInfo createObjectAreaInfo(AFPPaintingState paintingState, + int x, int y, int width, int height, int resolution) { + // set the data object parameters + AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo(); + + AffineTransform at = paintingState.getData().getTransform(); + at.translate(x, y); + objectAreaInfo.setX((int)Math.round(at.getTranslateX())); + objectAreaInfo.setY((int)Math.round(at.getTranslateY())); + + objectAreaInfo.setWidthRes(resolution); + objectAreaInfo.setHeightRes(resolution); + + AFPUnitConverter unitConv = paintingState.getUnitConverter(); + objectAreaInfo.setWidth(Math.round(unitConv.mpt2units(width))); + objectAreaInfo.setHeight(Math.round(unitConv.mpt2units(height))); + + int rotation = paintingState.getRotation(); + objectAreaInfo.setRotation(rotation); + + return objectAreaInfo; + } + + private AFPGraphicsObjectInfo createGraphicsObjectInfo(AFPPaintingState paintingState, Graphics2DImagePainter painter, + FOUserAgent userAgent, AFPResourceInfo resourceInfo, AFPGraphics2D g2d) { + AFPGraphicsObjectInfo graphicsObjectInfo = new AFPGraphicsObjectInfo(); + + String uri = paintingState.getImageUri(); + graphicsObjectInfo.setUri(uri); + + graphicsObjectInfo.setMimeType(MimeConstants.MIME_AFP_GOCA); + + graphicsObjectInfo.setResourceInfo(resourceInfo); + + graphicsObjectInfo.setPainter(painter); + + // Set the afp graphics 2d implementation + graphicsObjectInfo.setGraphics2D(g2d); + + return graphicsObjectInfo; + } + + public static BridgeContext createBridgeContext(FOUserAgent userAgent, AFPGraphics2D g2d) { + ImageManager imageManager = userAgent.getFactory().getImageManager(); + + SVGUserAgent svgUserAgent + = new SVGUserAgent(userAgent, new AffineTransform()); + + ImageSessionContext imageSessionContext = userAgent.getImageSessionContext(); + + FontInfo fontInfo = g2d.getFontInfo(); + return new AFPBridgeContext(svgUserAgent, fontInfo, imageManager, imageSessionContext, + new AffineTransform(), g2d); + } + /** {@inheritDoc} */ public boolean supportsRenderer(Renderer renderer) { return (renderer instanceof AFPRenderer); @@ -39,9 +214,29 @@ public class AFPSVGHandler extends AbstractGenericSVGHandler { /** {@inheritDoc} */ protected void updateRendererContext(RendererContext context) { //Work around a problem in Batik: Gradients cannot be done in ColorSpace.CS_GRAY - context.setProperty(AFPRendererContextConstants.AFP_GRAYSCALE, - Boolean.FALSE); + context.setProperty(AFPRendererContextConstants.AFP_GRAYSCALE, Boolean.FALSE); } -} + /** {@inheritDoc} */ + protected Graphics2DImagePainter createGrapics2DImagePainter(BridgeContext ctx, GraphicsNode root, Dimension imageSize) { + Graphics2DImagePainter painter = null; + if (paintAsBitmap()) { + // paint as IOCA Image + painter = super.createGraphics2DImagePainter(root, ctx, imageSize); + } else { + // paint as GOCA Graphics + painter = new Graphics2DImagePainterImpl(root, ctx, imageSize); + } + return painter; + } + /** + * Returns true if the SVG is to be painted as a bitmap + * + * @return true if the SVG is to be painted as a bitmap + */ + private boolean paintAsBitmap() { + return paintAsBitmap; + } + +} diff --git a/src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java b/src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java new file mode 100644 index 000000000..ae8ac9950 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java @@ -0,0 +1,79 @@ +/* + * 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.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; +import org.apache.fop.afp.AFPDataObjectInfo; +import org.apache.fop.afp.AFPObjectAreaInfo; +import org.apache.fop.afp.AFPPaintingState; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageSize; +import org.apache.xmlgraphics.image.loader.impl.ImageRawStream; + +/** + * A base abstract AFP raw stream image handler + */ +public abstract class AbstractAFPImageHandlerRawStream extends AFPImageHandler { + + /** {@inheritDoc} */ + public AFPDataObjectInfo generateDataObjectInfo( + AFPRendererImageInfo rendererImageInfo) throws IOException { + AFPDataObjectInfo dataObjectInfo = super.generateDataObjectInfo(rendererImageInfo); + + ImageInfo imageInfo = rendererImageInfo.getImageInfo(); + String mimeType = imageInfo.getMimeType(); + if (mimeType != null) { + dataObjectInfo.setMimeType(mimeType); + } + ImageRawStream rawStream = (ImageRawStream) rendererImageInfo.getImage(); + InputStream inputStream = rawStream.createInputStream(); + try { + dataObjectInfo.setData(IOUtils.toByteArray(inputStream)); + } finally { + IOUtils.closeQuietly(inputStream); + } + + int dataHeight = rawStream.getSize().getHeightPx(); + dataObjectInfo.setDataHeight(dataHeight); + + int dataWidth = rawStream.getSize().getWidthPx(); + dataObjectInfo.setDataWidth(dataWidth); + + ImageSize imageSize = rawStream.getSize(); + dataObjectInfo.setDataHeightRes((int) (imageSize.getDpiHorizontal() * 10)); + dataObjectInfo.setDataWidthRes((int) (imageSize.getDpiVertical() * 10)); + + // set object area info + AFPObjectAreaInfo objectAreaInfo = dataObjectInfo.getObjectAreaInfo(); + AFPRendererContext rendererContext + = (AFPRendererContext)rendererImageInfo.getRendererContext(); + AFPInfo afpInfo = rendererContext.getInfo(); + AFPPaintingState paintingState = afpInfo.getPaintingState(); + int resolution = paintingState.getResolution(); + objectAreaInfo.setWidthRes(resolution); + objectAreaInfo.setHeightRes(resolution); + + return dataObjectInfo; + } + +} diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPAttribute.java b/src/java/org/apache/fop/render/afp/extensions/AFPAttribute.java index 665a77562..6b4bc4eb9 100755 --- a/src/java/org/apache/fop/render/afp/extensions/AFPAttribute.java +++ b/src/java/org/apache/fop/render/afp/extensions/AFPAttribute.java @@ -19,14 +19,13 @@ package org.apache.fop.render.afp.extensions; -import org.apache.fop.apps.FOPException; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.properties.Property; import org.apache.fop.fo.properties.StringProperty; /** * This class extends the org.apache.fop.fo.StringProperty.Maker inner class - * in order to provide a static property maker. The object faciliates + * in order to provide a static property maker. The object facilitates * extraction of attributes from formatted objects based on the static list * as defined in the AFPElementMapping implementation. * <p/> @@ -58,5 +57,4 @@ public class AFPAttribute extends StringProperty.Maker { } return property; } - }
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPElement.java b/src/java/org/apache/fop/render/afp/extensions/AFPElement.java index b8bfa74b6..2fdd32649 100755 --- a/src/java/org/apache/fop/render/afp/extensions/AFPElement.java +++ b/src/java/org/apache/fop/render/afp/extensions/AFPElement.java @@ -23,6 +23,7 @@ import org.apache.fop.apps.FOPException; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FONode; import org.apache.fop.fo.ValidationException; +import org.apache.fop.fo.extensions.ExtensionAttachment; /** * This class extends the org.apache.fop.extensions.ExtensionObj class. The @@ -45,13 +46,13 @@ public class AFPElement extends AbstractAFPExtensionObject { /** {@inheritDoc} */ protected void startOfNode() throws FOPException { super.startOfNode(); - //if (!AFPElementMapping.NAMESPACE.equals(parent.getNamespaceURI()) - // || !AFPElementMapping.PAGE.equals(parent.getLocalName())) { - // throw new ValidationException(getName() + " must be a child of afp:page."); - //} if (parent.getNameId() != Constants.FO_SIMPLE_PAGE_MASTER) { throw new ValidationException(getName() + " must be a child of fo:simple-page-master."); } } + /** {@inheritDoc} */ + protected ExtensionAttachment instantiateExtensionAttachment() { + return new AFPPageSetup(getName()); + } } diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPElementMapping.java b/src/java/org/apache/fop/render/afp/extensions/AFPElementMapping.java index 216379cc0..c3ba2c43b 100755 --- a/src/java/org/apache/fop/render/afp/extensions/AFPElementMapping.java +++ b/src/java/org/apache/fop/render/afp/extensions/AFPElementMapping.java @@ -19,8 +19,6 @@ package org.apache.fop.render.afp.extensions; -import java.util.HashMap; - import org.apache.fop.fo.ElementMapping; import org.apache.fop.fo.FONode; @@ -39,7 +37,7 @@ public class AFPElementMapping extends ElementMapping { public static final String PAGE = "page"; /** page group element */ - public static final String PAGE_GROUP = "page-group"; +// public static final String PAGE_GROUP = "page-group"; /** tag logical element */ public static final String TAG_LOGICAL_ELEMENT = "tag-logical-element"; @@ -53,6 +51,9 @@ public class AFPElementMapping extends ElementMapping { /** NOP */ public static final String NO_OPERATION = "no-operation"; + /** resource information (name, level, dest) */ +// public static final String RESOURCE_INFO = "resource-info"; + /** * The namespace used for AFP extensions */ @@ -69,15 +70,18 @@ public class AFPElementMapping extends ElementMapping { } /** - * Private static synchronized method to set up the element and atribute + * Private static synchronized method to set up the element and attribute * HashMaps, this defines what elements and attributes are extracted. */ protected void initialize() { if (foObjs == null) { - foObjs = new HashMap(); + super.foObjs = new java.util.HashMap(); foObjs.put(PAGE, new AFPPageSetupMaker()); - // foObjs.put(PAGE_GROUP, new AFPMaker()); +// foObjs.put( +// PAGE_GROUP, +// new AFPPageGroupMaker() +// ); foObjs.put( TAG_LOGICAL_ELEMENT, new AFPTagLogicalElementMaker()); @@ -90,8 +94,10 @@ public class AFPElementMapping extends ElementMapping { foObjs.put( NO_OPERATION, new AFPNoOperationMaker()); +// foObjs.put( +// RESOURCE_INFO, +// new AFPResourceInfoMaker()); } - } static class AFPPageSetupMaker extends ElementMapping.Maker { @@ -123,4 +129,16 @@ public class AFPElementMapping extends ElementMapping { return new AFPElement(parent, NO_OPERATION); } } + +// static class AFPResourceInfoMaker extends ElementMapping.Maker { +// public FONode make(FONode parent) { +// return new AFPResourceInfoElement(parent); +// } +// } + +// static class AFPPageGroupMaker extends ElementMapping.Maker { +// public FONode make(FONode parent) { +// return new AFPElement(parent, PAGE_GROUP); +// } +// } } diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPExtensionAttachment.java b/src/java/org/apache/fop/render/afp/extensions/AFPExtensionAttachment.java new file mode 100644 index 000000000..9a8429b00 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/extensions/AFPExtensionAttachment.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.extensions; + +import java.io.Serializable; + +import org.apache.fop.fo.extensions.ExtensionAttachment; +import org.apache.xmlgraphics.util.XMLizable; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +/** + * This is the pass-through value object for the AFP extension. + */ +public abstract class AFPExtensionAttachment + implements ExtensionAttachment, Serializable, XMLizable { + private static final long serialVersionUID = 7190606822558332901L; + + /** The category URI for this extension attachment. */ + public static final String CATEGORY = "apache:fop:extensions:afp"; + + /** + * the extension element name + */ + protected String elementName; + + /** + * the extension content + */ + protected String content; + + /** + * the extension name attribute + */ + protected String name; + + /** + * the extension value attribute + */ + protected String value; + + /** + * Default constructor. + * + * @param elementName the name of the afp extension attachment, may be null + */ + public AFPExtensionAttachment(String elementName) { + this.elementName = elementName; + } + + /** @return the name */ + public String getElementName() { + return elementName; + } + + /** + * @return true if this element has a name attribute + */ + protected boolean hasName() { + return name != null; + } + + /** @return the name */ + public String getName() { + return name; + } + + /** + * Sets the name of the setup code object. + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the value + */ + public String getValue() { + return value; + } + + /** + * Sets the value + * @param source The value name to set. + */ + public void setValue(String source) { + this.value = source; + } + + /** {@inheritDoc} */ + public String getCategory() { + return CATEGORY; + } + + /** + * @return the data + */ + public String getContent() { + return content; + } + + /** + * Sets the data + * @param content The byte data to set. + */ + public void setContent(String content) { + this.content = content; + } + + /** + * name attribute + */ + protected static final String ATT_NAME = "name"; + + /** + * value attribute + */ + protected static final String ATT_VALUE = "value"; + + /** {@inheritDoc} */ + public void toSAX(ContentHandler handler) throws SAXException { + AttributesImpl atts = new AttributesImpl(); + if (name != null && name.length() > 0) { + atts.addAttribute(null, ATT_NAME, ATT_NAME, "CDATA", name); + } + if (value != null && value.length() > 0) { + atts.addAttribute(null, ATT_VALUE, ATT_VALUE, "CDATA", value); + } + handler.startElement(CATEGORY, elementName, elementName, atts); + if (content != null && content.length() > 0) { + char[] chars = content.toCharArray(); + handler.characters(chars, 0, chars.length); + } + handler.endElement(CATEGORY, elementName, elementName); + } +} diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java b/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java index 61ad9c1e7..08989c03c 100644 --- a/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java +++ b/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java @@ -54,7 +54,7 @@ public class AFPExtensionHandler extends DefaultHandler || localName.equals(AFPElementMapping.INCLUDE_PAGE_OVERLAY) || localName.equals(AFPElementMapping.INCLUDE_PAGE_SEGMENT) || localName.equals(AFPElementMapping.PAGE) - || localName.equals(AFPElementMapping.PAGE_GROUP)) { + /*|| localName.equals(AFPElementMapping.PAGE_GROUP)*/) { //handled in endElement } else { handled = false; diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java b/src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java index 30bc217e7..998ce6921 100644 --- a/src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java +++ b/src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java @@ -19,33 +19,10 @@ package org.apache.fop.render.afp.extensions; -import java.io.Serializable; - -import org.xml.sax.ContentHandler; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.AttributesImpl; - -import org.apache.xmlgraphics.util.XMLizable; - -import org.apache.fop.fo.extensions.ExtensionAttachment; - /** * This is the pass-through value object for the PostScript extension. */ -public class AFPPageSetup implements ExtensionAttachment, Serializable, XMLizable { - - private static final long serialVersionUID = 7190606822558332901L; - - /** The category URI for this extension attachment. */ - public static final String CATEGORY = "apache:fop:extensions:afp"; - - private String elementName; - - private String name; - - private String value; - - private String content; +public class AFPPageSetup extends AFPExtensionAttachment { /** * Default constructor. @@ -53,85 +30,16 @@ public class AFPPageSetup implements ExtensionAttachment, Serializable, XMLizabl * @param elementName the name of the setup code object, may be null */ public AFPPageSetup(String elementName) { - this.elementName = elementName; - } - - /** @return the name */ - public String getElementName() { - return elementName; - } - - /** @return the name */ - public String getName() { - return name; - } - - /** - * Sets the name of the setup code object. - * @param name The name to set. - */ - public void setName(String name) { - this.name = name; + super(elementName); } - /** - * @return the value - */ - public String getValue() { - return value; - } - - /** - * Sets the value - * @param source The value name to set. - */ - public void setValue(String source) { - this.value = source; - } - - /** {@inheritDoc} */ - public String getCategory() { - return CATEGORY; - } + private static final long serialVersionUID = -549941295384013190L; /** - * @return the data + * {@inheritDoc} */ - public String getContent() { - return content; - } - - /** - * Sets the data - * @param content The byte data to set. - */ - public void setContent(String content) { - this.content = content; - } - - /** {@inheritDoc} */ public String toString() { return "AFPPageSetup(element-name=" + getElementName() + " name=" + getName() + " value=" + getValue() + ")"; } - - private static final String ATT_NAME = "name"; - private static final String ATT_VALUE = "value"; - - /** {@inheritDoc} */ - public void toSAX(ContentHandler handler) throws SAXException { - AttributesImpl atts = new AttributesImpl(); - if (name != null && name.length() > 0) { - atts.addAttribute(null, ATT_NAME, ATT_NAME, "CDATA", name); - } - if (value != null && value.length() > 0) { - atts.addAttribute(null, ATT_VALUE, ATT_VALUE, "CDATA", value); - } - handler.startElement(CATEGORY, elementName, elementName, atts); - if (content != null && content.length() > 0) { - char[] chars = content.toCharArray(); - handler.characters(chars, 0, chars.length); - } - handler.endElement(CATEGORY, elementName, elementName); - } } diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java b/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java index 4971928f8..d167a8d4b 100644 --- a/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java +++ b/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java @@ -23,9 +23,10 @@ import org.apache.fop.apps.FOPException; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FONode; import org.apache.fop.fo.ValidationException; +import org.apache.fop.fo.extensions.ExtensionAttachment; /** - * Extension element for fox:ps-page-setup-code. + * Extension element for afp:ps-page-setup-code. */ public class AFPPageSetupElement extends AbstractAFPExtensionObject { @@ -45,4 +46,10 @@ public class AFPPageSetupElement extends AbstractAFPExtensionObject { } } + /** + * {@inheritDoc} + */ + protected ExtensionAttachment instantiateExtensionAttachment() { + return new AFPPageSetup(this.name); + } } diff --git a/src/java/org/apache/fop/render/afp/extensions/AbstractAFPExtensionObject.java b/src/java/org/apache/fop/render/afp/extensions/AbstractAFPExtensionObject.java index a92687aab..c0e9c2c89 100644 --- a/src/java/org/apache/fop/render/afp/extensions/AbstractAFPExtensionObject.java +++ b/src/java/org/apache/fop/render/afp/extensions/AbstractAFPExtensionObject.java @@ -35,11 +35,14 @@ import org.apache.fop.fo.extensions.ExtensionAttachment; public abstract class AbstractAFPExtensionObject extends FONode { /** - * AFP setup code + * the AFP extension attachment */ - private AFPPageSetup setupCode; + protected AFPExtensionAttachment extensionAttachment; - private String name; + /** + * the element name of this extension + */ + protected String name; /** * @see org.apache.fop.fo.FONode#FONode(FONode) @@ -49,10 +52,11 @@ public abstract class AbstractAFPExtensionObject extends FONode { public AbstractAFPExtensionObject(FONode parent, String name) { super(parent); this.name = name; - this.setupCode = new AFPPageSetup(name); } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ protected void validateChildNode(Locator loc, String nsURI, String localName) throws ValidationException { if (FO_URI.equals(nsURI)) { @@ -60,60 +64,85 @@ public abstract class AbstractAFPExtensionObject extends FONode { } } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ protected void characters(char[] data, int start, int length, - PropertyList pList, Locator locator) { - setupCode.setContent(new String(data, start, length)); + PropertyList pList, Locator locator) throws FOPException { + ((AFPExtensionAttachment)getExtensionAttachment()).setContent( + new String(data, start, length)); } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ public String getNamespaceURI() { return AFPElementMapping.NAMESPACE; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ public String getNormalNamespacePrefix() { return AFPElementMapping.NAMESPACE_PREFIX; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList propertyList) throws FOPException { - String name = attlist.getValue("name"); - if (name != null && name.length() > 0) { - setupCode.setName(name); + getExtensionAttachment(); + String attr = attlist.getValue("name"); + if (attr != null && attr.length() > 0) { + extensionAttachment.setName(attr); } else { throw new FOPException(elementName + " must have a name attribute."); } if (AFPElementMapping.INCLUDE_PAGE_SEGMENT.equals(elementName)) { - name = attlist.getValue("src"); - if (name != null && name.length() > 0) { - setupCode.setValue(name); + attr = attlist.getValue("src"); + if (attr != null && attr.length() > 0) { + extensionAttachment.setValue(attr); } else { throw new FOPException(elementName + " must have a src attribute."); } } else if (AFPElementMapping.TAG_LOGICAL_ELEMENT.equals(elementName)) { - name = attlist.getValue("value"); - if (name != null && name.length() > 0) { - setupCode.setValue(name); + attr = attlist.getValue("value"); + if (attr != null && attr.length() > 0) { + extensionAttachment.setValue(attr); } else { throw new FOPException(elementName + " must have a value attribute."); } } } - - /** {@inheritDoc} */ + + /** + * {@inheritDoc} + */ protected void endOfNode() throws FOPException { super.endOfNode(); } - /** {@inheritDoc} */ + /** + * Instantiates extension attachment object + * @return extension attachment + */ + protected abstract ExtensionAttachment instantiateExtensionAttachment(); + + /** + * {@inheritDoc} + */ public ExtensionAttachment getExtensionAttachment() { - return this.setupCode; + if (extensionAttachment == null) { + this.extensionAttachment = (AFPExtensionAttachment)instantiateExtensionAttachment(); + } + return this.extensionAttachment; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ public String getLocalName() { return name; } diff --git a/src/java/org/apache/fop/render/afp/fonts/AFPFontCollection.java b/src/java/org/apache/fop/render/afp/fonts/AFPFontCollection.java deleted file mode 100644 index 03b5580cf..000000000 --- a/src/java/org/apache/fop/render/afp/fonts/AFPFontCollection.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.fonts; - -import java.util.Iterator; -import java.util.List; - -import org.apache.fop.events.EventBroadcaster; -import org.apache.fop.fonts.Font; -import org.apache.fop.fonts.FontCollection; -import org.apache.fop.fonts.FontInfo; -import org.apache.fop.fonts.FontTriplet; -import org.apache.fop.fonts.base14.Courier; -import org.apache.fop.fonts.base14.Helvetica; -import org.apache.fop.fonts.base14.TimesRoman; -import org.apache.fop.render.afp.AFPEventProducer; - -/** - * A base collection of AFP fonts - */ -public class AFPFontCollection implements FontCollection { - - private EventBroadcaster eventBroadcaster; - private List/*<EmbedFontInfo>*/ embedFontInfoList; - - /** - * Main constructor - * - * @param eventBroadcaster the event broadcaster - * @param embedFontInfoList the embed font info list - */ - public AFPFontCollection(EventBroadcaster eventBroadcaster, - List/*<EmbedFontInfo>*/ embedFontInfoList) { - this.eventBroadcaster = eventBroadcaster; - this.embedFontInfoList = embedFontInfoList; - } - - /** {@inheritDoc} */ - public int setup(int start, FontInfo fontInfo) { - int num = 1; - if (embedFontInfoList != null && embedFontInfoList.size() > 0) { - for (Iterator it = embedFontInfoList.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(); - fontInfo.addFontProperties("F" + num, ft.getName() - , ft.getStyle(), ft.getWeight()); - fontInfo.addMetrics("F" + num, bf); - num++; - } - } - } else { - AFPEventProducer eventProducer = AFPEventProducer.Provider.get(eventBroadcaster); - eventProducer.warnDefaultFontSetup(this); - } - if (fontInfo.fontLookup("sans-serif", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL) == null) { - CharacterSet cs = new FopCharacterSet("T1V10500", "Cp500", "CZH200 ", - 1, new Helvetica()); - AFPFont bf = new OutlineFont("Helvetica", cs); - fontInfo.addFontProperties( - "F" + num, "sans-serif", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addMetrics("F" + num, bf); - num++; - } - if (fontInfo.fontLookup("serif", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL) == null) { - CharacterSet cs = new FopCharacterSet("T1V10500", "Cp500", "CZN200 ", - 1, new TimesRoman()); - AFPFont bf = new OutlineFont("Helvetica", cs); - fontInfo.addFontProperties("F" + num, "serif", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addMetrics("F" + num, bf); - num++; - } - if (fontInfo.fontLookup("monospace", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL) == null) { - CharacterSet cs = new FopCharacterSet("T1V10500", "Cp500", "CZ4200 ", - 1, new Courier()); - AFPFont bf = new OutlineFont("Helvetica", cs); - fontInfo.addFontProperties( - "F" + num, "monospace", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addMetrics("F" + num, bf); - num++; - } - if (fontInfo.fontLookup("any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL) == null) { - FontTriplet ft = fontInfo.fontLookup( - "sans-serif", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties( - fontInfo.getInternalFontKey(ft), "any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - num++; - } - return num; - } - -} diff --git a/src/java/org/apache/fop/render/afp/modca/AFPDataStream.java b/src/java/org/apache/fop/render/afp/modca/AFPDataStream.java deleted file mode 100644 index 0c60ec1d7..000000000 --- a/src/java/org/apache/fop/render/afp/modca/AFPDataStream.java +++ /dev/null @@ -1,701 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; - -import java.awt.Color; -import java.io.IOException; -import java.io.OutputStream; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.fop.render.afp.fonts.AFPFont; -import org.apache.fop.render.afp.tools.StringUtils; - -/** - * A data stream is a continuous ordered stream of data elements and objects - * conforming to a given format. Application programs can generate data streams - * destined for a presentation service, archive library, presentation device or - * another application program. The strategic presentation data stream - * architectures used is Mixed Object Document Content Architecture (MO:DCA�). - * - * The MO:DCA architecture defines the data stream used by applications to - * describe documents and object envelopes for interchange with other - * applications and application services. Documents defined in the MO:DCA format - * may be archived in a database, then later retrieved, viewed, annotated and - * printed in local or distributed systems environments. Presentation fidelity - * is accommodated by including resource objects in the documents that reference - * them. - * - */ -public class AFPDataStream { - - /** - * Static logging instance - */ - protected static Log log = LogFactory.getLog("org.apache.fop.render.afp.modca"); - - /** - * Boolean completion indicator - */ - private boolean complete = false; - - /** - * The application producing the AFP document - */ -// not used -// private String producer = null; - - /** - * The AFP document object - */ - private Document document = null; - - /** - * The current page group object - */ - private PageGroup currentPageGroup = null; - - /** - * The current page object - */ - private PageObject currentPageObject = null; - - /** - * The current overlay object - */ - private Overlay currentOverlay = null; - - /** - * The current page - */ - private AbstractPageObject currentPage = null; - - /** - * The page count - */ - private int pageCount = 0; - - /** - * The page group count - */ -// not used -// private int pageGroupCount = 0; - - /** - * The overlay count - */ - private int ovlCount = 0; - - /** - * The portrait rotation - */ - private int portraitRotation = 0; - - /** - * The landscape rotation - */ - private int landscapeRotation = 270; - - /** - * The x offset - */ - private int xOffset = 0; - - /** - * The y offset - */ - private int yOffset = 0; - - /** - * The rotation - */ - private int rotation; - - /** - * The outputstream for the data stream - */ - private OutputStream outputStream = null; - - /** - * Default constructor for the AFPDataStream. - */ - public AFPDataStream() { - } - - /** - * The document is started by invoking this method which creates an instance - * of the AFP Document object. - * - * @param docOutputStream - * 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); - throw new IllegalStateException(msg); - } - - this.document = new Document(); - this.outputStream = docOutputStream; - - } - - /** - * The document is ended by invoking this method which creates an instance - * of the AFP Document object and registers the start with a validation map - * which ensures that methods are not invoked out of the correct sequence. - * - * @throws java.io.IOException - * 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); - throw new IllegalStateException(msg); - } - - if (currentPageObject != null) { - // End the current page if necessary - endPage(); - } - - if (currentPageGroup != null) { - // End the current page group if necessary - endPageGroup(); - } - - document.endDocument(); - document.writeDataStream(this.outputStream); - this.outputStream.flush(); - - complete = true; - - document = null; - - this.outputStream = null; - } - - /** - * Start a new page. When processing has finished on the current page, the - * {@link #endPage()}method must be invoked to mark the page ending. - * - * @param pageWidth - * the width of the page - * @param pageHeight - * the height of the page - * @param pageRotation - * the rotation of the page - * @param pageWidthResolution - * the width resolution of the page - * @param pageHeightResolution - * the height resolution of the page - */ - public void startPage(int pageWidth, int pageHeight, int pageRotation, - int pageWidthResolution, int pageHeightResolution) { - - String pageName = "PGN" - + StringUtils.lpad(String.valueOf(pageCount++), '0', 5); - - currentPageObject = new PageObject(pageName, pageWidth, pageHeight, - pageRotation, pageWidthResolution, pageHeightResolution); - currentPage = currentPageObject; - currentOverlay = null; - setOffsets(0, 0, 0); - } - - /** - * Start a new overlay. When processing has finished on the current overlay, - * the {@link #endOverlay()}method must be invoked to mark the overlay - * ending. - * - * @param overlayX - * the x position of the overlay on the page - * @param overlayY - * the y position of the overlay on the page - * @param overlayWidth - * the width of the overlay - * @param overlayHeight - * the height of the overlay - * @param overlayWidthResolution - * the width resolution of the overlay - * @param overlayHeightResolution - * the height resolution of the overlay - * @param overlayRotation - * the rotation of the overlay - */ - public void startOverlay(int overlayX, int overlayY, int overlayWidth, - int overlayHeight, int overlayWidthResolution, - int overlayHeightResolution, int overlayRotation) { - - String overlayName = "OVL" - + StringUtils.lpad(String.valueOf(ovlCount++), '0', 5); - - currentOverlay = new Overlay(overlayName, overlayWidth, overlayHeight, - overlayWidthResolution, overlayHeightResolution, - overlayRotation); - currentPageObject.addOverlay(currentOverlay); - currentPageObject.createIncludePageOverlay(overlayName, overlayX, - overlayY, 0); - currentPage = currentOverlay; - setOffsets(0, 0, 0); - } - - /** - * Helper method to mark the end of the current overlay. - */ - public void endOverlay() { - - currentOverlay.endPage(); - currentOverlay = null; - currentPage = currentPageObject; - - } - - /** - * Helper method to save the current page. - * - * @return current page object that was saved - */ - public PageObject savePage() { - - PageObject pageObject = currentPageObject; - if (currentPageGroup != null) { - currentPageGroup.addPage(currentPageObject); - } else { - document.addPage(currentPageObject); - } - currentPageObject = null; - currentPage = null; - return pageObject; - - } - - /** - * Helper method to restore the current page. - * - * @param pageObject - * page object - */ - public void restorePage(PageObject pageObject) { - - currentPageObject = pageObject; - currentPage = pageObject; - - } - - /** - * Helper method to mark the end of the current page. - * - * @throws java.io.IOException - * thrown when an I/O exception of some sort has occurred - */ - public void endPage() throws IOException { - - currentPageObject.endPage(); - if (currentPageGroup != null) { - currentPageGroup.addPage(currentPageObject); - } else { - document.addPage(currentPageObject); - document.writeDataStream(this.outputStream); - } - - currentPageObject = null; - currentPage = null; - - } - - /** - * Sets the offsets to be used for element positioning - * - * @param xOff - * the offset in the x direction - * @param yOff - * the offset in the y direction - * @param rot - * the rotation - */ - public void setOffsets(int xOff, int yOff, int rot) { - this.xOffset = xOff; - this.yOffset = yOff; - this.rotation = rot; - } - - /** - * 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. - * - * @param fontReference - * the font number used as the resource identifier - * @param font - * the font - * @param size - * the point size of the font - */ - public void createFont(byte 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 x - * the x coordinate of the text - * @param y - * the y coordinate of the text - * @param col - * the text color - * @param vsci - * The variable space character increment. - * @param ica - * The inter character adjustment. - * @param data - * the text data to create - */ - public void createText(int fontNumber, int x, int y, Color col, int vsci, - int ica, byte[] data) { - - currentPage.createText(fontNumber, 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 - * the width of the image - * @param h - * the height of the image - * @param wr - * the width resolution of the image - * @param hr - * the height resolution of the image - * @return ImageObject used to create an image in the datastream - */ - public ImageObject getImageObject(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) { - case 90: - xOrigin = currentPage.getWidth() - y - yOffset; - yOrigin = x + xOffset; - width = h; - height = w; - widthResolution = hr; - heightResolution = wr; - break; - case 180: - xOrigin = currentPage.getWidth() - x - xOffset; - yOrigin = currentPage.getHeight() - y - yOffset; - width = w; - height = h; - widthResolution = wr; - heightResolution = hr; - break; - case 270: - xOrigin = y + yOffset; - yOrigin = currentPage.getHeight() - x - xOffset; - width = h; - height = w; - widthResolution = hr; - heightResolution = wr; - break; - default: - xOrigin = x + xOffset; - yOrigin = y + yOffset; - width = w; - height = h; - widthResolution = wr; - heightResolution = hr; - break; - } - ImageObject io = currentPage.getImageObject(); - io.setImageViewport(xOrigin, yOrigin, width, height, rotation, - widthResolution, heightResolution); - return io; - - } - - /** - * Method to create a line on the current page. - * - * @param x1 - * the first x coordinate of the line - * @param y1 - * the first y coordinate of the line - * @param x2 - * the second x coordinate of the line - * @param y2 - * the second y coordinate of the line - * @param thickness - * the thickness of the line - * @param col - * The text color. - */ - 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); - - } - - /** - * This method will create shading on the page using the specified - * coordinates (the shading contrast is controlled via the red, green, blue - * parameters, by converting this to grey scale). - * - * @param x - * the x coordinate of the shading - * @param y - * the y coordinate of the shading - * @param w - * the width of the shaded area - * @param h - * the height of the shaded area - * @param red - * the red value - * @param green - * the green value - * @param blue - * the blue value - */ - 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); - - } - - /** - * Helper method which allows creation of the MPO object, via the AEG. And - * the IPO via the Page. (See actual object for descriptions.) - * - * @param name - * the name of the static overlay - */ - public void createIncludePageOverlay(String name) { - - currentPageObject.createIncludePageOverlay(name, 0, 0, rotation); - ActiveEnvironmentGroup aeg = currentPageObject - .getActiveEnvironmentGroup(); - aeg.createOverlay(name); - - } - - /** - * Helper method which allows creation of the IMM object. - * - * @param name - * the name of the medium map - */ - public void createInvokeMediumMap(String name) { - - if (currentPageGroup == null) { - startPageGroup(); - } - currentPageGroup.createInvokeMediumMap(name); - - } - - /** - * Creates an IncludePageSegment on the current page. - * - * @param name - * the name of the include page segment - * @param x - * the x coordinate for the overlay - * @param y - * the y coordinate for the overlay - */ - public void createIncludePageSegment(String name, int x, int y) { - - int xOrigin; - int yOrigin; - switch (rotation) { - case 90: - xOrigin = currentPage.getWidth() - y - yOffset; - yOrigin = x + xOffset; - break; - case 180: - xOrigin = currentPage.getWidth() - x - xOffset; - yOrigin = currentPage.getHeight() - y - yOffset; - break; - case 270: - xOrigin = y + yOffset; - yOrigin = currentPage.getHeight() - x - xOffset; - break; - default: - xOrigin = x + xOffset; - yOrigin = y + yOffset; - break; - } - currentPage.createIncludePageSegment(name, xOrigin, yOrigin); - - } - - /** - * Creates a TagLogicalElement on the current page. - * - * @param attributes - * 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); - } - - } - - /** - * Creates a TagLogicalElement on the current page group. - * - * @param attributes - * the array of key value pairs. - */ - 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); - } - - } - - /** - * Creates a TagLogicalElement on the current page or page group - * - * @param name - * The tag name - * @param value - * The tag value - */ - public void createTagLogicalElement(String name, String value) { - - if (currentPageGroup != null) { - currentPageGroup.createTagLogicalElement(name, value); - } else { - currentPage.createTagLogicalElement(name, value); - } - - } - - /** - * Creates a NoOperation item - * - * @param content - * byte data - */ - public void createNoOperation(String content) { - currentPage.createNoOperation(content); - } - - /** - * Start a new page group. When processing has finished on the current page - * group the {@link #endPageGroup()}method must be invoked to mark the page - * group ending. - */ - public void startPageGroup() { - - String pageGroupName = "PGP" - + StringUtils.lpad(String.valueOf(pageCount++), '0', 5); - - currentPageGroup = new PageGroup(pageGroupName); - - } - - /** - * Helper method to mark the end of the page group. - * @throws IOException thrown if an I/O exception of some sort has occurred - */ - public void endPageGroup() throws IOException { - - currentPageGroup.endPageGroup(); - document.addPageGroup(currentPageGroup); - document.writeDataStream(outputStream); - currentPageGroup = null; - - } - - /** - * Sets the rotation to be used for portrait pages, valid values are 0 - * (default), 90, 180, 270. - * - * @param pageRotation - * The rotation in degrees. - */ - public void setPortraitRotation(int pageRotation) { - - if (pageRotation == 0 || pageRotation == 90 || pageRotation == 180 - || pageRotation == 270) { - this.portraitRotation = pageRotation; - } else { - throw new IllegalArgumentException( - "The portrait rotation must be one of the values 0, 90, 180, 270"); - } - - } - - /** - * Sets the rotation to be used for landscape pages, valid values are 0, 90, - * 180, 270 (default). - * - * @param pageRotation - * The rotation in degrees. - */ - public void setLandscapeRotation(int pageRotation) { - - if (pageRotation == 0 || pageRotation == 90 || pageRotation == 180 - || pageRotation == 270) { - this.landscapeRotation = pageRotation; - } else { - throw new IllegalArgumentException( - "The landscape rotation must be one of the values 0, 90, 180, 270"); - } - - } - -} diff --git a/src/java/org/apache/fop/render/afp/modca/AbstractAFPObject.java b/src/java/org/apache/fop/render/afp/modca/AbstractAFPObject.java deleted file mode 100644 index ef1b988c0..000000000 --- a/src/java/org/apache/fop/render/afp/modca/AbstractAFPObject.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Iterator; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This is the base class for all data stream objects. Page objects are - * responsible for building and generating the binary datastream in an - * AFP format. - * - */ -public abstract class AbstractAFPObject { - - /** - * Static logging instance - */ - protected static final Log log = LogFactory.getLog("org.apache.fop.render.afp.modca"); - - /** - * DataStream objects must implement the writeDataStream() - * method to write its data to the given OutputStream - * @param os The outputsteam stream - * @throws java.io.IOException - */ - public abstract void writeDataStream(OutputStream os) throws IOException; - - /** - * 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 - */ - protected void writeObjectList(List afpObjects, OutputStream os) - throws IOException { - - for (Iterator it = afpObjects.iterator(); it.hasNext(); ) { - ((AbstractAFPObject)it.next()).writeDataStream(os); - } - - } - -} diff --git a/src/java/org/apache/fop/render/afp/modca/AbstractNamedAFPObject.java b/src/java/org/apache/fop/render/afp/modca/AbstractNamedAFPObject.java deleted file mode 100644 index 85552a9e9..000000000 --- a/src/java/org/apache/fop/render/afp/modca/AbstractNamedAFPObject.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; -import java.io.UnsupportedEncodingException; - -/** - * This is the base class for all named data stream objects. - * A named data stream object has an 8 byte EBCIDIC name. - */ -public abstract class AbstractNamedAFPObject extends AbstractAFPObject { - - /** - * The actual name of the object - */ - protected String name = null; - - /** - * The name of the object in EBCIDIC bytes - */ - protected byte[] nameBytes; - - /** - * 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); - } - - try { - - nameBytes = name.getBytes(AFPConstants.EBCIDIC_ENCODING); - - } catch (UnsupportedEncodingException usee) { - - 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 deleted file mode 100644 index a99b28107..000000000 --- a/src/java/org/apache/fop/render/afp/modca/AbstractPageObject.java +++ /dev/null @@ -1,435 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; - -import java.awt.Color; -import java.util.ArrayList; -import java.util.List; - -import org.apache.fop.render.afp.fonts.AFPFont; -import org.apache.fop.render.afp.tools.StringUtils; - -/** - * Pages contain the data objects that comprise a presentation document. Each - * page has a set of data objects associated with it. Each page within a - * document is independent from any other page, and each must establish its own - * environment parameters. - * - * The page is the level in the document component hierarchy that is used for - * printing or displaying a document's content. The data objects contained in - * the page envelope in the data stream are presented when the page is - * presented. Each data object has layout information associated with it that - * directs the placement and orientation of the data on the page. In addition, - * each page contains layout information that specifies the measurement units, - * page width, and page depth. - * - * A page is initiated by a begin page structured field and terminated by an end - * page structured field. Structured fields that define objects and active - * environment groups or that specify attributes of the page may be encountered - * in page state. - * - */ -public abstract class AbstractPageObject extends AbstractNamedAFPObject { - - /** - * The active environment group for the page - */ - protected ActiveEnvironmentGroup activeEnvironmentGroup = null; - - /** - * The presentation text object, we only have one per page - */ - private PresentationTextObject presentationTextObject = null; - - /** - * The list of objects within the page - */ - protected List objects = new ArrayList(); - - /** - * The list of tag logical elements - */ - protected ArrayList tagLogicalElements = new ArrayList(); - - /** - * The list of the include page segments - */ - protected ArrayList segments = new ArrayList(); - - /** - * The page width - */ - private int width; - - /** - * The page height - */ - private int height; - - /** - * The page rotation - */ - private int rotation = 0; - - /** - * The page state - */ - private boolean complete = false; - - /** - * Construct a new page object for the specified name argument, the page - * name should be an 8 character identifier. - * - * @param name - * the name of the page. - * @param width - * the width of the page. - * @param height - * the height of the page. - * @param rotation - * the rotation of the page. - * @param widthResolution - * the width resolution of the page. - * @param heightResolution - * the height resolution of the page. - */ - public AbstractPageObject(String name, int width, int height, int rotation, - int widthResolution, int heightResolution) { - - super(name); - this.width = width; - this.height = height; - this.rotation = rotation; - - /** - * Every page object must have an ActiveEnvironmentGroup - */ - activeEnvironmentGroup = new ActiveEnvironmentGroup(width, height, - widthResolution, heightResolution); - - if (rotation != 0) { - switch (rotation) { - case 90: - activeEnvironmentGroup.setPosition(width, 0, rotation); - break; - case 180: - activeEnvironmentGroup.setPosition(width, height, rotation); - break; - case 270: - activeEnvironmentGroup.setPosition(0, height, rotation); - break; - default: - } - } - - /** - * We have a presentation text object per page - */ - presentationTextObject = new PresentationTextObject(); - objects.add(presentationTextObject); - - } - - /** - * 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 page. - * - * @param fontReference - * the font number used as the resource identifier - * @param font - * the font - * @param size - * the point size of the font - */ - public void createFont(byte fontReference, AFPFont font, int size) { - - activeEnvironmentGroup.createFont(fontReference, font, size, 0); - - } - - /** - * Helper method to create a line on the current page, this method delegates - * to the presentation text object in order to construct the line. - * - * @param x1 - * the first x coordinate of the line - * @param y1 - * the first y coordinate of the line - * @param x2 - * the second x coordinate of the line - * @param y2 - * the second y coordinate of the line - * @param thickness - * the thickness of the line - * @param lineRotation - * the rotation of the line - * @param col - * The text color. - */ - 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); - - } - - /** - * 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 - * the font number used as the resource identifier - * @param x - * the x coordinate of the text data - * @param y - * the y coordinate of the text data - * @param textRotation - * the rotation of the text data - * @param col - * the text color - * @param vsci - * The variable space character increment. - * @param ica - * The inter character adjustment. - * @param data - * the text data to create - */ - public void createText(int fontNumber, 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); - - } - - /** - * Helper method to mark the end of the page. This should end the control - * sequence on the current presenation text object. - */ - public void endPage() { - - if (presentationTextObject != null) { - presentationTextObject.endControlSequence(); - } - - complete = true; - - } - - /** - * This method will create shading on the page using the specified - * coordinates (the shading contrast is controlled via the red, green blue - * parameters, by converting this to grey scale). - * - * @param x - * the x coordinate of the shading - * @param y - * the y coordinate of the shading - * @param w - * the width of the shaded area - * @param h - * the height of the shaded area - * @param red - * the red value - * @param green - * the green value - * @param blue - * the blue value - */ - public void createShading(int x, int y, int w, int h, int red, int green, - int blue) { - - int xCoord = 0; - int yCoord = 0; - int areaWidth = 0; - int areaHeight = 0; - - switch (rotation) { - case 90: - xCoord = areaWidth - y - h; - yCoord = x; - areaWidth = h; - areaHeight = w; - break; - case 180: - xCoord = areaWidth - x - w; - yCoord = areaHeight - y - h; - areaWidth = w; - areaHeight = h; - break; - case 270: - xCoord = y; - yCoord = areaHeight - x - w; - areaWidth = h; - areaHeight = w; - break; - default: - xCoord = x; - yCoord = y; - areaWidth = w; - areaHeight = h; - break; - } - - // Convert the color to grey scale - float shade = (float) ((red * 0.3) + (green * 0.59) + (blue * 0.11)); - - int greyscale = Math.round((shade / 255) * 16); - - String imageName = "IMG" - + StringUtils.lpad(String.valueOf(objects.size() + 1), - '0', 5); - - IMImageObject io = new IMImageObject(imageName); - ImageOutputControl ioc = new ImageOutputControl(0, 0); - ImageInputDescriptor iid = new ImageInputDescriptor(); - ImageCellPosition icp = new ImageCellPosition(xCoord, yCoord); - icp.setXFillSize(areaWidth); - icp.setYFillSize(areaHeight); - icp.setXSize(64); - icp.setYSize(8); - - //defining this as a resource - ImageRasterData ird = new ImageRasterData(ImageRasterPattern - .getRasterData(greyscale)); - - io.setImageOutputControl(ioc); - io.setImageInputDescriptor(iid); - io.setImageCellPosition(icp); - io.setImageRasterData(ird); - objects.add(io); - - } - - /** - * Helper method to create an image on the current page and to return - * the object. - * @return the image object - */ - public ImageObject getImageObject() { - - if (presentationTextObject != null) { - presentationTextObject.endControlSequence(); - } - presentationTextObject = null; - - String imageName = "IMG" - + StringUtils.lpad(String.valueOf(objects.size() + 1), - '0', 5); - - ImageObject io = new ImageObject(imageName); - objects.add(io); - return io; - } - - /** - * Creates a TagLogicalElement on the page. - * - * @param name - * the name of the tag - * @param value - * the value of the tag - */ - public void createTagLogicalElement(String name, String value) { - - TagLogicalElement tle = new TagLogicalElement(name, value); - tagLogicalElements.add(tle); - - } - - /** - * Creates a NoOperation on the page. - * - * @param content the byte data - */ - public void createNoOperation(String content) { - - NoOperation noOp = new NoOperation(content); - objects.add(noOp); - - } - - /** - * Creates an IncludePageSegment on the current page. - * - * @param name - * the name of the page segment - * @param xCoor - * the x cooridinate of the page segment. - * @param yCoor - * the y cooridinate of the page segment. - */ - public void createIncludePageSegment(String name, int xCoor, int yCoor) { - - IncludePageSegment ips = new IncludePageSegment(name, xCoor, yCoor); - segments.add(ips); - - } - - /** - * Returns the ActiveEnvironmentGroup associated with this page. - * - * @return the ActiveEnvironmentGroup object - */ - public ActiveEnvironmentGroup getActiveEnvironmentGroup() { - return activeEnvironmentGroup; - } - - /** - * Returns an indication if the page is complete - * @return whether this page is complete - */ - public boolean isComplete() { - return complete; - } - - /** - * Returns the height of the page - * @return the height of the page - */ - public int getHeight() { - return height; - } - - /** - * Returns the width of the page - * @return the width of the page - */ - public int getWidth() { - return width; - } - - /** - * Returns the rotation of the page - * @return the rotation of the page - */ - public int getRotation() { - return rotation; - } - -} diff --git a/src/java/org/apache/fop/render/afp/modca/ActiveEnvironmentGroup.java b/src/java/org/apache/fop/render/afp/modca/ActiveEnvironmentGroup.java deleted file mode 100644 index 3e341c735..000000000 --- a/src/java/org/apache/fop/render/afp/modca/ActiveEnvironmentGroup.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; - -import org.apache.fop.render.afp.fonts.AFPFont; - -/** - * An Active Environment Group (AEG) is associated with each page, - * and is contained in the page's begin-end envelope in the data stream. - * The active environment group contains layout and formatting information - * that defines the measurement units and size of the page, and may contain - * resource information. - * - * Any objects that are required for page presentation and that are to be - * treated as resource objects must be mapped with a map structured field - * in the AEG. The scope of an active environment group is the scope of its - * containing page or overlay. - * - */ -public final class ActiveEnvironmentGroup extends AbstractNamedAFPObject { - - /** - * Default name for the active environment group - */ - private static final String DEFAULT_NAME = "AEG00001"; - - /** - * The collection of MapCodedFont objects - */ - private ArrayList mapCodedFonts = new ArrayList(); - - /** - * The Object Area Descriptor for the active environment group - */ - private ObjectAreaDescriptor objectAreaDescriptor = null; - - /** - * The Object Area Position for the active environment group - */ - private ObjectAreaPosition objectAreaPosition = null; - - /** - * The PresentationTextDescriptor for the active environment group - */ - private PresentationTextDescriptor presentationTextDataDescriptor = null; - - /** - * The PageDescriptor for the active environment group - */ - private PageDescriptor pageDescriptor = null; - - /** - * The collection of MapPageOverlay objects - */ - private ArrayList mapPageOverlays = new 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 - */ - public ActiveEnvironmentGroup(int width, int height, - int widthResolution, int heightResolution) { - - this(DEFAULT_NAME, width, height, widthResolution, heightResolution); - - } - - /** - * Constructor for the ActiveEnvironmentGroup, this takes a - * name parameter which must be 8 characters long. - * @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 - */ - public ActiveEnvironmentGroup(String name, int width, int height, - int widthResolution, int heightResolution) { - - super(name); - - // Create PageDescriptor - pageDescriptor = new PageDescriptor(width, height, widthResolution, heightResolution); - - // Create ObjectAreaDescriptor - objectAreaDescriptor = new ObjectAreaDescriptor(width, height, - widthResolution, heightResolution); - - // Create PresentationTextDataDescriptor - presentationTextDataDescriptor = new PresentationTextDescriptor(width, height, - widthResolution, heightResolution); - - } - - /** - * Set the position of the object area - * @param x the x offset - * @param y the y offset - * @param rotation the rotation - */ - public void setPosition(int x, int y, int rotation) { - - // Create ObjectAreaPosition - objectAreaPosition = new ObjectAreaPosition(x, y, rotation); - - } - - /** - * Accessor method to obtain the PageDescriptor object of the - * active environment group. - * @return the page descriptor object - */ - public PageDescriptor getPageDescriptor() { - - return pageDescriptor; - - } - - /** - * Accessor method to obtain the PresentationTextDataDescriptor object of - * the active environment group. - * @return the presentation text descriptor - */ - public PresentationTextDescriptor getPresentationTextDataDescriptor() { - - return presentationTextDataDescriptor; - - } - - /** - * Accessor method to write the AFP datastream for the active environment group. - * @param os The stream to write to - * @throws java.io.IOException throws if an I/O exception of some sort has occurred - */ - public void writeDataStream(OutputStream os) - throws IOException { - - writeStart(os); - - writeObjectList(mapCodedFonts, os); - - writeObjectList(mapPageOverlays, os); - - pageDescriptor.writeDataStream(os); - - if (objectAreaDescriptor != null && objectAreaPosition != null) { - objectAreaDescriptor.writeDataStream(os); - objectAreaPosition.writeDataStream(os); - } - - presentationTextDataDescriptor.writeDataStream(os); - - writeEnd(os); - - } - - /** - * Helper method to write the start of the active environment group. - * @param os The stream to write to - */ - private 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 - data[3] = (byte) 0xD3; // Structured field id byte 1 - data[4] = (byte) 0xA8; // Structured field id byte 2 - data[5] = (byte) 0xC9; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - - os.write(data); - - } - - /** - * Helper method to write the end of the active environment group. - * @param os The stream to write to - */ - 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) 0xC9; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - - os.write(data); - - } - - /** - * Method to create a map coded font object - * @param fontReference the font number used as the resource identifier - * @param font the font - * @param size the point size of the font - * @param orientation the orientation of the font (e.g. 0, 90, 180, 270) - */ - public void createFont( - byte fontReference, - AFPFont font, - int size, - int orientation) { - - MapCodedFont mcf = getCurrentMapCodedFont(); - - if (mcf == null) { - mcf = new MapCodedFont(); - mapCodedFonts.add(mcf); - } - - try { - - mcf.addFont( - fontReference, - font, - size, - orientation); - - } catch (MaximumSizeExceededException msee) { - - mcf = new MapCodedFont(); - mapCodedFonts.add(mcf); - - try { - - mcf.addFont( - fontReference, - font, - size, - orientation); - - } catch (MaximumSizeExceededException ex) { - - // Should never happen (but log just in case) - log.error("createFont():: resulted in a MaximumSizeExceededException"); - - } - - } - - } - - /** - * Actually creates the MPO object. - * Also creates the supporting object (an IPO) - * @param name the name of the overlay to be used - */ - public void createOverlay(String name) { - - MapPageOverlay mpo = getCurrentMapPageOverlay(); - - if (mpo == null) { - mpo = new MapPageOverlay(); - mapPageOverlays.add(mpo); - } - - try { - - mpo.addOverlay(name); - - } catch (MaximumSizeExceededException msee) { - mpo = new MapPageOverlay(); - mapPageOverlays.add(mpo); - try { - mpo.addOverlay(name); - } catch (MaximumSizeExceededException ex) { - // Should never happen (but log just in case) - log.error("createOverlay():: resulted in a MaximumSizeExceededException"); - } - } - } - - /** - * Getter method for the most recent MapCodedFont added to the - * Active Environment Group (returns null if no MapCodedFonts exist) - * @return the most recent Map Coded Font. - */ - private MapCodedFont getCurrentMapCodedFont() { - - int size = mapCodedFonts.size(); - if (size > 0) { - return (MapCodedFont) mapCodedFonts.get(mapCodedFonts.size() - 1); - } else { - return null; - } - - } - - /** - * Getter method for the most recent MapPageOverlay added to the - * Active Environment Group (returns null if no MapPageOverlay exist) - * @return the most recent Map Coded Font - */ - private MapPageOverlay getCurrentMapPageOverlay() { - - int size = mapPageOverlays.size(); - if (size > 0) { - return (MapPageOverlay) mapPageOverlays.get( - mapPageOverlays.size() - 1); - } else { - return null; - } - - } - -}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/Document.java b/src/java/org/apache/fop/render/afp/modca/Document.java deleted file mode 100644 index 3d2d40a3a..000000000 --- a/src/java/org/apache/fop/render/afp/modca/Document.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Iterator; -import java.util.List; - -/** - * The document is the highest level of the MO:DCA data-stream document - * component hierarchy. Documents can be made up of pages, and the pages, - * which are at the intermediate level, can be made up of objects. Objects - * are at the lowest level, and can be bar codes, graphics, images, and - * presentation text. - * - * At each level of the hierarchy certain sets of MO:DCA data structures, - * called structured fields, are permissible. The document, pages and objects - * are bounded by structured fields that define their beginnings and their ends. - * These structured fields, called begin-end pairs, provide an envelope for the - * data-stream components. This feature enables a processor of the data stream - * that is not fully compliant with the architecture to bypass those objects - * that are beyond its scope, and to process the data stream to the best of its - * abilities. - * - * A presentation document is one that has been formatted and is intended for - * presentation, usually on a printer or display device. A data stream containing - * a presentation document should produce the same document content in the - * same format on different printers or display devices dependent, however, - * on the capabilities of each of the printers or display devices. A presentation - * document can reference resources that are to be included as part of the - * document to be presented. - * - */ -public final class Document extends AbstractNamedAFPObject { - - /** - * Ststic default name reference - */ - private static final String DEFAULT_NAME = "DOC00001"; - - /** - * A list of the objects in the document - */ - private List objects = new java.util.ArrayList(); - - /** - * The document started state - */ - private boolean started = false; - - /** - * The document completion state - */ - private boolean complete = false; - - /** - * Default constructor for the document object. - */ - public Document() { - this(DEFAULT_NAME); - } - - /** - * Constructor for the document object. - * @param name The name of the document - */ - public Document(String name) { - - super(name); - - } - - /** - * Adds a page to the document. - * @param page - the Page object - */ - public void addPage(PageObject page) { - if (!objects.contains(page)) { - objects.add(page); - } - } - - /** - * Adds a PageGroup to the document. - * @param pageGroup the PageGroup object - */ - public void addPageGroup(PageGroup pageGroup) { - objects.add(pageGroup); - } - - /** - * Method to mark the end of the page group. - */ - public void endDocument() { - - complete = true; - - } - - /** - * Returns an indication if the page group is complete - * @return whether or not this page group is complete - */ - public boolean isComplete() { - return complete; - } - - /** - * Accessor method to write the AFP datastream for document. - * @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 { - - if (!started) { - writeStart(os); - started = true; - } - - for (Iterator it = objects.iterator(); it.hasNext();) { - AbstractAFPObject ao = (AbstractAFPObject)it.next(); - if (ao instanceof PageObject && ((PageObject)ao).isComplete() - || ao instanceof PageGroup && ((PageGroup)ao).isComplete()) { - ao.writeDataStream(os); - it.remove(); - } else { - break; - } - } - - if (complete) { - writeEnd(os); - } - - } - - /** - * Helper method to write the start of the Document - * @param os The stream to write to - */ - private 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 - data[3] = (byte) 0xD3; // Structured field id byte 1 - data[4] = (byte) 0xA8; // Structured field id byte 2 - data[5] = (byte) 0xA8; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - - os.write(data); - - } - - /** - * Helper method to write the end of the Document. - * @param os The stream to write to - */ - 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) 0xA8; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - - os.write(data); - - } - -}
\ 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 deleted file mode 100644 index e6f9f1857..000000000 --- a/src/java/org/apache/fop/render/afp/modca/ImageContent.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; -import java.io.IOException; -import java.io.OutputStream; -import org.apache.fop.render.afp.tools.BinaryUtils; - -/** - */ -public class ImageContent extends AbstractAFPObject { - - /** - * The image size parameter - */ - private ImageSizeParameter _imageSizeParameter = null; - - /** - * The image encoding - */ - private byte _encoding = 0x03; - - /** - * The image ide size - */ - private byte _size = 1; - - /** - * The image compression - */ - private byte _compression = (byte)0xC0; - - /** - * The image color model - */ - private byte _colorModel = 0x01; - - /** - * The image data - */ - private byte _data[] = null; - - /** - * Constructor for the image content - */ - public ImageContent() { - - } - - /** - * Sets the image size parameters - * resolution, hsize and vsize. - * @param hresol The horizontal resolution of the image. - * @param vresol The vertical resolution of the image. - * @param hsize The horizontal size of the image. - * @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); - } - - /** - * Sets the image encoding. - * @param encoding The image encoding. - */ - public void setImageEncoding(byte encoding) { - _encoding = encoding; - } - - /** - * Sets the image compression. - * @param compression The image compression. - */ - public void setImageCompression(byte compression) { - _compression = compression; - } - - /** - * Sets the image IDE size. - * @param size The IDE size. - */ - public void setImageIDESize(byte size) { - _size = size; - } - - /** - * Sets the image IDE color model. - * @param colorModel the IDE color model. - */ - public void setImageIDEColorModel(byte colorModel) { - _colorModel = colorModel; - } - - /** - * Set the data of the image. - */ - public void setImageData(byte data[]) { - _data = data; - } - - /** - * Accessor method to write the AFP datastream for the Image Content - * @param os The stream to write to - * @throws java.io.IOException - */ - public void writeDataStream(OutputStream os) - throws IOException { - - writeStart(os); - - if (_imageSizeParameter != null) { - _imageSizeParameter.writeDataStream(os); - } - - os.write(getImageEncodingParameter()); - - os.write(getImageIDESizeParameter()); - - os.write(getIDEStructureParameter()); - - os.write(getExternalAlgorithmParameter()); - - if (_data != null) { - int off = 0; - while (off < _data.length) { - int len = Math.min(30000, _data.length - off); - os.write(getImageDataStart(len)); - os.write(_data, off, len); - off += len; - } - } - - writeEnd(os); - - } - - /** - * 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[] { - (byte)0x91, // ID - 0x01, // Length - (byte)0xff, // Object Type = IOCA Image Object - }; - - os.write(data); - - } - - /** - * 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[] { - (byte)0x93, // ID - 0x00, // Length - }; - - os.write(data); - - } - - /** - * Helper method to return the start of the image segment. - * @return byte[] The data stream. - */ - private byte[] getImageDataStart(int len) { - - byte[] data = 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; - - } - - /** - * Helper method to return the image encoding parameter. - * @return byte[] The data stream. - */ - private byte[] getImageEncodingParameter() { - - byte[] data = new byte[] { - (byte)0x95, // ID - 0x02, // Length - _encoding, - 0x01, // RECID - }; - - return data; - - } - - /** - * Helper method to return the external algorithm parameter. - * @return byte[] The data stream. - */ - private byte[] getExternalAlgorithmParameter() { - - if (_encoding == (byte)0x83 && _compression != 0) { - byte[] data = new byte[] { - (byte)0x95, // ID - 0x00, // Length - 0x10, // ALGTYPE = Compression Algorithm - 0x00, // Reserved - (byte)0x83, // COMPRID = JPEG - 0x00, // Reserved - 0x00, // Reserved - 0x00, // Reserved - _compression, // MARKER - 0x00, // Reserved - 0x00, // Reserved - 0x00, // Reserved - }; - data[1] = (byte)(data.length - 2); - return data; - } - return new byte[0]; - } - - /** - * Helper method to return the image encoding parameter. - * @return byte[] The data stream. - */ - private byte[] getImageIDESizeParameter() { - - byte[] data = new byte[] { - (byte)0x96, // ID - 0x01, // Length - _size, - }; - - return data; - - } - - /** - * Helper method to return the external algorithm parameter. - * @return byte[] The data stream. - */ - private byte[] getIDEStructureParameter() { - - if (_colorModel != 0 && _size == 24) { - byte bits = (byte)(_size / 3); - byte[] data = new byte[] { - (byte)0x9B, // ID - 0x00, // Length - 0x00, // FLAGS - 0x00, // Reserved - _colorModel, // COLOR MODEL - 0x00, // Reserved - 0x00, // Reserved - 0x00, // Reserved - bits, - bits, - bits, - }; - data[1] = (byte)(data.length - 2); - return data; - } - 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 deleted file mode 100644 index 9250f0c7f..000000000 --- a/src/java/org/apache/fop/render/afp/modca/ImageDataDescriptor.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; - -import java.io.IOException; -import java.io.OutputStream; -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; - - /** - * Constructor for a ImageDataDescriptor for the specified - * resolution, width and height. - * @param xresol The horizontal resolution of the image. - * @param yresol The vertical resolution of the image. - * @param width The width of the image. - * @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; - - } - - /** - * Accessor method to write the AFP datastream for the Image Data Descriptor - * @param os The stream to write to - * @throws java.io.IOException - */ - public void writeDataStream(OutputStream os) - throws IOException { - - byte[] data = new byte[] { - 0x5A, - 0x00, - 0x20, - (byte) 0xD3, - (byte) 0xA6, - (byte) 0xFB, - 0x00, // Flags - 0x00, // Reserved - 0x00, // Reserved - 0x00, // Unit base - 10 Inches - 0x00, // XRESOL - 0x00, // - 0x00, // YRESOL - 0x00, // - 0x00, // XSIZE - 0x00, // - 0x00, // YSIZE - 0x00, // - (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 deleted file mode 100644 index 66c46c872..000000000 --- a/src/java/org/apache/fop/render/afp/modca/ImageObject.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -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; - - /** - * The image segment - */ - private ImageSegment imageSegment = null; - - /** - * Constructor for the image object with the specified name, - * the name must be a fixed length of eight characters. - * @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); - } - - /** - * Set the dimensions of the image. - * @param xresol the x resolution of the image - * @param yresol the y resolution of the image - * @param width the image width - * @param height the image height - */ - public void setImageParameters(int xresol, int yresol, int width, int height) { - if (objectEnvironmentGroup == null) { - objectEnvironmentGroup = new ObjectEnvironmentGroup(); - } - objectEnvironmentGroup.setImageData(xresol, yresol, width, height); - if (imageSegment == null) { - imageSegment = new ImageSegment(); - } - imageSegment.setImageSize(xresol, yresol, width, height); - } - - /** - * Sets the image encoding. - * @param encoding The image encoding. - */ - public void setImageEncoding(byte encoding) { - if (imageSegment == null) { - imageSegment = new ImageSegment(); - } - imageSegment.setImageEncoding(encoding); - } - - /** - * Sets the image compression. - * @param compression The image compression. - */ - public void setImageCompression(byte compression) { - if (imageSegment == null) { - imageSegment = new ImageSegment(); - } - imageSegment.setImageCompression(compression); - } - - /** - * Sets the image IDE size. - * @param size The IDE size. - */ - public void setImageIDESize(byte size) { - if (imageSegment == null) { - imageSegment = new ImageSegment(); - } - imageSegment.setImageIDESize(size); - } - - /** - * Sets the image IDE color model. - * @param colorModel the IDE color model. - */ - public void setImageIDEColorModel(byte colorModel) { - if (imageSegment == null) { - imageSegment = new ImageSegment(); - } - imageSegment.setImageIDEColorModel(colorModel); - } - - /** - * Set the data of the image. - * @param data The image data - */ - public void setImageData(byte[] data) { - if (imageSegment == null) { - imageSegment = new ImageSegment(); - } - imageSegment.setImageData(data); - } - - /** - * 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. - * @return byte[] The data stream. - */ - private byte[] getIPDStart(int len) { - - byte[] data = new byte[] { - - 0x5A, // Structured field identifier - 0x00, // Length byte 1 - 0x10, // Length byte 2 - (byte) 0xD3, // Structured field id byte 1 - (byte) 0xEE, // Structured field id byte 2 - (byte) 0xFB, // Structured field id byte 3 - 0x00, // Flags - 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 - */ - public void writeDataStream(OutputStream os) - throws IOException { - - writeStart(os); - - if (objectEnvironmentGroup != null) { - objectEnvironmentGroup.writeDataStream(os); - } - - if (imageSegment != null) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - imageSegment.writeDataStream(baos); - byte[] b = baos.toByteArray(); - int off = 0; - while (off < b.length) { - int len = Math.min(30000, b.length - off); - os.write(getIPDStart(len)); - os.write(b, off, len); - off += len; - } - } - - writeEnd(os); - - } - - /** - * Helper method to write the start of the Image Object. - * @param os The stream to write to - */ - private 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 - data[3] = (byte) 0xD3; // Structured field id byte 1 - data[4] = (byte) 0xA8; // Structured field id byte 2 - data[5] = (byte) 0xFB; // 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++) { - - 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 - */ - 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) 0xFB; // 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++) { - - 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 deleted file mode 100644 index 7d6cc18aa..000000000 --- a/src/java/org/apache/fop/render/afp/modca/ImageSegment.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; -import java.io.IOException; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; - -/** - * An Image Segment is represented by a set of self-defining fields, fields - * that describe their own contents. It starts with a Begin Segment, and - * ends with an End Segment. - * - * Between the Begin Segment and End Segment is the image information to - * be processed, called the Image Content. - * - * Only one Image Content can exist within a single IOCA Image Segment. - */ -public class ImageSegment extends AbstractAFPObject { - - /** - * Default name for the object environment group - */ - private static final String DEFAULT_NAME = "IS01"; - - /** - * The name of the image segment - */ - private String name; - - /** - * The name of the image segment as EBCIDIC bytes - */ - private byte[] nameBytes; - - /** - * The ImageContent for the image segment - */ - private ImageContent imageContent = null; - - /** - * Default constructor for the ImageSegment. - */ - public ImageSegment() { - this(DEFAULT_NAME); - } - - /** - * Constructor for the image segment with the specified name, - * the name must be a fixed length of eight characters. - * @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) { - this.nameBytes = name.getBytes(); - log.warn( - "Constructor:: UnsupportedEncodingException translating the name " - + name); - } - } - - /** - * Sets the image size parameters - * resolution, hsize and vsize. - * @param hresol The horizontal resolution of the image. - * @param vresol The vertical resolution of the image. - * @param hsize The horizontal size of the image. - * @param vsize The vertival size of the image. - */ - public void setImageSize(int hresol, int vresol, int hsize, int vsize) { - if (imageContent == null) { - imageContent = new ImageContent(); - } - imageContent.setImageSize(hresol, vresol, hsize, vsize); - } - - /** - * Sets the image encoding. - * @param encoding The image encoding. - */ - public void setImageEncoding(byte encoding) { - if (imageContent == null) { - imageContent = new ImageContent(); - } - imageContent.setImageEncoding(encoding); - } - - /** - * Sets the image compression. - * @param compression The image compression. - */ - public void setImageCompression(byte compression) { - if (imageContent == null) { - imageContent = new ImageContent(); - } - imageContent.setImageCompression(compression); - } - - /** - * Sets the image IDE size. - * @param size The IDE size. - */ - public void setImageIDESize(byte size) { - if (imageContent == null) { - imageContent = new ImageContent(); - } - imageContent.setImageIDESize(size); - } - - /** - * Sets the image IDE color model. - * @param colorModel the IDE color model. - */ - public void setImageIDEColorModel(byte colorModel) { - if (imageContent == null) { - imageContent = new ImageContent(); - } - imageContent.setImageIDEColorModel(colorModel); - } - - /** - * Set the data of the image. - * @param data the image data - */ - public void setImageData(byte[] data) { - if (imageContent == null) { - imageContent = new ImageContent(); - } - imageContent.setImageData(data); - } - - /** - * Accessor method to write the AFP datastream for the Image Segment - * @param os The stream to write to - * @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 { - - byte[] data = new byte[] { - 0x70, // ID - 0x04, // Length - 0x00, // Name byte 1 - 0x00, // Name byte 2 - 0x00, // Name byte 3 - 0x00, // Name byte 4 - }; - - for (int i = 0; i < nameBytes.length; i++) { - - data[2 + i] = nameBytes[i]; - - } - - os.write(data); - - } - - /** - * Helper method to write the end of the Image Segment. - * @param os The stream to write to - */ - private void writeEnd(OutputStream os) throws IOException { - - byte[] data = new byte[] { - 0x71, // ID - 0x00, // Length - }; - os.write(data); - } -} diff --git a/src/java/org/apache/fop/render/afp/modca/IncludeObject.java b/src/java/org/apache/fop/render/afp/modca/IncludeObject.java deleted file mode 100644 index 890fdcd9d..000000000 --- a/src/java/org/apache/fop/render/afp/modca/IncludeObject.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; - -import java.io.IOException; -import java.io.OutputStream; - -import org.apache.fop.render.afp.tools.BinaryUtils; - -/** - * An Include Object structured field references an object on a page or overlay. - * It optionally contains parameters that identify the object and that specify - * presentation parameters such as object position, size, orientation, mapping, - * and default color. - * <p> - * Where the presentation parameters conflict with parameters specified in the - * object's environment group (OEG), the parameters in the Include Object - * structured field override. If the referenced object is a page segment, the - * IOB parameters override the corresponding environment group parameters on all - * data objects in the page segment. - * </p> - */ -public class IncludeObject extends AbstractNamedAFPObject { - - /** - * The object type - */ - private byte objectType = (byte) 0x92; - - /** - * The orientation on the include object - */ - private int orientation = 0; - - /** - * Constructor for the include object with the specified name, the name must - * be a fixed length of eight characters and is the name of the referenced - * object. - * - * @param name - * the name of the image - */ - public IncludeObject(String name) { - - super(name); - objectType = (byte) 0xFB; - - } - - /** - * Sets the orientation to use for the Include Object. - * - * @param orientation - * The orientation (0,90, 180, 270) - */ - public void setOrientation(int orientation) { - - if (orientation == 0 || orientation == 90 || orientation == 180 - || orientation == 270) { - this.orientation = orientation; - } else { - throw new IllegalArgumentException( - "The orientation must be one of the values 0, 90, 180, 270"); - } - - } - - /** - * Accessor method to write the AFP datastream for the Include Object - * @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 { - - byte[] data = new byte[37]; - - data[0] = 0x5A; - - // Set the total record length - byte[] rl1 = BinaryUtils.convert(36, 2); //Ignore first byte - data[1] = rl1[0]; - data[2] = rl1[1]; - - // Structured field ID for a IOB - data[3] = (byte) 0xD3; - data[4] = (byte) 0xAF; - data[5] = (byte) 0xC3; - - data[6] = 0x00; // Reserved - data[7] = 0x00; // Reserved - data[8] = 0x00; // Reserved - - for (int i = 0; i < nameBytes.length; i++) { - data[9 + i] = nameBytes[i]; - } - - data[17] = 0x00; - data[18] = objectType; - - // XoaOset - data[20] = (byte) 0xFF; - data[21] = (byte) 0xFF; - data[22] = (byte) 0xFF; - - // YoaOset - data[23] = (byte) 0xFF; - data[24] = (byte) 0xFF; - data[25] = (byte) 0xFF; - - switch (orientation) { - case 90: - data[26] = 0x2D; - data[27] = 0x00; - data[28] = 0x5A; - data[29] = 0x00; - break; - case 180: - data[26] = 0x5A; - data[27] = 0x00; - data[28] = (byte) 0x87; - data[29] = 0x00; - break; - case 270: - data[26] = (byte) 0x87; - data[27] = 0x00; - data[28] = 0x00; - data[29] = 0x00; - break; - default: - data[26] = 0x00; - data[27] = 0x00; - data[28] = 0x2D; - data[29] = 0x00; - break; - } - - // XocaOset - data[30] = (byte) 0xFF; - data[31] = (byte) 0xFF; - data[32] = (byte) 0xFF; - - // YocaOset - data[33] = (byte) 0xFF; - data[34] = (byte) 0xFF; - data[35] = (byte) 0xFF; - - data[36] = 0x01; - - os.write(data); - - } - -}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/ObjectAreaDescriptor.java b/src/java/org/apache/fop/render/afp/modca/ObjectAreaDescriptor.java deleted file mode 100644 index 561c8c6fe..000000000 --- a/src/java/org/apache/fop/render/afp/modca/ObjectAreaDescriptor.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; - -import java.io.IOException; -import java.io.OutputStream; -import org.apache.fop.render.afp.tools.BinaryUtils; - -/** - * The Object Area Descriptor structured field specifies the size and attributes - * of an object area presentation space. - * - */ -public class ObjectAreaDescriptor extends AbstractDescriptor { - - /** - * Construct an object area descriptor for the specified object width - * 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. - */ - public ObjectAreaDescriptor(int width, int height, int widthResolution, int heightResolution) { - super(width, height, widthResolution, heightResolution); - } - - /** - * Accessor method to write the AFP datastream for the Object Area Descriptor - * @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 { - - byte[] data = new byte[29]; - data[0] = 0x5A; - - byte[] len = BinaryUtils.convert(data.length - 1, 2); - data[1] = len[0]; // Length - data[2] = len[1]; - - data[3] = (byte) 0xD3; - data[4] = (byte) 0xA6; - data[5] = (byte) 0x6B; - data[6] = 0x00; // Flags - data[7] = 0x00; // Reserved - data[8] = 0x00; // Reserved - data[9] = 0x03; // Triplet length - data[10] = 0x43; // tid = Descriptor Position Triplet - data[11] = 0x01; // DesPosId = 1 - data[12] = 0x08; // Triplet length - data[13] = 0x4B; // tid = Measurement Units Triplet - data[14] = 0x00; // XaoBase = 10 inches - data[15] = 0x00; // YaoBase = 10 inches - - // XaoUnits - byte[] xdpi = BinaryUtils.convert(widthResolution * 10, 2); - data[16] = xdpi[0]; - data[17] = xdpi[1]; - - // YaoUnits - byte[] ydpi = BinaryUtils.convert(heightResolution * 10, 2); - data[18] = ydpi[0]; - data[19] = ydpi[1]; - - data[20] = 0x09; // Triplet length - data[21] = 0x4C; // tid = Object Area Size - data[22] = 0x02; // Size Type - - byte[] x = BinaryUtils.convert(width, 3); - data[23] = x[0]; - data[24] = x[1]; - data[25] = x[2]; - - byte[] y = BinaryUtils.convert(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 deleted file mode 100644 index e500c1269..000000000 --- a/src/java/org/apache/fop/render/afp/modca/ObjectAreaPosition.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; - -import java.io.IOException; -import java.io.OutputStream; -import org.apache.fop.render.afp.tools.BinaryUtils; - -/** - * The Object Area Position structured field specifies the origin and - * orientation of the object area, and the origin and orientation of the - * object content within the object area. - */ -public class ObjectAreaPosition extends AbstractAFPObject { - - private int _x = 0; - private int _y = 0; - private int _rot = 0; - - /** - * Construct an object area position for the specified object y, y position. - * @param x The x coordinate. - * @param y The y coordinate. - * @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; - } - - /** - * Accessor method to write the AFP datastream for the Object Area Position - * @param os The stream to write to - * @throws java.io.IOException - */ - public void writeDataStream(OutputStream os) - throws IOException { - - byte[] data = new byte[] { - 0x5A, - 0x00, // Length - 0x20, // Length - (byte) 0xD3, - (byte) 0xAC, - (byte) 0x6B, - 0x00, // Flags - 0x00, // Reserved - 0x00, // Reserved - 0x01, // OAPosID = 1 - 0x17, // RGLength = 23 - 0x00, // XoaOSet - 0x00, - 0x00, - 0x00, // YoaOSet - 0x00, - 0x00, - (byte)(_rot / 2), // XoaOrent - 0x00, - (byte)(_rot / 2 + 45), // YoaOrent - 0x00, - 0x00, // Reserved - 0x00, // XocaOSet - 0x00, - 0x00, - 0x00, // YocaOSet - 0x00, - 0x00, - 0x00, // XocaOrent - 0x00, - 0x2D, // YocaOrent - 0x00, - 0x01, // 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); - - } - -}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/ObjectEnvironmentGroup.java b/src/java/org/apache/fop/render/afp/modca/ObjectEnvironmentGroup.java deleted file mode 100644 index d6b029122..000000000 --- a/src/java/org/apache/fop/render/afp/modca/ObjectEnvironmentGroup.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; -import java.io.IOException; -import java.io.OutputStream; - - -/** - * An Object Environment Group (OEG) may be associated with an object and is contained - * within the object's begin-end envelope. - * The object environment group defines the object's origin and orientation on the page, - * and can contain font and color attribute table information. The scope of an object - * environment group is the scope of its containing object. - * - * An application that creates a data-stream document may omit some of the parameters - * 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 { - - /** - * Default name for the object environment group - */ - private static final String DEFAULT_NAME = "OEG00001"; - - /** - * The ObjectAreaDescriptor for the object environment group - */ - private ObjectAreaDescriptor objectAreaDescriptor = null; - - /** - * The ObjectAreaPosition for the object environment group - */ - private ObjectAreaPosition objectAreaPosition = null; - - /** - * The ImageDataDescriptor for the object environment group - */ - private ImageDataDescriptor imageDataDescriptor = null; - - /** - * Default constructor for the ObjectEnvironmentGroup. - */ - public ObjectEnvironmentGroup() { - - this(DEFAULT_NAME); - - } - - /** - * Constructor for the ObjectEnvironmentGroup, this takes a - * name parameter which must be 8 characters long. - * @param name the object environment group name - */ - public ObjectEnvironmentGroup(String name) { - - super(name); - - } - - /** - * Sets the object area parameters. - * @param x the x position of the object - * @param y the y position of the object - * @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 - */ - 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); - - } - - /** - * Set the dimensions of the image. - * @param xresol the x resolution of the image - * @param yresol the y resolution of the image - * @param width the image width - * @param height the image height - */ - public void setImageData(int xresol, int yresol, int width, int height) { - 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 - */ - public void writeDataStream(OutputStream os) - throws IOException { - - - writeStart(os); - - objectAreaDescriptor.writeDataStream(os); - - objectAreaPosition.writeDataStream(os); - - if (imageDataDescriptor != null) { - imageDataDescriptor.writeDataStream(os); - } - - writeEnd(os); - - } - - /** - * Helper method to write the start of the object environment group. - * @param os The stream to write to - */ - private void writeStart(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) 0xA8, // Structured field id byte 2 - (byte) 0xC7, // Structured field id byte 3 - 0x00, // Flags - 0x00, // Reserved - 0x00, // Reserved - 0x00, // Name - 0x00, // - 0x00, // - 0x00, // - 0x00, // - 0x00, // - 0x00, // - 0x00, // - }; - - 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 - */ - 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++) { - - data[9 + i] = nameBytes[i]; - - } - - os.write(data); - - } - -}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/Overlay.java b/src/java/org/apache/fop/render/afp/modca/Overlay.java deleted file mode 100644 index 3a4cdfb11..000000000 --- a/src/java/org/apache/fop/render/afp/modca/Overlay.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * An overlay is a MO:DCA-P resource object. - * - * It may be stored in an external resource library or it may be - * carried in a resource group. An overlay is similar to a page in - * that it defines its own environment and carries the same data objects. - */ -public class Overlay extends AbstractPageObject { - - /** - * Construct a new overlay object for the specified name argument, the overlay - * name should be an 8 character identifier. - * - * @param name - * the name of the page. - * @param width - * the width of the page. - * @param height - * the height of the page. - * @param rotation - * the rotation of the page. - * @param widthResolution - * the width resolution of the page. - * @param heightResolution - * the height resolution of the page. - */ - public Overlay(String name, int width, int height, int rotation, - int widthResolution, int heightResolution) { - - super(name, width, height, rotation, widthResolution, heightResolution); - - } - - /** - * Accessor method to write the AFP datastream for the overlay. - * - * @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 { - - writeStart(os); - - activeEnvironmentGroup.writeDataStream(os); - - writeObjectList(segments, os); - - writeObjectList(tagLogicalElements, os); - - writeObjectList(objects, os); - - writeEnd(os); - - } - - /** - * Helper method to write the start of the overlay. - * @param os The stream to write to - */ - private 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 - data[3] = (byte) 0xD3; // Structured field id byte 1 - data[4] = (byte) 0xA8; // Structured field id byte 2 - data[5] = (byte) 0xDF; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - - os.write(data); - - } - - /** - * Helper method to write the end of the overlay. - * @param os The stream to write to - */ - 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) 0xDF; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - - os.write(data); - - } - -} diff --git a/src/java/org/apache/fop/render/afp/modca/PageGroup.java b/src/java/org/apache/fop/render/afp/modca/PageGroup.java deleted file mode 100644 index 0b40a83c5..000000000 --- a/src/java/org/apache/fop/render/afp/modca/PageGroup.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * A page group is used in the data stream to define a named, logical grouping - * of sequential pages. Page groups are delimited by begin-end structured fields - * that carry the name of the page group. Page groups are defined so that the - * pages that comprise the group can be referenced or processed as a single - * entity. Page groups are often processed in stand-alone fashion; that is, they - * are indexed, retrieved, and presented outside the context of the containing - * document. - * - * @author <a href="mailto:pete@townsend.uk.com">Pete Townsend </a> - */ -public class PageGroup extends AbstractNamedAFPObject { - - /** - * The pages contained within this group - */ - private List objects = new ArrayList(); - - /** - * The tag logical elements contained within this group - */ - private List tagLogicalElements = new ArrayList(); - - /** - * The page state - */ - private boolean complete = false; - - /** - * Constructor for the PageGroup. - * - * @param name - * the name of the page group - */ - public PageGroup(String name) { - - super(name); - - } - - /** - * Adds a page object to the group. - * - * @param page - * the page object to add - */ - public void addPage(PageObject page) { - - if (!objects.contains(page)) { - objects.add(page); - } - - } - - /** - * @return the name of the page group - */ - public String getName() { - return name; - } - - /** - * Creates a TagLogicalElement on the page. - * - * @param name - * the name of the tag - * @param value - * the value of the tag - */ - public void createTagLogicalElement(String name, String value) { - - TagLogicalElement tle = new TagLogicalElement(name, value); - tagLogicalElements.add(tle); - - } - - /** - * Creates an InvokeMediaMap on the page. - * - * @param name - * the name of the media map - */ - public void createInvokeMediumMap(String name) { - - InvokeMediumMap imm = new InvokeMediumMap(name); - objects.add(imm); - - } - - /** - * Method to mark the end of the page group. - */ - public void endPageGroup() { - - complete = true; - - } - - /** - * Returns an indication if the page group is complete - * @return whether or not this page group is complete or not - */ - public boolean isComplete() { - return complete; - } - - /** - * Accessor method to write the AFP datastream for the page group. - * @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 { - - writeStart(os); - - writeObjectList(tagLogicalElements, os); - - writeObjectList(objects, os); - - writeEnd(os); - - } - - /** - * Helper method to write the start of the page group. - * @param os The stream to write to - */ - private 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 - data[3] = (byte) 0xD3; // Structured field id byte 1 - data[4] = (byte) 0xA8; // Structured field id byte 2 - data[5] = (byte) 0xAD; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - - os.write(data); - - } - - /** - * Helper method to write the end of the page group. - * @param os The stream to write to - */ - 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) 0xAD; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - - os.write(data); - - } - -}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/PageObject.java b/src/java/org/apache/fop/render/afp/modca/PageObject.java deleted file mode 100644 index 5b9a00a89..000000000 --- a/src/java/org/apache/fop/render/afp/modca/PageObject.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; -import java.io.IOException; -import java.io.OutputStream; - - - -/** - * Pages contain the data objects that comprise a presentation document. Each - * page has a set of data objects associated with it. Each page within a - * document is independent from any other page, and each must establish its own - * environment parameters. - * - * The page is the level in the document component hierarchy that is used for - * printing or displaying a document's content. The data objects contained in - * the page envelope in the data stream are presented when the page is - * presented. Each data object has layout information associated with it that - * directs the placement and orientation of the data on the page. In addition, - * each page contains layout information that specifies the measurement units, - * page width, and page depth. - * - * A page is initiated by a begin page structured field and terminated by an end - * page structured field. Structured fields that define objects and active - * environment groups or that specify attributes of the page may be encountered - * in page state. - * - */ -public class PageObject extends AbstractPageObject { - - /** - * The resource group object - */ - private ResourceGroup resourceGroup = null; - - /** - * Construct a new page object for the specified name argument, the page - * name should be an 8 character identifier. - * - * @param name - * the name of the page. - * @param width - * the width of the page. - * @param height - * the height of the page. - * @param rotation - * the rotation of the page. - * @param widthResolution - * the width resolution of the page. - * @param heightResolution - * the height resolution of the page. - */ - public PageObject(String name, int width, int height, int rotation, - int widthResolution, int heightResolution) { - - super(name, width, height, rotation, widthResolution, heightResolution); - - } - - /** - * Adds an overlay to the page resources - * @param overlay the overlay to add - */ - public void addOverlay(Overlay overlay) { - if (resourceGroup == null) { - resourceGroup = new ResourceGroup(); - } - resourceGroup.addOverlay(overlay); - } - - /** - * Creates an IncludePageOverlay on the page. - * - * @param name - * the name of the overlay - * @param x - * the x position of the overlay - * @param y - * the y position of the overlay - * @param orientation - * the orientation required for the overlay - */ - public void createIncludePageOverlay(String name, int x, int y, int orientation) { - - IncludePageOverlay ipo = new IncludePageOverlay(name, x, y, orientation); - objects.add(ipo); - - } - - /** - * Accessor method to write the AFP datastream for the page. - * @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 { - - writeStart(os); - - if (resourceGroup != null) { - resourceGroup.writeDataStream(os); - } - - activeEnvironmentGroup.writeDataStream(os); - - writeObjectList(segments, os); - - writeObjectList(tagLogicalElements, os); - - writeObjectList(objects, os); - - writeEnd(os); - - } - - /** - * Helper method to write the start of the page. - * @param os The stream to write to - */ - private 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 - data[3] = (byte) 0xD3; // Structured field id byte 1 - data[4] = (byte) 0xA8; // Structured field id byte 2 - data[5] = (byte) 0xAF; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - - os.write(data); - - } - - /** - * Helper method to write the end of the page. - * @param os The stream to write to - */ - 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) 0xAF; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - - os.write(data); - - } - -}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/PresentationTextObject.java b/src/java/org/apache/fop/render/afp/modca/PresentationTextObject.java deleted file mode 100644 index c0f06439e..000000000 --- a/src/java/org/apache/fop/render/afp/modca/PresentationTextObject.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; - -import java.awt.Color; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; - -/** - * The Presentation Text object is the data object used in document processing - * environments for representing text which has been prepared for presentation. - * Text, as used here, means an ordered string of characters, such as graphic - * symbols, numbers, and letters, that are suitable for the specific purpose of - * representing coherent information. Text which has been prepared for - * presentation has been reduced to a primitive form through explicit - * specification of the characters and their placement in the presentation - * space. Control sequences which designate specific control functions may be - * embedded within the text. These functions extend the primitive form by - * applying specific characteristics to the text when it is presented. The - * collection of the graphic characters and control codes is called Presentation - * Text, and the object that contains the Presentation Text is called the - * PresentationText object. - * - */ -public class PresentationTextObject extends AbstractNamedAFPObject { - - /** - * Default name for the presentation text object - */ - private static final String DEFAULT_NAME = "PTO00001"; - - private PresentationTextData currentPresentationTextData = null; - - private ArrayList presentationTextData = new ArrayList(); - - /** - * Default constructor for the PresentationTextObject - */ - public PresentationTextObject() { - - this(DEFAULT_NAME); - - } - - /** - * Construct a new PresentationTextObject for the specified name argument, - * the name should be an 8 character identifier. - * @param name the name of this presentation object - */ - public PresentationTextObject(String name) { - - super(name); - - } - - /** - * Create the presentation text data for the byte array of data. - * - * @param fontNumber - * The font resource identifier. - * @param x - * The x coordinate for the text data. - * @param y - * The y coordinate for the text data. - * @param col - * The text color. - * @param vsci - * The variable space character increment. - * @param ica - * The inter character increment. - * @param data - * The text data to be created. - */ - public void createTextData(int fontNumber, int x, int y, Color col, - int vsci, int ica, byte[] data) { - - // Use a default orientation of zero - createTextData(fontNumber, x, y, 0, col, vsci, ica, data); - - } - - /** - * Create the presentation text data for the byte array of data. - * - * @param fontNumber - * The font resource identifier. - * @param x - * The x coordinate for the text data. - * @param y - * The y coordinate for the text data. - * @param orientation - * The orientation of the text data. - * @param col - * The text color. - * @param vsci - * The variable space character increment. - * @param ica - * The inter character adjustment. - * @param data - * The text data to be created. - */ - public void createTextData(int fontNumber, int x, int y, int orientation, - Color col, int vsci, int ica, byte[] data) { - - if (currentPresentationTextData == null) { - startPresentationTextData(); - } - - try { - - currentPresentationTextData.createTextData(fontNumber, x, y, - orientation, col, vsci, ica, data); - - } catch (MaximumSizeExceededException msee) { - - endPresentationTextData(); - createTextData(fontNumber, x, y, orientation, col, vsci, ica, data); - - } - - } - - /** - * Drawing of lines using the starting and ending coordinates, thickness. - * - * @param x1 - * The first x coordinate of the line. - * @param y1 - * The first y coordinate of the line. - * @param x2 - * The second x coordinate of the line. - * @param y2 - * The second y coordinate of the line. - * @param thickness - * The thickness of the line. - * @param col - * The text color. - */ - public void createLineData(int x1, int y1, int x2, int y2, int thickness, Color col) { - // Default orientation - createLineData(x1, y1, x2, y2, thickness, 0, col); - } - - /** - * Drawing of lines using the starting and ending coordinates, thickness and - * orientation arguments. - * - * @param x1 - * The first x coordinate of the line. - * @param y1 - * The first y coordinate of the line. - * @param x2 - * The second x coordinate of the line. - * @param y2 - * The second y coordinate of the line. - * @param thickness - * The thickness of the line. - * @param orientation - * The orientation of the line. - * @param col - * The text color. - */ - public void createLineData(int x1, int y1, int x2, int y2, int thickness, - int orientation, Color col) { - - if (currentPresentationTextData == null) { - startPresentationTextData(); - } - - try { - - currentPresentationTextData.createLineData(x1, y1, x2, y2, - thickness, orientation, col); - - } catch (MaximumSizeExceededException msee) { - - endPresentationTextData(); - createLineData(x1, y1, x2, y2, thickness, orientation, col); - - } - - } - - /** - * Helper method to mark the start of the presentation text data - */ - private void startPresentationTextData() { - - if (presentationTextData.size() == 0) { - currentPresentationTextData = new PresentationTextData(true); - } else { - currentPresentationTextData = new PresentationTextData(); - } - - presentationTextData.add(currentPresentationTextData); - - } - - /** - * Helper method to mark the end of the presentation text data - */ - private void endPresentationTextData() { - - currentPresentationTextData = null; - - } - - /** - * Accessor method to write the AFP datastream for the PresentationTextObject. - * @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 { - - writeStart(os); - - writeObjectList(presentationTextData, os); - - writeEnd(os); - - } - - /** - * Returns the name of this presentation text object - * @return the name of this presentation text object - */ - public String getName() { - - return name; - - } - - /** - * Helper method to write the start of the presenation text object. - * @param os The stream to write to - */ - private 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 - data[3] = (byte) 0xD3; // Structured field id byte 1 - data[4] = (byte) 0xA8; // Structured field id byte 2 - data[5] = (byte) 0x9B; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - - os.write(data); - - } - - /** - * Helper method to write the end of the presenation text object. - * @param os The stream to write to - */ - 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) 0x9B; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - - os.write(data); - - } - - /** - * A control sequence is a sequence of bytes that specifies a control - * function. A control sequence consists of a control sequence introducer - * and zero or more parameters. The control sequence can extend multiple - * presentation text data objects, but must eventually be terminated. This - * method terminates the control sequence. - */ - public void endControlSequence() { - - if (currentPresentationTextData == null) { - startPresentationTextData(); - } - - try { - - currentPresentationTextData.endControlSequence(); - - } catch (MaximumSizeExceededException msee) { - - endPresentationTextData(); - endControlSequence(); - - } - - } - -}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/modca/ResourceGroup.java b/src/java/org/apache/fop/render/afp/modca/ResourceGroup.java deleted file mode 100644 index 07043dcf1..000000000 --- a/src/java/org/apache/fop/render/afp/modca/ResourceGroup.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.afp.modca; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * A Resource Group contains a set of overlays. - */ -public final class ResourceGroup extends AbstractNamedAFPObject { - - /** - * Default name for the resource group - */ - private static final String DEFAULT_NAME = "RG000001"; - - - /** - * The overlays contained in this resource group - */ - private List overlays = new ArrayList(); - - /** - * Default constructor - */ - public ResourceGroup() { - - this(DEFAULT_NAME); - - } - - /** - * Constructor for the ResourceGroup, this takes a - * name parameter which must be 8 characters long. - * @param name the resource group name - */ - public ResourceGroup(String name) { - - super(name); - - } - - /** - * Adds an overlay to the resource group - * @param overlay the overlay to add - */ - public void addOverlay(Overlay overlay) { - overlays.add(overlay); - } - - /** - * Returns the list of overlays - * @return the list of overlays - */ - public List getOverlays() { - return overlays; - } - - /** - * Accessor method to obtain write the AFP datastream for - * the resource group. - * @param os The stream to write to - * @throws java.io.IOException if an I/O exception of some sort has occurred - */ - public void writeDataStream(OutputStream os) - throws IOException { - - writeStart(os); - - writeObjectList(overlays, os); - - writeEnd(os); - - } - - /** - * Helper method to write the start of the resource group. - * @param os The stream to write to - */ - private 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 - data[3] = (byte) 0xD3; // Structured field id byte 1 - data[4] = (byte) 0xA8; // Structured field id byte 2 - data[5] = (byte) 0xC6; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - - os.write(data); - - } - - /** - * Helper method to write the end of the resource group. - * @param os The stream to write to - */ - 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) 0xC6; // 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++) { - - data[9 + i] = nameBytes[i]; - - } - - os.write(data); - - } - -}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/afp/package.html b/src/java/org/apache/fop/render/afp/package.html new file mode 100644 index 000000000..3e611d964 --- /dev/null +++ b/src/java/org/apache/fop/render/afp/package.html @@ -0,0 +1,23 @@ +<!-- + 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.html 643433 2008-04-01 15:08:24Z acumiskey $ --> +<HTML> +<TITLE>org.apache.fop.render.afp Package</TITLE> +<BODY> +<P>An AFP Renderer implementation and supporting classes.</P> +</BODY> +</HTML>
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/awt/AWTRenderer.java b/src/java/org/apache/fop/render/awt/AWTRenderer.java index f67c2c7a2..5b4c6b13a 100644 --- a/src/java/org/apache/fop/render/awt/AWTRenderer.java +++ b/src/java/org/apache/fop/render/awt/AWTRenderer.java @@ -149,14 +149,11 @@ public class AWTRenderer extends Java2DRenderer implements Pageable { Rectangle2D bounds = getPageViewport(pageNum).getViewArea(); pageWidth = (int) Math.round(bounds.getWidth() / 1000f); pageHeight = (int) Math.round(bounds.getHeight() / 1000f); - double scaleX = scaleFactor + double scale = scaleFactor * (25.4 / FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION) / userAgent.getTargetPixelUnitToMillimeter(); - double scaleY = scaleFactor - * (25.4 / FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION) - / userAgent.getTargetPixelUnitToMillimeter(); - int bitmapWidth = (int) ((pageWidth * scaleX) + 0.5); - int bitmapHeight = (int) ((pageHeight * scaleY) + 0.5); + int bitmapWidth = (int) ((pageWidth * scale) + 0.5); + int bitmapHeight = (int) ((pageHeight * scale) + 0.5); return new Dimension(bitmapWidth, bitmapHeight); } diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java index 65e6ac0fe..933398125 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java +++ b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java @@ -135,7 +135,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem /** The current state, holds a Graphics2D and its context */ protected Java2DGraphicsState state; - private Stack stateStack = new Stack(); + private final Stack stateStack = new Stack(); /** true if the renderer has finished rendering all the pages */ private boolean renderingDone; @@ -146,9 +146,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem public Java2DRenderer() { } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void setUserAgent(FOUserAgent foUserAgent) { super.setUserAgent(foUserAgent); userAgent.setRendererOverride(this); // for document regeneration @@ -164,9 +162,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem return userAgent; } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void setupFontInfo(FontInfo inFontInfo) { //Don't call super.setupFontInfo() here! Java2D needs a special font setup // create a temp Image to test font metrics on @@ -437,16 +433,12 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem state.transform(new AffineTransform(CTMHelper.toPDFArray(ctm))); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ protected void endVParea() { restoreGraphicsState(); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ protected List breakOutOfStateStack() { log.debug("Block.FIXED --> break out"); List breakOutList; @@ -459,10 +451,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem return breakOutList; } - /** - * {@inheritDoc} - * java.util.List) - */ + /** {@inheritDoc} */ protected void restoreStateStackAfterBreakOut(List breakOutList) { log.debug("Block.FIXED --> restoring context after break-out"); @@ -474,16 +463,12 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem } } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ protected void updateColor(Color col, boolean fill) { state.updateColor(col); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ protected void clip() { if (currentPath == null) { throw new IllegalStateException("No current path available!"); @@ -492,16 +477,12 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem currentPath = null; } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ protected void closePath() { currentPath.closePath(); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ protected void lineTo(float x, float y) { if (currentPath == null) { currentPath = new GeneralPath(); @@ -509,9 +490,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem currentPath.lineTo(x, y); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ protected void moveTo(float x, float y) { if (currentPath == null) { currentPath = new GeneralPath(); @@ -519,23 +498,17 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem currentPath.moveTo(x, y); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ protected void clipRect(float x, float y, float width, float height) { state.updateClip(new Rectangle2D.Float(x, y, width, height)); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ protected void fillRect(float x, float y, float width, float height) { state.getGraph().fill(new Rectangle2D.Float(x, y, width, height)); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ protected void drawBorderLine(float x1, float y1, float x2, float y2, boolean horz, boolean startOrBefore, int style, Color col) { Graphics2D g2d = state.getGraph(); @@ -706,9 +679,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem } } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void renderText(TextArea text) { renderInlineAreaBackAndBorders(text); @@ -890,18 +861,20 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem super.renderLeader(area); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void renderImage(Image image, Rectangle2D pos) { // endTextObject(); String url = image.getURL(); drawImage(url, pos); } - /** - * {@inheritDoc} - */ + private static final ImageFlavor[] FLAVOURS = new ImageFlavor[] + {ImageFlavor.GRAPHICS2D, + ImageFlavor.BUFFERED_IMAGE, + ImageFlavor.RENDERED_IMAGE, + ImageFlavor.XML_DOM}; + + /** {@inheritDoc} */ protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) { int x = currentIPPosition + (int)Math.round(pos.getX()); @@ -913,14 +886,9 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem try { ImageSessionContext sessionContext = getUserAgent().getImageSessionContext(); info = manager.getImageInfo(uri, sessionContext); - final ImageFlavor[] flavors = new ImageFlavor[] - {ImageFlavor.GRAPHICS2D, - ImageFlavor.BUFFERED_IMAGE, - ImageFlavor.RENDERED_IMAGE, - ImageFlavor.XML_DOM}; Map hints = ImageUtil.getDefaultHints(sessionContext); org.apache.xmlgraphics.image.loader.Image img = manager.getImage( - info, flavors, hints, sessionContext); + info, FLAVOURS, hints, sessionContext); if (img instanceof ImageGraphics2D) { ImageGraphics2D imageG2D = (ImageGraphics2D)img; int width = (int)pos.getWidth(); diff --git a/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java b/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java index 12b269a44..99502096c 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java +++ b/src/java/org/apache/fop/render/java2d/Java2DSVGHandler.java @@ -20,6 +20,8 @@ package org.apache.fop.render.java2d; import java.awt.geom.AffineTransform; +import java.io.IOException; +import java.util.Map; import org.w3c.dom.Document; @@ -29,9 +31,11 @@ import org.apache.batik.gvt.GraphicsNode; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.image.loader.batik.BatikUtil; import org.apache.fop.render.AbstractGenericSVGHandler; import org.apache.fop.render.Renderer; import org.apache.fop.render.RendererContext; +import org.apache.fop.render.RendererContextConstants; import org.apache.fop.svg.SVGEventProducer; import org.apache.fop.svg.SVGUserAgent; @@ -66,6 +70,11 @@ public class Java2DSVGHandler extends AbstractGenericSVGHandler pdfi.height = ((Integer)context.getProperty(HEIGHT)).intValue(); pdfi.currentXPosition = ((Integer)context.getProperty(XPOS)).intValue(); pdfi.currentYPosition = ((Integer)context.getProperty(YPOS)).intValue(); + Map foreign = (Map)context.getProperty(RendererContextConstants.FOREIGN_ATTRIBUTES); + if (foreign != null + && BITMAP.equalsIgnoreCase((String)foreign.get(CONVERSION_MODE))) { + pdfi.paintAsBitmap = true; + } return pdfi; } @@ -83,6 +92,7 @@ public class Java2DSVGHandler extends AbstractGenericSVGHandler public int currentXPosition; /** see Java2D_YPOS */ public int currentYPosition; + public boolean paintAsBitmap; /** {@inheritDoc} */ public String toString() { @@ -91,7 +101,8 @@ public class Java2DSVGHandler extends AbstractGenericSVGHandler + "width = " + width + ", " + "height = " + height + ", " + "currentXPosition = " + currentXPosition + ", " - + "currentYPosition = " + currentYPosition + "}"; + + "currentYPosition = " + currentYPosition + ", " + + "paintAsBitmap = " + paintAsBitmap + "}"; } } @@ -103,17 +114,33 @@ public class Java2DSVGHandler extends AbstractGenericSVGHandler log.debug("renderSVGDocument(" + context + ", " + doc + ", " + info + ")"); } + // fallback paint as bitmap + if (info.paintAsBitmap) { + try { + super.renderSVGDocument(context, doc); + } catch (IOException ioe) { + SVGEventProducer eventProducer = SVGEventProducer.Provider.get( + context.getUserAgent().getEventBroadcaster()); + eventProducer.svgRenderingError(this, ioe, getDocumentURI(doc)); + } + return; + } + int x = info.currentXPosition; int y = info.currentYPosition; SVGUserAgent ua = new SVGUserAgent(context.getUserAgent(), new AffineTransform()); - GVTBuilder builder = new GVTBuilder(); BridgeContext ctx = new BridgeContext(ua); + //Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine) + //to it. + Document clonedDoc = BatikUtil.cloneSVGDocument(doc); + GraphicsNode root; try { - root = builder.build(ctx, doc); + GVTBuilder builder = new GVTBuilder(); + root = builder.build(ctx, clonedDoc); } catch (Exception e) { SVGEventProducer eventProducer = SVGEventProducer.Provider.get( context.getUserAgent().getEventBroadcaster()); @@ -126,8 +153,8 @@ public class Java2DSVGHandler extends AbstractGenericSVGHandler float iw = (float) ctx.getDocumentSize().getWidth() * 1000f; float ih = (float) ctx.getDocumentSize().getHeight() * 1000f; - float w = (float) info.width; - float h = (float) info.height; + float w = info.width; + float h = info.height; AffineTransform origTransform = info.state.getGraph().getTransform(); diff --git a/src/java/org/apache/fop/render/pcl/PCLRenderer.java b/src/java/org/apache/fop/render/pcl/PCLRenderer.java index 509d4538e..b492f1b07 100644 --- a/src/java/org/apache/fop/render/pcl/PCLRenderer.java +++ b/src/java/org/apache/fop/render/pcl/PCLRenderer.java @@ -534,7 +534,7 @@ public class PCLRenderer extends PrintRenderer implements PCLConstants { public Dimension getImageSize() { return paintRect.getSize(); } - + }; g2a.paintImage(painter, rc, paintRect.x, paintRect.y, paintRect.width, paintRect.height); diff --git a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java index 70e0f7eb5..4b0f35bec 100644 --- a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java +++ b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java @@ -29,8 +29,8 @@ import org.apache.fop.pdf.PDFColor; import org.apache.fop.pdf.PDFDocument; import org.apache.fop.pdf.PDFFilterList; import org.apache.fop.pdf.PDFNumber; +import org.apache.fop.pdf.PDFPaintingState; import org.apache.fop.pdf.PDFResourceContext; -import org.apache.fop.pdf.PDFState; import org.apache.fop.pdf.PDFStream; import org.apache.fop.pdf.PDFTextUtil; import org.apache.fop.pdf.PDFXObject; @@ -52,7 +52,7 @@ public class PDFContentGenerator { private PDFStream currentStream; /** drawing state */ - protected PDFState currentState = null; + protected PDFPaintingState currentState = null; /** Text generation utility holding the current font status */ protected PDFTextUtil textutil; @@ -77,7 +77,7 @@ public class PDFContentGenerator { } }; - this.currentState = new PDFState(); + this.currentState = new PDFPaintingState(); } /** @@ -116,7 +116,7 @@ public class PDFContentGenerator { * Returns the {@code PDFState} associated with this instance. * @return the PDF state */ - public PDFState getState() { + public PDFPaintingState getState() { return this.currentState; } @@ -149,7 +149,7 @@ public class PDFContentGenerator { /** {@inheritDoc} */ protected void saveGraphicsState() { endTextObject(); - currentState.push(); + currentState.save(); currentStream.add("q\n"); } @@ -162,7 +162,7 @@ public class PDFContentGenerator { endTextObject(); currentStream.add("Q\n"); if (popState) { - currentState.pop(); + currentState.restore(); } } diff --git a/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java b/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java index 4da7f13cb..102c1ab45 100644 --- a/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java +++ b/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java @@ -98,7 +98,7 @@ public class PDFGraphics2DAdapter extends AbstractGraphics2DAdapter { AffineTransform transform = new AffineTransform(); transform.translate(fx, fy); generator.getState().concatenate(transform); - graphics.setPDFState(generator.getState()); + graphics.setPaintingState(generator.getState()); graphics.setOutputStream(pdfInfo.outputStream); if (pdfInfo.paintAsBitmap) { diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandler.java b/src/java/org/apache/fop/render/pdf/PDFImageHandler.java index f93ee5a97..934d306b9 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandler.java @@ -24,35 +24,15 @@ import java.awt.Rectangle; import java.io.IOException; import org.apache.xmlgraphics.image.loader.Image; -import org.apache.xmlgraphics.image.loader.ImageFlavor; import org.apache.fop.pdf.PDFXObject; +import org.apache.fop.render.ImageHandlerBase; import org.apache.fop.render.RendererContext; /** * This interface is used for handling all sorts of image type for PDF output. */ -public interface PDFImageHandler { - - /** - * Returns the priority for this image handler. A lower value means higher priority. This - * information is used to build the ordered/prioritized list of supported ImageFlavors for - * the PDF renderer. The built-in handlers use priorities between 100 and 999. - * @return a positive integer (>0) indicating the priority - */ - int getPriority(); - - /** - * Returns the {@link ImageFlavor}s supported by this instance - * @return the supported image flavors - */ - ImageFlavor[] getSupportedImageFlavors(); - - /** - * Returns the {@link Image} subclass supported by this instance. - * @return the Image type - */ - Class getSupportedImageClass(); +public interface PDFImageHandler extends ImageHandlerBase { /** * Generates the PDF objects for the given {@link Image} instance. If the handler generates diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java index 610fa274f..18717809d 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java @@ -108,7 +108,7 @@ public class PDFImageHandlerGraphics2D extends AbstractImageHandlerGraphics2D AffineTransform transform = new AffineTransform(); transform.translate(fx, fy); generator.getState().concatenate(transform); - graphics.setPDFState(generator.getState()); + graphics.setPaintingState(generator.getState()); graphics.setOutputStream(generator.getOutputStream()); Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh); diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java index b664a0a24..1d4c733a3 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java @@ -19,171 +19,18 @@ package org.apache.fop.render.pdf; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.xmlgraphics.image.loader.Image; -import org.apache.xmlgraphics.image.loader.ImageFlavor; -import org.apache.xmlgraphics.util.Service; +import org.apache.fop.render.AbstractImageHandlerRegistry; /** * This class holds references to various image handlers used by the PDF renderer. It also * supports automatic discovery of additional handlers available through * the class path. */ -public class PDFImageHandlerRegistry { - - /** the logger */ - private static Log log = LogFactory.getLog(PDFImageHandlerRegistry.class); - - private static final Comparator HANDLER_COMPARATOR = new Comparator() { - public int compare(Object o1, Object o2) { - PDFImageHandler h1 = (PDFImageHandler)o1; - PDFImageHandler h2 = (PDFImageHandler)o2; - return h1.getPriority() - h2.getPriority(); - } - }; - - /** Map containing PDF image handlers for various MIME types */ - private Map handlers = new java.util.HashMap(); - /** List containing the same handlers as above but ordered by priority */ - private List handlerList = new java.util.LinkedList(); +public class PDFImageHandlerRegistry extends AbstractImageHandlerRegistry { - /** Sorted Set of registered handlers */ - private ImageFlavor[] supportedFlavors = new ImageFlavor[0]; - private int handlerRegistrations; - private int lastSync; - - /** - * Default constructor. - */ - public PDFImageHandlerRegistry() { - discoverHandlers(); - } - - /** - * Add an PDFImageHandler. The handler itself is inspected to find out what it supports. - * @param classname the fully qualified class name - */ - public void addHandler(String classname) { - try { - PDFImageHandler handlerInstance - = (PDFImageHandler)Class.forName(classname).newInstance(); - addHandler(handlerInstance); - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("Could not find " - + classname); - } catch (InstantiationException e) { - throw new IllegalArgumentException("Could not instantiate " - + classname); - } catch (IllegalAccessException e) { - throw new IllegalArgumentException("Could not access " - + classname); - } catch (ClassCastException e) { - throw new IllegalArgumentException(classname - + " is not an " - + PDFImageHandler.class.getName()); - } + /** {@inheritDoc} */ + public Class getHandlerClass() { + return PDFImageHandler.class; } - /** - * Add an image handler. The handler itself is inspected to find out what it supports. - * @param handler the PDFImageHandler instance - */ - public synchronized void addHandler(PDFImageHandler handler) { - Class imageClass = handler.getSupportedImageClass(); - this.handlers.put(imageClass, handler); - - //Sorted insert - ListIterator iter = this.handlerList.listIterator(); - while (iter.hasNext()) { - PDFImageHandler h = (PDFImageHandler)iter.next(); - if (HANDLER_COMPARATOR.compare(handler, h) < 0) { - iter.previous(); - break; - } - } - iter.add(handler); - this.handlerRegistrations++; - } - - /** - * Returns an PDFImageHandler which handles an specific image type given the MIME type - * of the image. - * @param img the Image to be handled - * @return the PDFImageHandler responsible for handling the image or null if none is available - */ - public PDFImageHandler getHandler(Image img) { - return getHandler(img.getClass()); - } - - /** - * Returns an PDFImageHandler which handles an specific image type given the MIME type - * of the image. - * @param imageClass the Image subclass for which to get a handler - * @return the PDFImageHandler responsible for handling the image or null if none is available - */ - protected synchronized PDFImageHandler getHandler(Class imageClass) { - PDFImageHandler handler = null; - Class cl = imageClass; - while (cl != null) { - handler = (PDFImageHandler)handlers.get(cl); - if (handler != null) { - break; - } - cl = cl.getSuperclass(); - } - return handler; - } - - /** - * Returns the ordered array of supported image flavors. - * @return the array of image flavors - */ - public synchronized ImageFlavor[] getSupportedFlavors() { - if (this.lastSync != this.handlerRegistrations) { - //Extract all ImageFlavors into a single array - List flavors = new java.util.ArrayList(); - Iterator iter = this.handlerList.iterator(); - while (iter.hasNext()) { - ImageFlavor[] f = ((PDFImageHandler)iter.next()).getSupportedImageFlavors(); - for (int i = 0; i < f.length; i++) { - flavors.add(f[i]); - } - } - this.supportedFlavors = (ImageFlavor[])flavors.toArray(new ImageFlavor[flavors.size()]); - this.lastSync = this.handlerRegistrations; - } - return this.supportedFlavors; - } - - /** - * Discovers PDFImageHandler implementations through the classpath and dynamically - * registers them. - */ - private void discoverHandlers() { - // add mappings from available services - Iterator providers = Service.providers(PDFImageHandler.class); - if (providers != null) { - while (providers.hasNext()) { - PDFImageHandler handler = (PDFImageHandler)providers.next(); - try { - if (log.isDebugEnabled()) { - log.debug("Dynamically adding PDFImageHandler: " - + handler.getClass().getName()); - } - addHandler(handler); - } catch (IllegalArgumentException e) { - log.error("Error while adding PDFImageHandler", e); - } - - } - } - } } diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java index 3764486b7..d1b7aa986 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java @@ -148,7 +148,7 @@ public class PDFImageHandlerSVG implements ImageHandler { generator.comment("SVG start"); //Save state and update coordinate system for the SVG image - generator.getState().push(); + generator.getState().save(); generator.getState().concatenate(imageTransform); //Now that we have the complete transformation matrix for the image, we can update the @@ -157,7 +157,7 @@ public class PDFImageHandlerSVG implements ImageHandler { SVGDOMImplementation.SVG_NAMESPACE_URI, SVGConstants.SVG_A_TAG); aBridge.getCurrentTransform().setTransform(generator.getState().getTransform()); - graphics.setPDFState(generator.getState()); + graphics.setPaintingState(generator.getState()); graphics.setOutputStream(generator.getOutputStream()); try { root.paint(graphics); @@ -167,7 +167,7 @@ public class PDFImageHandlerSVG implements ImageHandler { context.getUserAgent().getEventBroadcaster()); eventProducer.svgRenderingError(this, e, image.getInfo().getOriginalURI()); } - generator.getState().pop(); + generator.getState().restore(); generator.restoreGraphicsState(); generator.comment("SVG end"); } diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerXML.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerXML.java index d111e733f..26ba83371 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerXML.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerXML.java @@ -24,14 +24,12 @@ import java.awt.Rectangle; import java.io.IOException; import java.util.Map; -import org.w3c.dom.Document; - +import org.apache.fop.pdf.PDFXObject; +import org.apache.fop.render.RendererContext; import org.apache.xmlgraphics.image.loader.Image; import org.apache.xmlgraphics.image.loader.ImageFlavor; import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; - -import org.apache.fop.pdf.PDFXObject; -import org.apache.fop.render.RendererContext; +import org.w3c.dom.Document; /** * PDFImageHandler implementation which handles XML-based images. diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index 730acb540..e0e1bab69 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -82,9 +82,9 @@ import org.apache.fop.pdf.PDFLink; import org.apache.fop.pdf.PDFNumber; import org.apache.fop.pdf.PDFOutline; import org.apache.fop.pdf.PDFPage; +import org.apache.fop.pdf.PDFPaintingState; import org.apache.fop.pdf.PDFResourceContext; import org.apache.fop.pdf.PDFResources; -import org.apache.fop.pdf.PDFState; import org.apache.fop.pdf.PDFTextUtil; import org.apache.fop.pdf.PDFXMode; import org.apache.fop.pdf.PDFXObject; @@ -92,8 +92,9 @@ import org.apache.fop.render.AbstractPathOrientedRenderer; import org.apache.fop.render.Graphics2DAdapter; import org.apache.fop.render.RendererContext; import org.apache.fop.traits.RuleStyle; +import org.apache.fop.util.AbstractPaintingState; import org.apache.fop.util.CharUtilities; -import org.apache.fop.util.ColorUtil; +import org.apache.fop.util.AbstractPaintingState.AbstractData; /** * Renderer that renders areas to PDF. @@ -190,7 +191,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf protected int pageHeight; /** Image handler registry */ - private PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry(); + private final PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry(); /** @@ -213,7 +214,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf return this.generator; } - PDFState getState() { + PDFPaintingState getState() { return getGenerator().getState(); } @@ -262,11 +263,8 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf //pvReferences.clear(); pdfResources = null; this.generator = null; - //currentStream = null; currentContext = null; currentPage = null; - //currentState = null; - //this.textutil = null; idPositions.clear(); idGoTos.clear(); @@ -505,7 +503,6 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf } // multiply with current CTM generator.concatenate(new AffineTransform(CTMHelper.toPDFArray(ctm))); - //currentStream.add(CTMHelper.toPDFString(ctm) + " cm\n"); } /** {@inheritDoc} */ @@ -516,11 +513,6 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf /** {@inheritDoc} */ protected void concatenateTransformationMatrix(AffineTransform at) { generator.concatenate(at); - /* - if (!at.isIdentity()) { - currentState.concatenate(at); - currentStream.add(CTMHelper.toPDFString(at, false) + " cm\n"); - }*/ } /** @@ -582,10 +574,10 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf /** * {@inheritDoc} */ - protected void fillRect(float x, float y, float w, float h) { - if (w != 0 && h != 0) { + protected void fillRect(float x, float y, float width, float height) { + if (width > 0 && height > 0) { generator.add(format(x) + " " + format(y) + " " - + format(w) + " " + format(h) + " re f\n"); + + format(width) + " " + format(height) + " re f\n"); } } @@ -607,11 +599,12 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf * @return the saved state stack to recreate later */ protected List breakOutOfStateStack() { + PDFPaintingState paintingState = getState(); List breakOutList = new java.util.ArrayList(); - PDFState.Data data; + AbstractPaintingState.AbstractData data; while (true) { - data = getState().getData(); - if (getState().pop() == null) { + data = paintingState.getData(); + if (paintingState.restore() == null) { break; } if (breakOutList.size() == 0) { @@ -629,10 +622,11 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf */ protected void restoreStateStackAfterBreakOut(List breakOutList) { generator.comment("------ restoring context after break-out..."); - PDFState.Data data; +// currentState.pushAll(breakOutList); + AbstractData data; Iterator i = breakOutList.iterator(); while (i.hasNext()) { - data = (PDFState.Data)i.next(); + data = (AbstractData)i.next(); saveGraphicsState(); AffineTransform at = data.getTransform(); concatenateTransformationMatrix(at); @@ -1131,7 +1125,8 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf info, supportedFlavors, hints, sessionContext); //First check for a dynamically registered handler - PDFImageHandler handler = imageHandlerRegistry.getHandler(img.getClass()); + PDFImageHandler handler + = (PDFImageHandler)imageHandlerRegistry.getHandler(img.getClass()); if (handler != null) { if (log.isDebugEnabled()) { log.debug("Using PDFImageHandler: " + handler.getClass().getName()); @@ -1170,6 +1165,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf this.generator.flushPDFDoc(); } catch (IOException ioe) { // ioexception will be caught later + log.error(ioe.getMessage()); } } @@ -1198,7 +1194,6 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf x, y, width, height, foreignAttributes); context.setProperty(PDFRendererContextConstants.PDF_DOCUMENT, pdfDoc); context.setProperty(PDFRendererContextConstants.OUTPUT_STREAM, ostream); - context.setProperty(PDFRendererContextConstants.PDF_STATE, getState()); context.setProperty(PDFRendererContextConstants.PDF_PAGE, currentPage); context.setProperty(PDFRendererContextConstants.PDF_CONTEXT, currentContext == null ? currentPage : currentContext); diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java b/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java index d416f1147..fccba1c25 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java +++ b/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java @@ -54,6 +54,7 @@ public class PDFRendererConfigurator extends PrintRendererConfigurator /** * Default constructor + * * @param userAgent user agent */ public PDFRendererConfigurator(FOUserAgent userAgent) { @@ -64,6 +65,7 @@ public class PDFRendererConfigurator extends PrintRendererConfigurator * Configure the PDF renderer. * Get the configuration to be used for pdf stream filters, * fonts etc. + * * @param renderer pdf renderer * @throws FOPException fop exception */ @@ -97,7 +99,8 @@ public class PDFRendererConfigurator extends PrintRendererConfigurator if (s != null) { pdfUtil.setXMode(PDFXMode.valueOf(s)); } - Configuration encryptionParamsConfig = cfg.getChild(PDFRenderer.ENCRYPTION_PARAMS, false); + Configuration encryptionParamsConfig + = cfg.getChild(PDFRenderer.ENCRYPTION_PARAMS, false); if (encryptionParamsConfig != null) { PDFEncryptionParams encryptionParams = new PDFEncryptionParams(); Configuration ownerPasswordConfig = encryptionParamsConfig.getChild( @@ -142,8 +145,8 @@ public class PDFRendererConfigurator extends PrintRendererConfigurator if (s != null) { pdfUtil.setOutputProfileURI(s); } - Configuration disableColorSpaceConfig - = cfg.getChild(PDFRenderer.KEY_DISABLE_SRGB_COLORSPACE, false); + Configuration disableColorSpaceConfig = cfg.getChild( + PDFRenderer.KEY_DISABLE_SRGB_COLORSPACE, false); if (disableColorSpaceConfig != null) { pdfUtil.setDisableSRGBColorSpace( disableColorSpaceConfig.getValueAsBoolean(false)); @@ -152,6 +155,7 @@ public class PDFRendererConfigurator extends PrintRendererConfigurator /** * Builds a filter map from an Avalon Configuration object. + * * @param cfg the Configuration object * @return Map the newly built filter map * @throws ConfigurationException if a filter list is defined twice diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererContextConstants.java b/src/java/org/apache/fop/render/pdf/PDFRendererContextConstants.java index de51aabc7..11380bf59 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRendererContextConstants.java +++ b/src/java/org/apache/fop/render/pdf/PDFRendererContextConstants.java @@ -29,9 +29,6 @@ public interface PDFRendererContextConstants extends RendererContextConstants { /** The PDF document that this image is being drawn into. */ String PDF_DOCUMENT = "pdfDoc"; - /** The current pdf state. */ - String PDF_STATE = "pdfState"; - /** The current PDF page for page renference and as a resource context. */ String PDF_PAGE = "pdfPage"; diff --git a/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java b/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java index 11d9b1c3f..8f7aad300 100644 --- a/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java @@ -36,11 +36,9 @@ import org.apache.batik.util.SVGConstants; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.xmlgraphics.util.QName; - import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.fo.extensions.ExtensionElementMapping; import org.apache.fop.fonts.FontInfo; +import org.apache.fop.image.loader.batik.BatikUtil; import org.apache.fop.pdf.PDFDocument; import org.apache.fop.pdf.PDFPage; import org.apache.fop.pdf.PDFResourceContext; @@ -89,9 +87,9 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler pdfi.currentYPosition = ((Integer)context.getProperty(YPOS)).intValue(); pdfi.cfg = (Configuration)context.getProperty(HANDLER_CONFIGURATION); Map foreign = (Map)context.getProperty(RendererContextConstants.FOREIGN_ATTRIBUTES); - QName qName = new QName(ExtensionElementMapping.URI, null, "conversion-mode"); + if (foreign != null - && "bitmap".equalsIgnoreCase((String)foreign.get(qName))) { + && BITMAP.equalsIgnoreCase((String)foreign.get(CONVERSION_MODE))) { pdfi.paintAsBitmap = true; } return pdfi; @@ -105,8 +103,6 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler public PDFDocument pdfDoc; /** see OUTPUT_STREAM */ public OutputStream outputStream; - /** see PDF_STATE */ - //public PDFState pdfState; /** see PDF_PAGE */ public PDFPage pdfPage; /** see PDF_CONTEXT */ @@ -167,8 +163,6 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler AffineTransform resolutionScaling = new AffineTransform(); resolutionScaling.scale(s, s); - GVTBuilder builder = new GVTBuilder(); - //Controls whether text painted by Batik is generated using text or path operations boolean strokeText = false; Configuration cfg = pdfInfo.cfg; @@ -182,10 +176,14 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler userAgent.getImageSessionContext(), new AffineTransform()); + //Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine) + //to it. + Document clonedDoc = BatikUtil.cloneSVGDocument(doc); + GraphicsNode root; try { - root = builder.build(ctx, doc); - builder = null; + GVTBuilder builder = new GVTBuilder(); + root = builder.build(ctx, clonedDoc); } catch (Exception e) { SVGEventProducer eventProducer = SVGEventProducer.Provider.get( context.getUserAgent().getEventBroadcaster()); @@ -196,8 +194,8 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler float w = (float)ctx.getDocumentSize().getWidth() * 1000f; float h = (float)ctx.getDocumentSize().getHeight() * 1000f; - float sx = pdfInfo.width / (float)w; - float sy = pdfInfo.height / (float)h; + float sx = pdfInfo.width / w; + float sy = pdfInfo.height / h; //Scaling and translation for the bounding box of the image AffineTransform scaling = new AffineTransform( @@ -247,7 +245,7 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler generator.comment("SVG start"); //Save state and update coordinate system for the SVG image - generator.getState().push(); + generator.getState().save(); generator.getState().concatenate(imageTransform); //Now that we have the complete transformation matrix for the image, we can update the @@ -256,7 +254,7 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler SVGDOMImplementation.SVG_NAMESPACE_URI, SVGConstants.SVG_A_TAG); aBridge.getCurrentTransform().setTransform(generator.getState().getTransform()); - graphics.setPDFState(generator.getState()); + graphics.setPaintingState(generator.getState()); graphics.setOutputStream(pdfInfo.outputStream); try { root.paint(graphics); @@ -266,7 +264,7 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler context.getUserAgent().getEventBroadcaster()); eventProducer.svgRenderingError(this, e, getDocumentURI(doc)); } - generator.getState().pop(); + generator.getState().restore(); generator.restoreGraphicsState(); generator.comment("SVG end"); } diff --git a/src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java b/src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java index e5d8200b7..542a69a4a 100644 --- a/src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java +++ b/src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java @@ -33,6 +33,7 @@ import org.apache.xmlgraphics.util.QName; import org.apache.fop.fo.extensions.ExtensionElementMapping; import org.apache.fop.render.AbstractGraphics2DAdapter; +import org.apache.fop.render.Graphics2DAdapter; import org.apache.fop.render.RendererContext; import org.apache.fop.render.RendererContextConstants; import org.apache.fop.render.RendererContext.RendererContextWrapper; diff --git a/src/java/org/apache/fop/render/ps/PSSVGHandler.java b/src/java/org/apache/fop/render/ps/PSSVGHandler.java index 1e65dfb98..7171efb4e 100644 --- a/src/java/org/apache/fop/render/ps/PSSVGHandler.java +++ b/src/java/org/apache/fop/render/ps/PSSVGHandler.java @@ -37,6 +37,7 @@ import org.apache.xmlgraphics.java2d.ps.PSGraphics2D; import org.apache.xmlgraphics.ps.PSGenerator; import org.apache.fop.fonts.FontInfo; +import org.apache.fop.image.loader.batik.BatikUtil; import org.apache.fop.render.AbstractGenericSVGHandler; import org.apache.fop.render.Renderer; import org.apache.fop.render.RendererContext; @@ -258,7 +259,6 @@ public class PSSVGHandler extends AbstractGenericSVGHandler PSGraphics2D graphics = new PSGraphics2D(strokeText, gen); graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext()); - GVTBuilder builder = new GVTBuilder(); NativeTextHandler nativeTextHandler = null; BridgeContext ctx = new BridgeContext(ua); if (!strokeText) { @@ -271,9 +271,14 @@ public class PSSVGHandler extends AbstractGenericSVGHandler ctx.putBridge(tBridge); } + //Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine) + //to it. + Document clonedDoc = BatikUtil.cloneSVGDocument(doc); + GraphicsNode root; try { - root = builder.build(ctx, doc); + GVTBuilder builder = new GVTBuilder(); + root = builder.build(ctx, clonedDoc); } catch (Exception e) { SVGEventProducer eventProducer = SVGEventProducer.Provider.get( context.getUserAgent().getEventBroadcaster()); @@ -288,7 +293,6 @@ public class PSSVGHandler extends AbstractGenericSVGHandler float sy = psInfo.getHeight() / h; ctx = null; - builder = null; try { gen.commentln("%FOPBeginSVG"); diff --git a/src/java/org/apache/fop/render/ps/PSTextPainter.java b/src/java/org/apache/fop/render/ps/PSTextPainter.java index 31cb4b605..a318c6465 100644 --- a/src/java/org/apache/fop/render/ps/PSTextPainter.java +++ b/src/java/org/apache/fop/render/ps/PSTextPainter.java @@ -19,41 +19,35 @@ package org.apache.fop.render.ps; +import java.awt.Color; import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.font.TextAttribute; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; -/* java.awt.Font is not imported to avoid confusion with - org.apache.fop.fonts.Font */ - +import java.io.IOException; import java.text.AttributedCharacterIterator; import java.text.CharacterIterator; -import java.awt.font.TextAttribute; -import java.awt.Shape; -import java.awt.Paint; -import java.awt.Stroke; -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.xmlgraphics.java2d.ps.PSGraphics2D; -import org.apache.xmlgraphics.java2d.TextHandler; +import java.util.List; 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.TextPainter; import org.apache.batik.gvt.font.GVTFontFamily; import org.apache.batik.gvt.renderer.StrokingTextPainter; - +import org.apache.batik.gvt.text.GVTAttributedCharacterIterator; +import org.apache.batik.gvt.text.Mark; +import org.apache.batik.gvt.text.TextPaintInfo; +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.fonts.FontTriplet; +import org.apache.xmlgraphics.java2d.ps.PSGraphics2D; + /** * Renders the attributed character iterator of a <tt>TextNode</tt>. @@ -74,8 +68,8 @@ public class PSTextPainter implements TextPainter { /** the logger for this class */ protected Log log = LogFactory.getLog(PSTextPainter.class); - private NativeTextHandler nativeTextHandler; - private FontInfo fontInfo; + private final NativeTextHandler nativeTextHandler; + private final FontInfo fontInfo; /** * Use the stroking text painter to get the bounds and shape. @@ -317,7 +311,7 @@ public class PSTextPainter implements TextPainter { } drawPrimitiveString(g2d, loc, font, txt, tx); - loc.setLocation(loc.getX() + (double)advance, loc.getY()); + loc.setLocation(loc.getX() + advance, loc.getY()); return loc; } @@ -422,7 +416,7 @@ public class PSTextPainter implements TextPainter { fStyle |= java.awt.Font.ITALIC; } return new java.awt.Font(font.getFontName(), fStyle, - (int)(font.getFontSize() / 1000)); + (font.getFontSize() / 1000)); } private float getStringWidth(String str, Font font) { diff --git a/src/java/org/apache/fop/render/ps/extensions/PSCommentAfterElement.java b/src/java/org/apache/fop/render/ps/extensions/PSCommentAfterElement.java index c47649eb1..eb0f4d833 100644 --- a/src/java/org/apache/fop/render/ps/extensions/PSCommentAfterElement.java +++ b/src/java/org/apache/fop/render/ps/extensions/PSCommentAfterElement.java @@ -43,7 +43,7 @@ public class PSCommentAfterElement extends AbstractPSCommentElement { * @see org.apache.fop.fo.FONode#getLocalName() */ public String getLocalName() { - return ELEMENT; + return PSCommentAfter.ELEMENT; } /** diff --git a/src/java/org/apache/fop/render/ps/extensions/PSCommentBeforeElement.java b/src/java/org/apache/fop/render/ps/extensions/PSCommentBeforeElement.java index f441553b7..951e685b3 100644 --- a/src/java/org/apache/fop/render/ps/extensions/PSCommentBeforeElement.java +++ b/src/java/org/apache/fop/render/ps/extensions/PSCommentBeforeElement.java @@ -43,7 +43,7 @@ public class PSCommentBeforeElement extends AbstractPSCommentElement { * @see org.apache.fop.fo.FONode#getLocalName() */ public String getLocalName() { - return ELEMENT; + return PSCommentBefore.ELEMENT; } /** diff --git a/src/java/org/apache/fop/render/ps/extensions/PSExtensionElementMapping.java b/src/java/org/apache/fop/render/ps/extensions/PSExtensionElementMapping.java index d1a1ede37..2044385a8 100644 --- a/src/java/org/apache/fop/render/ps/extensions/PSExtensionElementMapping.java +++ b/src/java/org/apache/fop/render/ps/extensions/PSExtensionElementMapping.java @@ -42,8 +42,8 @@ public class PSExtensionElementMapping extends ElementMapping { foObjs.put(PSSetupCodeElement.ELEMENT, new PSSetupCodeMaker()); foObjs.put(PSPageSetupCodeElement.ELEMENT, new PSPageSetupCodeMaker()); foObjs.put(PSSetPageDeviceElement.ELEMENT, new PSSetPageDeviceMaker()); - foObjs.put(PSCommentBeforeElement.ELEMENT, new PSCommentBeforeMaker()); - foObjs.put(PSCommentAfterElement.ELEMENT, new PSCommentAfterMaker()); + foObjs.put(PSCommentBefore.ELEMENT, new PSCommentBeforeMaker()); + foObjs.put(PSCommentAfter.ELEMENT, new PSCommentAfterMaker()); } } diff --git a/src/java/org/apache/fop/svg/AbstractFOPBridgeContext.java b/src/java/org/apache/fop/svg/AbstractFOPBridgeContext.java new file mode 100644 index 000000000..ae4d67516 --- /dev/null +++ b/src/java/org/apache/fop/svg/AbstractFOPBridgeContext.java @@ -0,0 +1,142 @@ +/* + * 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.svg; + +import java.awt.geom.AffineTransform; +import java.lang.reflect.Constructor; + +import org.apache.batik.bridge.Bridge; +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.bridge.DocumentLoader; +import org.apache.batik.bridge.UserAgent; +import org.apache.fop.fonts.FontInfo; +import org.apache.xmlgraphics.image.loader.ImageManager; +import org.apache.xmlgraphics.image.loader.ImageSessionContext; + +/** + * A FOP base implementation of a Batik BridgeContext. + */ +public abstract class AbstractFOPBridgeContext extends BridgeContext { + + /** The font list. */ + protected final FontInfo fontInfo; + + protected final ImageManager imageManager; + protected final ImageSessionContext imageSessionContext; + + protected final AffineTransform linkTransform; + + /** + * Constructs a new bridge context. + * @param userAgent the user agent + * @param loader the Document Loader to use for referenced documents. + * @param fontInfo the font list for the text painter, may be null + * in which case text is painted as shapes + * @param linkTransform AffineTransform to properly place links, + * may be null + * @param imageManager an image manager + * @param imageSessionContext an image session context + * @param linkTransform AffineTransform to properly place links, + * may be null + */ + public AbstractFOPBridgeContext(UserAgent userAgent, + DocumentLoader loader, + FontInfo fontInfo, + ImageManager imageManager, + ImageSessionContext imageSessionContext, + AffineTransform linkTransform) { + super(userAgent, loader); + this.fontInfo = fontInfo; + this.imageManager = imageManager; + this.imageSessionContext = imageSessionContext; + this.linkTransform = linkTransform; + } + + /** + * Constructs a new bridge context. + * @param userAgent the user agent + * @param fontInfo the font list for the text painter, may be null + * in which case text is painted as shapes + * @param imageManager an image manager + * @param imageSessionContext an image session context + * @param linkTransform AffineTransform to properly place links, + * may be null + */ + public AbstractFOPBridgeContext(UserAgent userAgent, + FontInfo fontInfo, + ImageManager imageManager, + ImageSessionContext imageSessionContext, + AffineTransform linkTransform) { + super(userAgent); + this.fontInfo = fontInfo; + this.imageManager = imageManager; + this.imageSessionContext = imageSessionContext; + this.linkTransform = linkTransform; + } + + /** + * Constructs a new bridge context. + * @param userAgent the user agent + * @param fontInfo the font list for the text painter, may be null + * in which case text is painted as shapes + * @param imageManager an image manager + * @param imageSessionContext an image session context + */ + public AbstractFOPBridgeContext(UserAgent userAgent, + FontInfo fontInfo, + ImageManager imageManager, + ImageSessionContext imageSessionContext) { + this(userAgent, fontInfo, imageManager, imageSessionContext, null); + } + + /** + * Returns the ImageManager to be used by the ImageElementBridge. + * @return the image manager + */ + public ImageManager getImageManager() { + return this.imageManager; + } + + /** + * Returns the ImageSessionContext to be used by the ImageElementBridge. + * @return the image session context + */ + public ImageSessionContext getImageSessionContext() { + return this.imageSessionContext; + } + + protected void putElementBridgeConditional(String className, String testFor) { + try { + Class.forName(testFor); + //if we get here the test class is available + + Class clazz = Class.forName(className); + Constructor constructor = clazz.getConstructor(new Class[] {FontInfo.class}); + putBridge((Bridge)constructor.newInstance(new Object[] {fontInfo})); + } catch (Throwable t) { + //simply ignore (bridges instantiated over this method are optional) + } + } + + // Make sure any 'sub bridge contexts' also have our bridges. + //TODO There's no matching method in the super-class here + public abstract BridgeContext createBridgeContext(); + +} diff --git a/src/java/org/apache/fop/svg/AbstractFOPImageElementBridge.java b/src/java/org/apache/fop/svg/AbstractFOPImageElementBridge.java new file mode 100644 index 000000000..31895cebe --- /dev/null +++ b/src/java/org/apache/fop/svg/AbstractFOPImageElementBridge.java @@ -0,0 +1,284 @@ +/* + * 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.svg; + +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.Rectangle2D; + +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.bridge.SVGImageElementBridge; +import org.apache.batik.gvt.AbstractGraphicsNode; +import org.apache.batik.gvt.GraphicsNode; +import org.apache.batik.util.ParsedURL; +import org.apache.xmlgraphics.image.loader.Image; +import org.apache.xmlgraphics.image.loader.ImageException; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageManager; +import org.apache.xmlgraphics.image.loader.ImageSessionContext; +import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; +import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; +import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG; +import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; +import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; +import org.w3c.dom.Element; +import org.w3c.dom.svg.SVGDocument; + +/** + * Bridge class for the <image> element when jpeg images. + * + * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a> + */ +public abstract class AbstractFOPImageElementBridge extends SVGImageElementBridge { + + /** + * Constructs a new bridge for the <image> element. + */ + public AbstractFOPImageElementBridge() { } + + /** + * Create the raster image node. + * THis checks if it is a jpeg file and creates a jpeg node + * so the jpeg can be inserted directly into the pdf document. + * @param ctx the bridge context + * @param imageElement the svg element for the image + * @param purl the parsed url for the image resource + * @return a new graphics node + */ + protected GraphicsNode createImageGraphicsNode + (BridgeContext ctx, Element imageElement, ParsedURL purl) { + AbstractFOPBridgeContext bridgeCtx = (AbstractFOPBridgeContext)ctx; + + ImageManager manager = bridgeCtx.getImageManager(); + ImageSessionContext sessionContext = bridgeCtx.getImageSessionContext(); + try { + ImageInfo info = manager.getImageInfo(purl.toString(), sessionContext); + ImageFlavor[] supportedFlavors = getSupportedFlavours(); + Image image = manager.getImage(info, supportedFlavors, sessionContext); + + //TODO color profile overrides aren't handled, yet! + //ICCColorSpaceExt colorspaceOverride = extractColorSpace(e, ctx); + AbstractGraphicsNode specializedNode = null; + if (image instanceof ImageXMLDOM) { + ImageXMLDOM xmlImage = (ImageXMLDOM)image; + if (xmlImage.getDocument() instanceof SVGDocument) { + return createSVGImageNode(ctx, imageElement, + (SVGDocument)xmlImage.getDocument()); + } else { + //Convert image to Graphics2D + image = manager.convertImage(xmlImage, + new ImageFlavor[] {ImageFlavor.GRAPHICS2D}); + } + } + if (image instanceof ImageRawJPEG) { + specializedNode = createLoaderImageNode(image, ctx, imageElement, purl); + } else if (image instanceof ImageRawCCITTFax) { + specializedNode = createLoaderImageNode(image, ctx, imageElement, purl); + } else if (image instanceof ImageGraphics2D) { + ImageGraphics2D g2dImage = (ImageGraphics2D)image; + specializedNode = new Graphics2DNode(g2dImage); + } else { + ctx.getUserAgent().displayError( + new ImageException("Cannot convert an image to a usable format: " + purl)); + } + + Rectangle2D imgBounds = getImageBounds(ctx, imageElement); + Rectangle2D bounds = specializedNode.getPrimitiveBounds(); + float [] vb = new float[4]; + vb[0] = 0; // x + vb[1] = 0; // y + vb[2] = (float) bounds.getWidth(); // width + vb[3] = (float) bounds.getHeight(); // height + + // handles the 'preserveAspectRatio', 'overflow' and 'clip' + // and sets the appropriate AffineTransform to the image node + initializeViewport(ctx, imageElement, specializedNode, vb, imgBounds); + return specializedNode; + } catch (Exception e) { + ctx.getUserAgent().displayError(e); + } + + return superCreateGraphicsNode(ctx, imageElement, purl); + } + + /** + * Calls the superclass' createImageGraphicNode() method to create the normal GraphicsNode. + * @param ctx the bridge context + * @param imageElement the image element + * @param purl the parsed URL + * @return the newly created graphics node + * @see org.apache.batik.bridge.SVGImageElementBridge#createGraphicsNode(BridgeContext, Element) + */ + protected GraphicsNode superCreateGraphicsNode + (BridgeContext ctx, Element imageElement, ParsedURL purl) { + return super.createImageGraphicsNode(ctx, imageElement, purl); + } + + /** + * Returns an array of supported image flavours + * + * @return an array of supported image flavours + */ + protected abstract ImageFlavor[] getSupportedFlavours(); + + /** + * Creates a loader image node implementation + * @param purl the parsed url + * @param imageElement the image element + * @param ctx the batik bridge context + * @param image the image + * + * @return a loader image node implementation + */ + protected LoaderImageNode createLoaderImageNode( + Image image, BridgeContext ctx, Element imageElement, ParsedURL purl) { + return new LoaderImageNode(image, ctx, imageElement, purl); + } + + /** + * An image node for natively handled Image instance. + * This holds a natively handled image so that it can be drawn into + * the PDFGraphics2D. + */ + public class LoaderImageNode extends AbstractGraphicsNode { + + protected final Image image; + protected final BridgeContext ctx; + protected final Element imageElement; + protected final ParsedURL purl; + protected GraphicsNode origGraphicsNode = null; + + /** + * Create a new image node for drawing natively handled images + * into PDF graphics. + * @param image the JPEG image + * @param ctx the bridge context + * @param imageElement the SVG image element + * @param purl the URL to the image + */ + public LoaderImageNode(Image image, BridgeContext ctx, + Element imageElement, ParsedURL purl) { + this.image = image; + this.ctx = ctx; + this.imageElement = imageElement; + this.purl = purl; + } + + /** {@inheritDoc} */ + public Shape getOutline() { + return getPrimitiveBounds(); + } + + /** {@inheritDoc} */ + public void primitivePaint(Graphics2D g2d) { + if (g2d instanceof NativeImageHandler) { + NativeImageHandler nativeImageHandler = (NativeImageHandler) g2d; + float x = 0; + float y = 0; + try { + float width = image.getSize().getWidthPx(); + float height = image.getSize().getHeightPx(); + nativeImageHandler.addNativeImage(image, x, y, width, height); + } catch (Exception e) { + ctx.getUserAgent().displayError(e); + } + } else { + // Not going directly into PDF so use + // original implementation so filters etc work. + if (origGraphicsNode == null) { + // Haven't constructed base class Graphics Node, + // so do so now. + origGraphicsNode + = superCreateGraphicsNode(ctx, imageElement, purl); + } + origGraphicsNode.primitivePaint(g2d); + } + } + + /** {@inheritDoc} */ + public Rectangle2D getGeometryBounds() { + return getPrimitiveBounds(); + } + + /** {@inheritDoc} */ + public Rectangle2D getPrimitiveBounds() { + return new Rectangle2D.Double(0, 0, + image.getSize().getWidthPx(), + image.getSize().getHeightPx()); + } + + /** {@inheritDoc} */ + public Rectangle2D getSensitiveBounds() { + //No interactive features, just return primitive bounds + return getPrimitiveBounds(); + } + + } + + /** + * A node that holds a Graphics2D image. + */ + public class Graphics2DNode extends AbstractGraphicsNode { + + private final ImageGraphics2D image; + + /** + * Create a new Graphics2D node. + * @param g2d the Graphics2D image + */ + public Graphics2DNode(ImageGraphics2D g2d) { + this.image = g2d; + } + + /** {@inheritDoc} */ + public Shape getOutline() { + return getPrimitiveBounds(); + } + + /** {@inheritDoc} */ + public void primitivePaint(Graphics2D g2d) { + int width = image.getSize().getWidthPx(); + int height = image.getSize().getHeightPx(); + Rectangle2D area = new Rectangle2D.Double(0, 0, width, height); + Graphics2DImagePainter painter = image.getGraphics2DImagePainter(); + painter.paint(g2d, area); + } + + /** {@inheritDoc} */ + public Rectangle2D getGeometryBounds() { + return getPrimitiveBounds(); + } + + /** {@inheritDoc} */ + public Rectangle2D getPrimitiveBounds() { + return new Rectangle2D.Double(0, 0, + image.getSize().getWidthPx(), + image.getSize().getHeightPx()); + } + + /** {@inheritDoc} */ + public Rectangle2D getSensitiveBounds() { + //No interactive features, just return primitive bounds + return getPrimitiveBounds(); + } + + } +} diff --git a/src/java/org/apache/fop/svg/AbstractFOPTextElementBridge.java b/src/java/org/apache/fop/svg/AbstractFOPTextElementBridge.java new file mode 100644 index 000000000..53b8e2ad5 --- /dev/null +++ b/src/java/org/apache/fop/svg/AbstractFOPTextElementBridge.java @@ -0,0 +1,113 @@ +/* + * 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.svg; + +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.bridge.SVGTextElementBridge; +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. + * + * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a> + */ +public abstract class AbstractFOPTextElementBridge extends SVGTextElementBridge { + + /** text painter */ + protected TextPainter textPainter; + + /** + * Main constructor + * + * @param textPainter the text painter + */ + public AbstractFOPTextElementBridge(TextPainter 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) { + //Set our own text painter + ((TextNode)node).setTextPainter(textPainter); + } + return node; + } + + /** + * 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 Graphics2D + */ + protected 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/svg/AbstractFOPTextPainter.java b/src/java/org/apache/fop/svg/AbstractFOPTextPainter.java new file mode 100644 index 000000000..560c76cb5 --- /dev/null +++ b/src/java/org/apache/fop/svg/AbstractFOPTextPainter.java @@ -0,0 +1,528 @@ +/* + * 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.svg; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Shape; +import java.awt.font.TextAttribute; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.text.AttributedCharacterIterator; +import java.text.CharacterIterator; +import java.util.Iterator; +import java.util.List; + +import org.apache.batik.dom.svg.SVGOMTextElement; +import org.apache.batik.gvt.TextNode; +import org.apache.batik.gvt.TextPainter; +import org.apache.batik.gvt.font.GVTFontFamily; +import org.apache.batik.gvt.renderer.StrokingTextPainter; +import org.apache.batik.gvt.text.GVTAttributedCharacterIterator; +import org.apache.batik.gvt.text.Mark; +import org.apache.batik.gvt.text.TextPaintInfo; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.afp.AFPGraphics2D; +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 Graphics2D 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 abstract class AbstractFOPTextPainter implements TextPainter { + + /** the logger for this class */ + protected Log log = LogFactory.getLog(AbstractFOPTextPainter.class); + + private final FOPTextHandler nativeTextHandler; + + /** + * 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 AbstractFOPTextPainter(FOPTextHandler 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; + + Font font = getFont(aci); + String text = getText(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); + AffineTransform at = g2d.getTransform(); + loc = at.transform(loc, null); + + // font + Font font = getFont(aci); + if (font != null) { + 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); + + // text + 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 + double x = loc.getX(); + double y = loc.getY(); + try { + try { + nativeTextHandler.drawString(g2d, txt, (float)x + tx, (float)y); + } catch (IOException ioe) { + if (g2d instanceof AFPGraphics2D) { + ((AFPGraphics2D)g2d).handleIOException(ioe); + } + } + } finally { + nativeTextHandler.setOverrideFont(null); + } + loc.setLocation(loc.getX() + 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)) + ? Font.STYLE_ITALIC + : Font.STYLE_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 getFont(AttributedCharacterIterator aci) { + Float fontSize = (Float)aci.getAttribute(TextAttribute.SIZE); + 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 AFP 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 AFP 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 AFP 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 AFP 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 AFP 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 AFP 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 AFP 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/svg/FOPTextHandler.java b/src/java/org/apache/fop/svg/FOPTextHandler.java new file mode 100644 index 000000000..8fa9eeedd --- /dev/null +++ b/src/java/org/apache/fop/svg/FOPTextHandler.java @@ -0,0 +1,27 @@ +/* + * 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.svg; + +public interface FOPTextHandler extends org.apache.xmlgraphics.java2d.TextHandler { + + void setOverrideFont(org.apache.fop.fonts.Font font); + + org.apache.fop.fonts.FontInfo getFontInfo(); +} diff --git a/src/java/org/apache/fop/svg/GraphicsConfiguration.java b/src/java/org/apache/fop/svg/GraphicsConfiguration.java index ca3b3363c..881096b9a 100644 --- a/src/java/org/apache/fop/svg/GraphicsConfiguration.java +++ b/src/java/org/apache/fop/svg/GraphicsConfiguration.java @@ -17,7 +17,6 @@ /* $Id$ */ - package org.apache.fop.svg; import java.awt.image.VolatileImage; diff --git a/src/java/org/apache/fop/svg/NativeImageHandler.java b/src/java/org/apache/fop/svg/NativeImageHandler.java new file mode 100644 index 000000000..8e74cba1d --- /dev/null +++ b/src/java/org/apache/fop/svg/NativeImageHandler.java @@ -0,0 +1,40 @@ +/* + * 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.svg; + +public interface NativeImageHandler { + + /** + * Add a natively handled image directly to the document. + * This is used by the ImageElementBridge to draw a natively handled image + * (like JPEG or CCITT images) + * directly into the document rather than converting the image into + * a bitmap and increasing the size. + * + * @param image the image to draw + * @param x the x position + * @param y the y position + * @param width the width to draw the image + * @param height the height to draw the image + */ + void addNativeImage(org.apache.xmlgraphics.image.loader.Image image, float x, float y, + float width, float height); + +} diff --git a/src/java/org/apache/fop/svg/PDFBridgeContext.java b/src/java/org/apache/fop/svg/PDFBridgeContext.java index fdf83784f..364c7a6f3 100644 --- a/src/java/org/apache/fop/svg/PDFBridgeContext.java +++ b/src/java/org/apache/fop/svg/PDFBridgeContext.java @@ -20,30 +20,20 @@ package org.apache.fop.svg; import java.awt.geom.AffineTransform; -import java.lang.reflect.Constructor; -import org.apache.batik.bridge.Bridge; import org.apache.batik.bridge.BridgeContext; import org.apache.batik.bridge.DocumentLoader; +import org.apache.batik.bridge.SVGTextElementBridge; import org.apache.batik.bridge.UserAgent; - +import org.apache.batik.gvt.TextPainter; +import org.apache.fop.fonts.FontInfo; import org.apache.xmlgraphics.image.loader.ImageManager; import org.apache.xmlgraphics.image.loader.ImageSessionContext; -import org.apache.fop.fonts.FontInfo; - /** * BridgeContext which registers the custom bridges for PDF output. */ -public class PDFBridgeContext extends BridgeContext { - - /** The font list. */ - private final FontInfo fontInfo; - - private final ImageManager imageManager; - private final ImageSessionContext imageSessionContext; - - private AffineTransform linkTransform; +public class PDFBridgeContext extends AbstractFOPBridgeContext { /** * Constructs a new bridge context. @@ -53,18 +43,16 @@ public class PDFBridgeContext extends BridgeContext { * in which case text is painted as shapes * @param linkTransform AffineTransform to properly place links, * may be null + * @param imageManager an image manager + * @param imageSessionContext an image session context + * @param linkTransform AffineTransform to properly place links, + * may be null */ - public PDFBridgeContext(UserAgent userAgent, - DocumentLoader loader, - FontInfo fontInfo, - ImageManager imageManager, - ImageSessionContext imageSessionContext, - AffineTransform linkTransform) { - super(userAgent, loader); - this.fontInfo = fontInfo; - this.imageManager = imageManager; - this.imageSessionContext = imageSessionContext; - this.linkTransform = linkTransform; + public PDFBridgeContext(UserAgent userAgent, DocumentLoader documentLoader, + FontInfo fontInfo, ImageManager imageManager, + ImageSessionContext imageSessionContext, + AffineTransform linkTransform) { + super(userAgent, documentLoader, fontInfo, imageManager, imageSessionContext, linkTransform); } /** @@ -72,19 +60,12 @@ public class PDFBridgeContext extends BridgeContext { * @param userAgent the user agent * @param fontInfo the font list for the text painter, may be null * in which case text is painted as shapes - * @param linkTransform AffineTransform to properly place links, - * may be null + * @param imageManager an image manager + * @param imageSessionContext an image session context */ - public PDFBridgeContext(UserAgent userAgent, - FontInfo fontInfo, - ImageManager imageManager, - ImageSessionContext imageSessionContext, - AffineTransform linkTransform) { - super(userAgent); - this.fontInfo = fontInfo; - this.imageManager = imageManager; - this.imageSessionContext = imageSessionContext; - this.linkTransform = linkTransform; + public PDFBridgeContext(UserAgent userAgent, FontInfo fontInfo, + ImageManager imageManager, ImageSessionContext imageSessionContext) { + super(userAgent, fontInfo, imageManager, imageSessionContext); } /** @@ -92,41 +73,15 @@ public class PDFBridgeContext extends BridgeContext { * @param userAgent the user agent * @param fontInfo the font list for the text painter, may be null * in which case text is painted as shapes + * @param imageManager an image manager + * @param imageSessionContext an image session context + * @param linkTransform AffineTransform to properly place links, + * may be null */ - public PDFBridgeContext(UserAgent userAgent, - FontInfo fontInfo, - ImageManager imageManager, - ImageSessionContext imageSessionContext) { - this(userAgent, fontInfo, imageManager, imageSessionContext, null); - } - - /** - * Returns the ImageManager to be used by the ImageElementBridge. - * @return the image manager - */ - public ImageManager getImageManager() { - return this.imageManager; - } - - /** - * Returns the ImageSessionContext to be used by the ImageElementBridge. - * @return the image session context - */ - public ImageSessionContext getImageSessionContext() { - return this.imageSessionContext; - } - - private void putPDFElementBridgeConditional(String className, String testFor) { - try { - Class.forName(testFor); - //if we get here the test class is available - - Class clazz = Class.forName(className); - Constructor constructor = clazz.getConstructor(new Class[] {FontInfo.class}); - putBridge((Bridge)constructor.newInstance(new Object[] {fontInfo})); - } catch (Throwable t) { - //simply ignore (bridges instantiated over this method are optional) - } + public PDFBridgeContext(SVGUserAgent userAgent, FontInfo fontInfo, + ImageManager imageManager, ImageSessionContext imageSessionContext, + AffineTransform linkTransform) { + super(userAgent, fontInfo, imageManager, imageSessionContext, linkTransform); } /** {@inheritDoc} */ @@ -134,23 +89,24 @@ public class PDFBridgeContext extends BridgeContext { super.registerSVGBridges(); if (fontInfo != null) { - PDFTextElementBridge textElementBridge = new PDFTextElementBridge(fontInfo); + TextPainter textPainter = new PDFTextPainter(fontInfo); + SVGTextElementBridge textElementBridge = new PDFTextElementBridge(textPainter); putBridge(textElementBridge); //Batik flow text extension (may not always be available) //putBridge(new PDFBatikFlowTextElementBridge(fontInfo); - putPDFElementBridgeConditional( + putElementBridgeConditional( "org.apache.fop.svg.PDFBatikFlowTextElementBridge", "org.apache.batik.extension.svg.BatikFlowTextElementBridge"); //SVG 1.2 flow text support //putBridge(new PDFSVG12TextElementBridge(fontInfo)); //-->Batik 1.7 - putPDFElementBridgeConditional( + putElementBridgeConditional( "org.apache.fop.svg.PDFSVG12TextElementBridge", "org.apache.batik.bridge.svg12.SVG12TextElementBridge"); //putBridge(new PDFSVGFlowRootElementBridge(fontInfo)); - putPDFElementBridgeConditional( + putElementBridgeConditional( "org.apache.fop.svg.PDFSVGFlowRootElementBridge", "org.apache.batik.bridge.svg12.SVGFlowRootElementBridge"); } diff --git a/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java index dd13df1c4..cc6e06978 100644 --- a/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java +++ b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java @@ -19,30 +19,30 @@ package org.apache.fop.svg; -import org.apache.fop.Version; -import org.apache.fop.pdf.PDFDocument; -import org.apache.fop.pdf.PDFFilterList; -import org.apache.fop.pdf.PDFPage; -import org.apache.fop.pdf.PDFStream; -import org.apache.fop.pdf.PDFState; -import org.apache.fop.pdf.PDFNumber; -import org.apache.fop.pdf.PDFResources; -import org.apache.fop.pdf.PDFColor; -import org.apache.fop.pdf.PDFAnnotList; -import org.apache.fop.fonts.FontInfo; -import org.apache.fop.fonts.FontSetup; - -import java.awt.Graphics; -import java.awt.Font; import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; import java.awt.Shape; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; -import java.io.OutputStream; import java.io.IOException; +import java.io.OutputStream; import java.io.StringWriter; +import org.apache.fop.Version; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontSetup; +import org.apache.fop.pdf.PDFAnnotList; +import org.apache.fop.pdf.PDFColor; +import org.apache.fop.pdf.PDFDocument; +import org.apache.fop.pdf.PDFFilterList; +import org.apache.fop.pdf.PDFNumber; +import org.apache.fop.pdf.PDFPage; +import org.apache.fop.pdf.PDFPaintingState; +import org.apache.fop.pdf.PDFResources; +import org.apache.fop.pdf.PDFStream; + /** * This class is a wrapper for the <tt>PDFGraphics2D</tt> that * is used to create a full document around the pdf rendering from @@ -52,7 +52,7 @@ import java.io.StringWriter; */ public class PDFDocumentGraphics2D extends PDFGraphics2D { - private PDFContext pdfContext; + private final PDFContext pdfContext; private int width; private int height; @@ -296,7 +296,7 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D { throw new IllegalStateException("Close page first before starting another"); } //Start page - graphicsState = new PDFState(); + paintingState = new PDFPaintingState(); if (this.initialTransform == null) { //Save initial transformation matrix this.initialTransform = getTransform(); @@ -322,7 +322,7 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D { pageRef = page.referencePDF(); AffineTransform at = new AffineTransform(1.0, 0.0, 0.0, -1.0, - 0.0, (double)height); + 0.0, height); currentStream.write("1 0 0 -1 0 " + height + " cm\n"); if (svgWidth != 0) { double scaleX = width / svgWidth; @@ -340,7 +340,7 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D { scale(1 / s, 1 / s); } // Remember the transform we installed. - graphicsState.concatenate(at); + paintingState.concatenate(at); pdfContext.increasePageCount(); } diff --git a/src/java/org/apache/fop/svg/PDFGraphics2D.java b/src/java/org/apache/fop/svg/PDFGraphics2D.java index 08655fd47..554d26798 100644 --- a/src/java/org/apache/fop/svg/PDFGraphics2D.java +++ b/src/java/org/apache/fop/svg/PDFGraphics2D.java @@ -59,19 +59,9 @@ import org.apache.batik.ext.awt.RadialGradientPaint; import org.apache.batik.ext.awt.RenderingHintsKeyExt; import org.apache.batik.gvt.GraphicsNode; import org.apache.batik.gvt.PatternPaint; - -import org.apache.xmlgraphics.image.loader.ImageInfo; -import org.apache.xmlgraphics.image.loader.ImageSize; -import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; -import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG; -import org.apache.xmlgraphics.image.loader.impl.ImageRendered; -import org.apache.xmlgraphics.java2d.AbstractGraphics2D; -import org.apache.xmlgraphics.java2d.GraphicContext; - import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontSetup; -import org.apache.fop.fonts.FontTriplet; import org.apache.fop.pdf.BitmapImage; import org.apache.fop.pdf.PDFAnnotList; import org.apache.fop.pdf.PDFColor; @@ -83,16 +73,23 @@ import org.apache.fop.pdf.PDFImage; import org.apache.fop.pdf.PDFImageXObject; import org.apache.fop.pdf.PDFLink; import org.apache.fop.pdf.PDFNumber; +import org.apache.fop.pdf.PDFPaintingState; import org.apache.fop.pdf.PDFPattern; import org.apache.fop.pdf.PDFResourceContext; import org.apache.fop.pdf.PDFResources; -import org.apache.fop.pdf.PDFState; import org.apache.fop.pdf.PDFText; import org.apache.fop.pdf.PDFXObject; import org.apache.fop.render.pdf.ImageRawCCITTFaxAdapter; import org.apache.fop.render.pdf.ImageRawJPEGAdapter; import org.apache.fop.render.pdf.ImageRenderedAdapter; import org.apache.fop.util.ColorExt; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageSize; +import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; +import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG; +import org.apache.xmlgraphics.image.loader.impl.ImageRendered; +import org.apache.xmlgraphics.java2d.AbstractGraphics2D; +import org.apache.xmlgraphics.java2d.GraphicContext; /** * PDF Graphics 2D. @@ -103,8 +100,7 @@ import org.apache.fop.util.ColorExt; * @version $Id$ * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D */ -public class PDFGraphics2D extends AbstractGraphics2D { - +public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHandler { private static final AffineTransform IDENTITY_TRANSFORM = new AffineTransform(); /** The number of decimal places. */ @@ -129,9 +125,9 @@ public class PDFGraphics2D extends AbstractGraphics2D { protected String pageRef; /** - * the current state of the pdf graphics + * The PDF painting state */ - protected PDFState graphicsState; + protected PDFPaintingState paintingState; /** * The PDF graphics state level that this svg is being drawn into. @@ -200,7 +196,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { currentFontSize = size; fontInfo = fi; pageRef = pref; - graphicsState = new PDFState(); + paintingState = new PDFPaintingState(); } /** @@ -226,7 +222,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { this.currentFontSize = g.currentFontSize; this.fontInfo = g.fontInfo; this.pageRef = g.pageRef; - this.graphicsState = g.graphicsState; + this.paintingState = g.paintingState; this.currentStream = g.currentStream; this.nativeCount = g.nativeCount; this.outputStream = g.outputStream; @@ -266,9 +262,9 @@ public class PDFGraphics2D extends AbstractGraphics2D { * * @param state the PDF state */ - public void setPDFState(PDFState state) { - graphicsState = state; - baseLevel = graphicsState.getStackLevel(); + public void setPaintingState(PDFPaintingState state) { + paintingState = state; + baseLevel = paintingState.getStackLevel(); } /** @@ -369,7 +365,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { * @return the transformation matrix that established the basic user space for this document */ protected AffineTransform getBaseTransform() { - AffineTransform at = new AffineTransform(graphicsState.getTransform()); + AffineTransform at = new AffineTransform(paintingState.getTransform()); return at; } @@ -417,7 +413,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { * @param width the width to draw the image * @param height the height to draw the image */ - void addNativeImage(org.apache.xmlgraphics.image.loader.Image image, float x, float y, + public void addNativeImage(org.apache.xmlgraphics.image.loader.Image image, float x, float y, float width, float height) { preparePainting(); String key = image.getInfo().getOriginalURI(); @@ -522,10 +518,14 @@ public class PDFGraphics2D extends AbstractGraphics2D { g.setBackground(new Color(1, 1, 1, 0)); g.setPaint(new Color(1, 1, 1, 0)); g.fillRect(0, 0, width, height); - g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight())); + + int imageWidth = buf.getWidth(); + int imageHeight = buf.getHeight(); + g.clip(new Rectangle(0, 0, imageWidth, imageHeight)); g.setComposite(gc.getComposite()); - if (!g.drawImage(img, 0, 0, buf.getWidth(), buf.getHeight(), observer)) { + boolean drawn = g.drawImage(img, 0, 0, imageWidth, imageHeight, observer); + if (!drawn) { return false; } g.dispose(); @@ -606,13 +606,13 @@ public class PDFGraphics2D extends AbstractGraphics2D { trans.getMatrix(tranvals); Shape imclip = getClip(); - boolean newClip = graphicsState.checkClip(imclip); - boolean newTransform = graphicsState.checkTransform(trans) + boolean newClip = paintingState.checkClip(imclip); + boolean newTransform = paintingState.checkTransform(trans) && !trans.isIdentity(); if (newClip || newTransform) { currentStream.write("q\n"); - graphicsState.push(); + paintingState.save(); if (newTransform) { concatMatrix(tranvals); } @@ -629,7 +629,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { applyColor(c, true); Paint paint = getPaint(); - if (graphicsState.setPaint(paint)) { + if (paintingState.setPaint(paint)) { if (!applyPaint(paint, false)) { // Stroke the shape and use it to 'clip' // the paint contents. @@ -638,7 +638,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { if (newClip || newTransform) { currentStream.write("Q\n"); - graphicsState.pop(); + paintingState.restore(); } return; } @@ -650,7 +650,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { doDrawing(false, true, false); if (newClip || newTransform) { currentStream.write("Q\n"); - graphicsState.pop(); + paintingState.restore(); } } @@ -1304,7 +1304,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { if (ovFontState == null) { java.awt.Font gFont = getFont(); fontTransform = gFont.getTransform(); - fontState = getInternalFontForAWTFont(gFont); + fontState = fontInfo.getFontInstanceForAWTFont(gFont); } else { fontState = fontInfo.getFontInstance( ovFontState.getFontTriplet(), ovFontState.getFontSize()); @@ -1360,7 +1360,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { if (!useMultiByte) { if (ch > 127) { currentStream.write("\\"); - currentStream.write(Integer.toOctalString((int)ch)); + currentStream.write(Integer.toOctalString(ch)); } else { switch (ch) { case '(': @@ -1377,8 +1377,8 @@ public class PDFGraphics2D extends AbstractGraphics2D { } if (kerningAvailable && (i + 1) < l) { - addKerning(currentStream, (new Integer((int)ch)), - (new Integer((int)fontState.mapChar(s.charAt(i + 1)))), + addKerning(currentStream, (new Integer(ch)), + (new Integer(fontState.mapChar(s.charAt(i + 1)))), kerning, startText, endText); } @@ -1406,7 +1406,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { vals.put(PDFGState.GSTATE_ALPHA_STROKE, new Float(strokeAlpha / 255f)); } PDFGState gstate = pdfDoc.getFactory().makeGState( - vals, graphicsState.getGState()); + vals, paintingState.getGState()); resourceContext.addGState(gstate); currentStream.write("/" + gstate.getName() + " gs\n"); } @@ -1418,7 +1418,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { */ protected void updateCurrentFont(Font font) { String name = font.getFontName(); - float size = (float)font.getFontSize() / 1000f; + float size = font.getFontSize() / 1000f; //Only update if necessary if ((!name.equals(this.currentFontName)) @@ -1433,19 +1433,10 @@ public class PDFGraphics2D extends AbstractGraphics2D { * Returns a suitable internal font given an AWT Font instance. * @param awtFont the AWT font * @return the internal Font + * @deprecated use FontInfo.getFontInstanceForAWTFont(java.awt.Font awtFont) instead */ protected Font getInternalFontForAWTFont(java.awt.Font awtFont) { - Font fontState; - String n = awtFont.getFamily(); - if (n.equals("sanserif")) { - n = "sans-serif"; - } - float siz = awtFont.getSize2D(); - String style = awtFont.isItalic() ? "italic" : "normal"; - int weight = awtFont.isBold() ? Font.WEIGHT_BOLD : Font.WEIGHT_NORMAL; - FontTriplet triplet = fontInfo.fontLookup(n, style, weight); - fontState = fontInfo.getFontInstance(triplet, (int)(siz * 1000 + 0.5)); - return fontState; + return fontInfo.getFontInstanceForAWTFont(awtFont); } /** @@ -1597,13 +1588,13 @@ public class PDFGraphics2D extends AbstractGraphics2D { trans.getMatrix(tranvals); Shape imclip = getClip(); - boolean newClip = graphicsState.checkClip(imclip); - boolean newTransform = graphicsState.checkTransform(trans) + boolean newClip = paintingState.checkClip(imclip); + boolean newTransform = paintingState.checkTransform(trans) && !trans.isIdentity(); if (newClip || newTransform) { currentStream.write("q\n"); - graphicsState.push(); + paintingState.save(); if (newTransform) { concatMatrix(tranvals); } @@ -1620,14 +1611,14 @@ public class PDFGraphics2D extends AbstractGraphics2D { applyColor(c, false); Paint paint = getPaint(); - if (graphicsState.setPaint(paint)) { + if (paintingState.setPaint(paint)) { if (!applyPaint(paint, true)) { // Use the shape to 'clip' the paint contents. applyUnknownPaint(paint, s); if (newClip || newTransform) { currentStream.write("Q\n"); - graphicsState.pop(); + paintingState.restore(); } return; } @@ -1640,7 +1631,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { iter.getWindingRule() == PathIterator.WIND_EVEN_ODD); if (newClip || newTransform) { currentStream.write("Q\n"); - graphicsState.pop(); + paintingState.restore(); } } diff --git a/src/java/org/apache/fop/svg/PDFGraphicsConfiguration.java b/src/java/org/apache/fop/svg/PDFGraphicsConfiguration.java index 83a431d5e..0204a2756 100644 --- a/src/java/org/apache/fop/svg/PDFGraphicsConfiguration.java +++ b/src/java/org/apache/fop/svg/PDFGraphicsConfiguration.java @@ -26,6 +26,7 @@ import java.awt.image.ColorModel; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; + /** * Our implementation of the class that returns information about * roughly what we can handle and want to see (alpha for example). diff --git a/src/java/org/apache/fop/svg/PDFImageElementBridge.java b/src/java/org/apache/fop/svg/PDFImageElementBridge.java index 7eb89d2b1..1a17aa410 100644 --- a/src/java/org/apache/fop/svg/PDFImageElementBridge.java +++ b/src/java/org/apache/fop/svg/PDFImageElementBridge.java @@ -19,36 +19,14 @@ package org.apache.fop.svg; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.geom.Rectangle2D; - -import org.w3c.dom.Element; -import org.w3c.dom.svg.SVGDocument; - -import org.apache.batik.bridge.BridgeContext; -import org.apache.batik.bridge.SVGImageElementBridge; -import org.apache.batik.gvt.AbstractGraphicsNode; -import org.apache.batik.gvt.GraphicsNode; -import org.apache.batik.util.ParsedURL; - -import org.apache.xmlgraphics.image.loader.Image; -import org.apache.xmlgraphics.image.loader.ImageException; import org.apache.xmlgraphics.image.loader.ImageFlavor; -import org.apache.xmlgraphics.image.loader.ImageInfo; -import org.apache.xmlgraphics.image.loader.ImageManager; -import org.apache.xmlgraphics.image.loader.ImageSessionContext; -import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; -import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; -import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG; -import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; /** - * Bridge class for the <image> element when jpeg images. + * PDF Image Element Bridge class for the <image> element when jpeg images. * * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a> */ -public class PDFImageElementBridge extends SVGImageElementBridge { +public class PDFImageElementBridge extends AbstractFOPImageElementBridge { /** * Constructs a new bridge for the <image> element. @@ -60,210 +38,9 @@ public class PDFImageElementBridge extends SVGImageElementBridge { ImageFlavor.RAW_CCITTFAX, ImageFlavor.GRAPHICS2D, ImageFlavor.XML_DOM}; - /** - * Create the raster image node. - * THis checks if it is a jpeg file and creates a jpeg node - * so the jpeg can be inserted directly into the pdf document. - * @param ctx the bridge context - * @param imageElement the svg element for the image - * @param purl the parsed url for the image resource - * @return a new graphics node - */ - protected GraphicsNode createImageGraphicsNode - (BridgeContext ctx, Element imageElement, ParsedURL purl) { - PDFBridgeContext pdfCtx = (PDFBridgeContext)ctx; - - ImageManager manager = pdfCtx.getImageManager(); - ImageSessionContext sessionContext = pdfCtx.getImageSessionContext(); - try { - ImageInfo info = manager.getImageInfo(purl.toString(), sessionContext); - Image image = manager.getImage(info, supportedFlavors, sessionContext); - - //TODO color profile overrides aren't handled, yet! - //ICCColorSpaceExt colorspaceOverride = extractColorSpace(e, ctx); - AbstractGraphicsNode specializedNode = null; - if (image instanceof ImageXMLDOM) { - ImageXMLDOM xmlImage = (ImageXMLDOM)image; - if (xmlImage.getDocument() instanceof SVGDocument) { - return createSVGImageNode(ctx, imageElement, - (SVGDocument)xmlImage.getDocument()); - } else { - //Convert image to Graphics2D - image = manager.convertImage(xmlImage, - new ImageFlavor[] {ImageFlavor.GRAPHICS2D}); - } - } - if (image instanceof ImageRawJPEG) { - specializedNode = new LoaderImageNode(image, ctx, imageElement, purl); - } else if (image instanceof ImageRawCCITTFax) { - specializedNode = new LoaderImageNode(image, ctx, imageElement, purl); - } else if (image instanceof ImageGraphics2D) { - ImageGraphics2D g2dImage = (ImageGraphics2D)image; - specializedNode = new Graphics2DNode(g2dImage); - } else { - ctx.getUserAgent().displayError( - new ImageException("Cannot convert an image to a usable format: " + purl)); - } - - Rectangle2D imgBounds = getImageBounds(ctx, imageElement); - Rectangle2D bounds = specializedNode.getPrimitiveBounds(); - float [] vb = new float[4]; - vb[0] = 0; // x - vb[1] = 0; // y - vb[2] = (float) bounds.getWidth(); // width - vb[3] = (float) bounds.getHeight(); // height - - // handles the 'preserveAspectRatio', 'overflow' and 'clip' - // and sets the appropriate AffineTransform to the image node - initializeViewport(ctx, imageElement, specializedNode, vb, imgBounds); - return specializedNode; - } catch (Exception e) { - ctx.getUserAgent().displayError(e); - } - - return superCreateGraphicsNode(ctx, imageElement, purl); - } - - /** - * Calls the superclass' createImageGraphicNode() method to create the normal GraphicsNode. - * @param ctx the bridge context - * @param imageElement the image element - * @param purl the parsed URL - * @return the newly created graphics node - * @see org.apache.batik.bridge.SVGImageElementBridge#createGraphicsNode(BridgeContext, Element) - */ - protected GraphicsNode superCreateGraphicsNode - (BridgeContext ctx, Element imageElement, ParsedURL purl) { - return super.createImageGraphicsNode(ctx, imageElement, purl); - } - - - /** - * An image node for natively handled Image instance. - * This holds a natively handled image so that it can be drawn into - * the PDFGraphics2D. - */ - public class LoaderImageNode extends AbstractGraphicsNode { - - private Image image; - private BridgeContext ctx; - private Element imageElement; - private ParsedURL purl; - private GraphicsNode origGraphicsNode = null; - - /** - * Create a new image node for drawing natively handled images - * into PDF graphics. - * @param image the JPEG image - * @param ctx the bridge context - * @param imageElement the SVG image element - * @param purl the URL to the image - */ - public LoaderImageNode(Image image, BridgeContext ctx, - Element imageElement, ParsedURL purl) { - this.image = image; - this.ctx = ctx; - this.imageElement = imageElement; - this.purl = purl; - } - - /** {@inheritDoc} */ - public Shape getOutline() { - return getPrimitiveBounds(); - } - - /** {@inheritDoc} */ - public void primitivePaint(Graphics2D g2d) { - if (g2d instanceof PDFGraphics2D) { - PDFGraphics2D pdfg = (PDFGraphics2D) g2d; - float x = 0; - float y = 0; - try { - float width = image.getSize().getWidthPx(); - float height = image.getSize().getHeightPx(); - pdfg.addNativeImage(image, x, y, width, height); - } catch (Exception e) { - ctx.getUserAgent().displayError(e); - } - } else { - // Not going directly into PDF so use - // original implementation so filters etc work. - if (origGraphicsNode == null) { - // Haven't constructed baseclass Graphics Node, - // so do so now. - origGraphicsNode - = PDFImageElementBridge.this.superCreateGraphicsNode - (ctx, imageElement, purl); - } - origGraphicsNode.primitivePaint(g2d); - } - } - - /** {@inheritDoc} */ - public Rectangle2D getGeometryBounds() { - return getPrimitiveBounds(); - } - - /** {@inheritDoc} */ - public Rectangle2D getPrimitiveBounds() { - return new Rectangle2D.Double(0, 0, - image.getSize().getWidthPx(), - image.getSize().getHeightPx()); - } - - /** {@inheritDoc} */ - public Rectangle2D getSensitiveBounds() { - //No interactive features, just return primitive bounds - return getPrimitiveBounds(); - } - - } - - /** - * A node that holds a Graphics2D image. - */ - public class Graphics2DNode extends AbstractGraphicsNode { - - private ImageGraphics2D image; - - /** - * Create a new Graphics2D node. - * @param g2d the Graphics2D image - */ - public Graphics2DNode(ImageGraphics2D g2d) { - this.image = g2d; - } - - /** {@inheritDoc} */ - public Shape getOutline() { - return getPrimitiveBounds(); - } - - /** {@inheritDoc} */ - public void primitivePaint(Graphics2D g2d) { - int width = image.getSize().getWidthPx(); - int height = image.getSize().getHeightPx(); - Rectangle2D area = new Rectangle2D.Double(0, 0, width, height); - image.getGraphics2DImagePainter().paint(g2d, area); - } - - /** {@inheritDoc} */ - public Rectangle2D getGeometryBounds() { - return getPrimitiveBounds(); - } - - /** {@inheritDoc} */ - public Rectangle2D getPrimitiveBounds() { - return new Rectangle2D.Double(0, 0, - image.getSize().getWidthPx(), - image.getSize().getHeightPx()); - } - - /** {@inheritDoc} */ - public Rectangle2D getSensitiveBounds() { - //No interactive features, just return primitive bounds - return getPrimitiveBounds(); - } + /** {@inheritDoc} */ + protected ImageFlavor[] getSupportedFlavours() { + return supportedFlavors; } } diff --git a/src/java/org/apache/fop/svg/PDFTextElementBridge.java b/src/java/org/apache/fop/svg/PDFTextElementBridge.java index 4c11aa97e..c983d2b45 100644 --- a/src/java/org/apache/fop/svg/PDFTextElementBridge.java +++ b/src/java/org/apache/fop/svg/PDFTextElementBridge.java @@ -19,13 +19,7 @@ package org.apache.fop.svg; -import org.apache.batik.bridge.BridgeContext; -import org.apache.batik.bridge.SVGTextElementBridge; -import org.apache.batik.gvt.GraphicsNode; -import org.apache.batik.gvt.TextNode; import org.apache.batik.gvt.TextPainter; -import org.apache.fop.fonts.FontInfo; -import org.w3c.dom.Element; /** * Bridge class for the <text> element. @@ -34,41 +28,15 @@ import org.w3c.dom.Element; * * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a> */ -public class PDFTextElementBridge extends SVGTextElementBridge { - - private PDFTextPainter pdfTextPainter; +public class PDFTextElementBridge extends AbstractFOPTextElementBridge { /** * Constructs a new bridge for the <text> element. - * @param fi the font information - */ - public PDFTextElementBridge(FontInfo fi) { - pdfTextPainter = new PDFTextPainter(fi); - } - - /** - * 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 + * + * @param textPainter the text painter to use */ - public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) { - GraphicsNode node = super.createGraphicsNode(ctx, e); - if (node != null) { - //Set our own text painter - ((TextNode)node).setTextPainter(getTextPainter()); - } - return node; + public PDFTextElementBridge(TextPainter textPainter) { + super(textPainter); } - - /** - * Returns the TextPainter instance used by this bridge. - * @return the text painter - */ - public TextPainter getTextPainter() { - return pdfTextPainter; - } - } diff --git a/src/java/org/apache/fop/svg/PDFTextPainter.java b/src/java/org/apache/fop/svg/PDFTextPainter.java index 06fea54cc..85447a4f9 100644 --- a/src/java/org/apache/fop/svg/PDFTextPainter.java +++ b/src/java/org/apache/fop/svg/PDFTextPainter.java @@ -63,8 +63,8 @@ public class PDFTextPainter extends StrokingTextPainter { private static final boolean DEBUG = false; - private boolean strokeText = false; - private FontInfo fontInfo; + private final boolean strokeText = false; + private final FontInfo fontInfo; /** * Create a new PDF text painter with the given font information. @@ -280,12 +280,12 @@ public class PDFTextPainter extends StrokingTextPainter { Float fontSize = (Float) aci.getAttribute(TextAttribute.SIZE); String style = ((posture != null) && (posture.floatValue() > 0.0)) - ? "italic" : "normal"; + ? Font.STYLE_ITALIC : Font.STYLE_NORMAL; int weight = ((taWeight != null) && (taWeight.floatValue() > 1.0)) ? Font.WEIGHT_BOLD : Font.WEIGHT_NORMAL; - String fontFamily = null; + String firstFontFamily = null; //GVT_FONT can sometimes be different from the fonts in GVT_FONT_FAMILIES //or GVT_FONT_FAMILIES can even be empty and only GVT_FONT is set @@ -307,6 +307,7 @@ public class PDFTextPainter extends StrokingTextPainter { int fsize = (int)(fontSize.floatValue() * 1000); fonts.add(fontInfo.getFontInstance(triplet, fsize)); } + firstFontFamily = gvtFontFamily; } catch (Exception e) { //Most likely NoSuchMethodError here when using Batik 1.6 //Just skip this section in this case @@ -320,7 +321,7 @@ public class PDFTextPainter extends StrokingTextPainter { if (fam instanceof SVGFontFamily) { return null; //Let Batik paint this text! } - fontFamily = fam.getFamilyName(); + String fontFamily = fam.getFamilyName(); if (DEBUG) { System.out.print(fontFamily + ", "); } @@ -330,15 +331,20 @@ public class PDFTextPainter extends StrokingTextPainter { int fsize = (int)(fontSize.floatValue() * 1000); fonts.add(fontInfo.getFontInstance(triplet, fsize)); } + if (firstFontFamily == null) { + firstFontFamily = fontFamily; + } } } if (fonts.size() == 0) { - FontTriplet triplet = fontInfo.fontLookup("any", style, Font.WEIGHT_NORMAL); + if (firstFontFamily == null) { + //This will probably never happen. Just to be on the safe side. + firstFontFamily = "any"; + } + //lookup with fallback possibility (incl. substitution notification) + FontTriplet triplet = fontInfo.fontLookup(firstFontFamily, style, weight); int fsize = (int)(fontSize.floatValue() * 1000); fonts.add(fontInfo.getFontInstance(triplet, fsize)); - if (DEBUG) { - System.out.print("fallback to 'any' font"); - } } if (DEBUG) { System.out.println(); diff --git a/src/java/org/apache/fop/util/AbstractPaintingState.java b/src/java/org/apache/fop/util/AbstractPaintingState.java new file mode 100644 index 000000000..4fb6b173c --- /dev/null +++ b/src/java/org/apache/fop/util/AbstractPaintingState.java @@ -0,0 +1,531 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.util; + +import java.awt.Color; +import java.awt.geom.AffineTransform; +import java.io.Serializable; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Stack; + +/** + * A base class which holds information about the current painting state. + */ +public abstract class AbstractPaintingState implements Cloneable, Serializable { + + private static final long serialVersionUID = 5998356138437094188L; + + /** current state data */ + private AbstractData data = null; + + /** the state stack */ + private StateStack/*<AbstractData>*/ stateStack = new StateStack/*<AbstractData>*/(); + + /** + * Instantiates a new state data object + * + * @return a new state data object + */ + protected abstract AbstractData instantiateData(); + + /** + * Instantiates a new state object + * + * @return a new state object + */ + protected abstract AbstractPaintingState instantiate(); + + /** + * Returns the currently valid state + * + * @return the currently valid state + */ + public AbstractData getData() { + if (data == null) { + data = instantiateData(); + } + return data; + } + + /** + * Set the current color. + * Check if the new color is a change and then set the current color. + * + * @param col the color to set + * @return true if the color has changed + */ + public boolean setColor(Color col) { + if (!col.equals(getData().color)) { + getData().color = col; + return true; + } + return false; + } + + /** + * Get the color. + * + * @return the color + */ + public Color getColor() { + if (getData().color == null) { + getData().color = Color.black; + } + return getData().color; + } + + /** + * Get the background color. + * + * @return the background color + */ + public Color getBackColor() { + if (getData().backColor == null) { + getData().backColor = Color.white; + } + return getData().backColor; + } + + /** + * Set the current background color. + * Check if the new background color is a change and then set the current background color. + * + * @param col the background color to set + * @return true if the color has changed + */ + public boolean setBackColor(Color col) { + if (!col.equals(getData().backColor)) { + getData().backColor = col; + return true; + } + return false; + } + + /** + * Set the current font name + * + * @param internalFontName the internal font name + * @return true if the font name has changed + */ + public boolean setFontName(String internalFontName) { + if (!internalFontName.equals(getData().fontName)) { + getData().fontName = internalFontName; + return true; + } + return false; + } + + /** + * Gets the current font name + * + * @return the current font name + */ + public String getFontName() { + return getData().fontName; + } + + /** + * Gets the current font size + * + * @return the current font size + */ + public int getFontSize() { + return getData().fontSize; + } + + /** + * Set the current font size. + * Check if the font size is a change and then set the current font size. + * + * @param size the font size to set + * @return true if the font size has changed + */ + public boolean setFontSize(int size) { + if (size != getData().fontSize) { + getData().fontSize = size; + return true; + } + return false; + } + + /** + * Set the current line width. + * + * @param width the line width in points + * @return true if the line width has changed + */ + public boolean setLineWidth(float width) { + if (getData().lineWidth != width) { + getData().lineWidth = width; + return true; + } + return false; + } + + /** + * Returns the current line width + * + * @return the current line width + */ + public float getLineWidth() { + return getData().lineWidth; + } + + /** + * Sets the dash array (line type) for the current basic stroke + * + * @param dash the line dash array + * @return true if the dash array has changed + */ + public boolean setDashArray(float[] dash) { + if (!Arrays.equals(dash, getData().dashArray)) { + getData().dashArray = dash; + return true; + } + return false; + } + + /** + * Get the current transform. + * This gets the combination of all transforms in the + * current state. + * + * @return the calculate combined transform for the current state + */ + public AffineTransform getTransform() { + AffineTransform at = new AffineTransform(); + for (Iterator iter = stateStack.iterator(); iter.hasNext();) { + AbstractData data = (AbstractData)iter.next(); + AffineTransform stackTrans = data.getTransform(); + at.concatenate(stackTrans); + } + AffineTransform currentTrans = getData().getTransform(); + at.concatenate(currentTrans); + return at; + } + + /** + * Check the current transform. + * The transform for the current state is the combination of all + * transforms in the current state. The parameter is compared + * against this current transform. + * + * @param tf the transform the check against + * @return true if the new transform is different then the current transform + */ + public boolean checkTransform(AffineTransform tf) { + return !tf.equals(getData().getTransform()); + } + + /** + * Get a copy of the base transform for the page. Used to translate + * IPP/BPP values into X,Y positions when positioning is "fixed". + * + * @return the base transform, or null if the state stack is empty + */ + public AffineTransform getBaseTransform() { + if (stateStack.isEmpty()) { + return null; + } else { + AbstractData baseData = (AbstractData)stateStack.get(0); + return (AffineTransform) baseData.getTransform().clone(); + } + } + + /** + * Concatenates the given AffineTransform to the current one. + * + * @param at the transform to concatenate to the current level transform + */ + public void concatenate(AffineTransform at) { + getData().concatenate(at); + } + + /** + * Resets the current AffineTransform to the Base AffineTransform. + */ + public void resetTransform() { + getData().setTransform(getBaseTransform()); + } + + /** + * Clears the current AffineTransform to the Identity AffineTransform + */ + public void clearTransform() { + getData().clearTransform(); + } + + + /** + * Save the current painting state. + * This pushes the current painting state onto the stack. + * This call should be used when the Q operator is used + * so that the state is known when popped. + */ + public void save() { + AbstractData copy = (AbstractData)getData().clone(); + stateStack.push(copy); + } + + /** + * Restore the current painting state. + * This pops the painting state from the stack and sets current values to popped state. + * + * @return the restored state, null if the stack is empty + */ + public AbstractData restore() { + if (!stateStack.isEmpty()) { + setData((AbstractData)stateStack.pop()); + return this.data; + } else { + return null; + } + } + + /** + * Save all painting state data. + * This pushes all painting state data in the given list to the stack + * + * @param dataList a state data list + */ + public void saveAll(List/*<AbstractData>*/ dataList) { + Iterator it = dataList.iterator(); + while (it.hasNext()) { + // save current data on stack + save(); + setData((AbstractData)it.next()); + } + } + + /** + * Restore all painting state data. + * This pops all painting state data from the stack + * + * @return a list of state data popped from the stack + */ + public List/*<AbstractData>*/ restoreAll() { + List/*<AbstractData>*/ dataList = new java.util.ArrayList/*<AbstractData>*/(); + AbstractData data; + while (true) { + data = getData(); + if (restore() == null) { + break; + } + // insert because of stack-popping + dataList.add(0, data); + } + return dataList; + } + + /** + * Sets the current state data + * + * @param currentData state data + */ + protected void setData(AbstractData data) { + this.data = data; + } + + /** + * Clears the state stack + */ + public void clear() { + stateStack.clear(); + setData(null); + } + + /** + * Return the state stack + * + * @return the state stack + */ + protected Stack/*<AbstractData>*/ getStateStack() { + return this.stateStack; + } + + /** {@inheritDoc} */ + public Object clone() { + AbstractPaintingState state = instantiate(); + state.stateStack = new StateStack(this.stateStack); + state.data = (AbstractData)this.data.clone(); + return state; + } + + /** {@inheritDoc} */ + public String toString() { + return ", stateStack=" + stateStack + + ", currentData=" + data; + } + + + /** + * A stack implementation which holds state objects + */ + public class StateStack extends java.util.Stack { + + private static final long serialVersionUID = 4897178211223823041L; + + /** + * Default constructor + */ + public StateStack() { + super(); + } + + /** + * Copy constructor + * + * @param c initial contents of stack + */ + public StateStack(Collection c) { + elementCount = c.size(); + // 10% for growth + elementData = new Object[ + (int)Math.min((elementCount * 110L) / 100, Integer.MAX_VALUE)]; + c.toArray(elementData); + } + } + + + /** + * A base painting state data holding object + */ + public abstract class AbstractData implements Cloneable, Serializable { + + private static final long serialVersionUID = 5208418041189828624L; + + /** The current color */ + protected Color color = null; + + /** The current background color */ + protected Color backColor = null; + + /** The current font name */ + protected String fontName = null; + + /** The current font size */ + protected int fontSize = 0; + + /** The current line width */ + protected float lineWidth = 0; + + /** The dash array for the current basic stroke (line type) */ + protected float[] dashArray = null; + + /** The current transform */ + protected AffineTransform transform = null; + + /** + * Returns a newly create data object + * + * @return a new data object + */ + protected abstract AbstractData instantiate(); + + /** + * Concatenate the given AffineTransform with the current thus creating + * a new viewport. Note that all concatenation operations are logged + * so they can be replayed if necessary (ex. for block-containers with + * "fixed" positioning. + * + * @param at Transformation to perform + */ + public void concatenate(AffineTransform at) { + getTransform().concatenate(at); + } + + /** + * Get the current AffineTransform. + * + * @return the current transform + */ + public AffineTransform getTransform() { + if (transform == null) { + transform = new AffineTransform(); + } + return transform; + } + + /** + * Sets the current AffineTransform. + */ + public void setTransform(AffineTransform baseTransform) { + this.transform = baseTransform; + } + + /** + * Resets the current AffineTransform. + */ + public void clearTransform() { + transform = new AffineTransform(); + } + + /** + * Returns the derived rotation from the current transform + * + * @return the derived rotation from the current transform + */ + public int getDerivedRotation() { + AffineTransform at = getTransform(); + double sx = at.getScaleX(); + double sy = at.getScaleY(); + double shx = at.getShearX(); + double shy = at.getShearY(); + int rotation = 0; + if (sx == 0 && sy == 0 && shx > 0 && shy < 0) { + rotation = 270; + } else if (sx < 0 && sy < 0 && shx == 0 && shy == 0) { + rotation = 180; + } else if (sx == 0 && sy == 0 && shx < 0 && shy > 0) { + rotation = 90; + } else { + rotation = 0; + } + return rotation; + } + + /** {@inheritDoc} */ + public Object clone() { + AbstractData data = instantiate(); + data.color = this.color; + data.backColor = this.backColor; + data.fontName = this.fontName; + data.fontSize = this.fontSize; + data.lineWidth = this.lineWidth; + data.dashArray = this.dashArray; + data.transform = new AffineTransform(this.transform); + return data; + } + + /** {@inheritDoc} */ + public String toString() { + return "color=" + color + + ", backColor=" + backColor + + ", fontName=" + fontName + + ", fontSize=" + fontSize + + ", lineWidth=" + lineWidth + + ", dashArray=" + dashArray + + ", transform=" + transform; + } + } +} |