aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorManuel Mall <manuel@apache.org>2006-04-27 15:08:17 +0000
committerManuel Mall <manuel@apache.org>2006-04-27 15:08:17 +0000
commit0040a29ecce57798e6947fdb33750a4dba1afea0 (patch)
tree501628c14f955bac7a8006e81b3155b5e906f57d /src
parent31c92194560170ea22c7537736bbdf2ad5e5aaf6 (diff)
downloadxmlgraphics-fop-0040a29ecce57798e6947fdb33750a4dba1afea0.tar.gz
xmlgraphics-fop-0040a29ecce57798e6947fdb33750a4dba1afea0.zip
AFP Renderer as per IP clearance (http://mail-archives.apache.org/mod_mbox/xmlgraphics-general/200604.mbox/%3c20060426085421.B456.DEV@jeremias-maerki.ch%3e) plus some further corrections and changes made by manuel@apache.org since
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@397562 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
-rw-r--r--src/sandbox/META-INF/services/org.apache.fop.render.Renderer1
-rw-r--r--src/sandbox/org/apache/fop/render/afp/AFPFontAttributes.java110
-rw-r--r--src/sandbox/org/apache/fop/render/afp/AFPFontColor.java169
-rw-r--r--src/sandbox/org/apache/fop/render/afp/AFPRenderer.java1796
-rw-r--r--src/sandbox/org/apache/fop/render/afp/AFPRendererMaker.java51
-rw-r--r--src/sandbox/org/apache/fop/render/afp/exceptions/FontRuntimeException.java45
-rw-r--r--src/sandbox/org/apache/fop/render/afp/exceptions/NestedRuntimeException.java108
-rw-r--r--src/sandbox/org/apache/fop/render/afp/exceptions/RendererRuntimeException.java45
-rwxr-xr-xsrc/sandbox/org/apache/fop/render/afp/extensions/AFPAttribute.java60
-rwxr-xr-xsrc/sandbox/org/apache/fop/render/afp/extensions/AFPElementMapping.java109
-rw-r--r--src/sandbox/org/apache/fop/render/afp/extensions/AFPPageSetup.java90
-rw-r--r--src/sandbox/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java47
-rw-r--r--src/sandbox/org/apache/fop/render/afp/extensions/AbstractAFPExtensionObject.java120
-rw-r--r--src/sandbox/org/apache/fop/render/afp/fonts/AFPFont.java91
-rw-r--r--src/sandbox/org/apache/fop/render/afp/fonts/AFPFontInfo.java58
-rw-r--r--src/sandbox/org/apache/fop/render/afp/fonts/AFPFontReader.java608
-rw-r--r--src/sandbox/org/apache/fop/render/afp/fonts/CharacterSet.java322
-rw-r--r--src/sandbox/org/apache/fop/render/afp/fonts/CharacterSetOrientation.java275
-rw-r--r--src/sandbox/org/apache/fop/render/afp/fonts/FopCharacterSet.java138
-rw-r--r--src/sandbox/org/apache/fop/render/afp/fonts/OutlineFont.java193
-rw-r--r--src/sandbox/org/apache/fop/render/afp/fonts/RasterFont.java243
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/AFPConstants.java37
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/AFPDataStream.java650
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/AbstractAFPObject.java65
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/AbstractPageObject.java409
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/ActiveEnvironmentGroup.java345
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/Document.java213
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/EndPageGroup.java74
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/IMImageObject.java190
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/ImageCellPosition.java193
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/ImageContent.java294
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/ImageDataDescriptor.java108
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/ImageInputDescriptor.java146
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/ImageObject.java271
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/ImageOutputControl.java207
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/ImageRasterData.java91
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/ImageRasterPattern.java762
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/ImageSegment.java225
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/ImageSizeParameter.java94
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/IncludeObject.java171
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/IncludePageOverlay.java156
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/IncludePageSegment.java114
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/InvokeMediumMap.java81
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/MapCodedFont.java298
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/MapPageOverlay.java157
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/MaximumSizeExceededException.java31
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/ObjectAreaDescriptor.java106
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/ObjectAreaPosition.java111
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/ObjectEnvironmentGroup.java194
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/Overlay.java130
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/PageDescriptor.java97
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/PageGroup.java207
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/PageObject.java185
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/PresentationTextData.java598
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/PresentationTextDescriptor.java113
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/PresentationTextObject.java330
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/ResourceGroup.java151
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/TagLogicalElement.java148
-rw-r--r--src/sandbox/org/apache/fop/render/afp/modca/TagLogicalElementBean.java60
-rw-r--r--src/sandbox/org/apache/fop/render/afp/tools/BinaryUtils.java131
-rw-r--r--src/sandbox/org/apache/fop/render/afp/tools/DTDEntityResolver.java112
-rw-r--r--src/sandbox/org/apache/fop/render/afp/tools/StringUtils.java80
-rw-r--r--src/sandbox/org/apache/fop/render/afp/tools/StructuredFieldReader.java134
63 files changed, 12948 insertions, 0 deletions
diff --git a/src/sandbox/META-INF/services/org.apache.fop.render.Renderer b/src/sandbox/META-INF/services/org.apache.fop.render.Renderer
index d75e81eb2..dcd2b38c8 100644
--- a/src/sandbox/META-INF/services/org.apache.fop.render.Renderer
+++ b/src/sandbox/META-INF/services/org.apache.fop.render.Renderer
@@ -1,2 +1,3 @@
+org.apache.fop.render.afp.AFPRendererMaker
org.apache.fop.render.pcl.PCLRendererMaker
org.apache.fop.render.svg.SVGRendererMaker \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/AFPFontAttributes.java b/src/sandbox/org/apache/fop/render/afp/AFPFontAttributes.java
new file mode 100644
index 000000000..2bb446c3a
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/AFPFontAttributes.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.afp;
+
+import org.apache.fop.render.afp.fonts.AFPFont;
+import org.apache.fop.render.afp.tools.BinaryUtils;
+
+/**
+ * This class encapsulates the font atributes 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 byte
+ */
+ private byte _fontReference;
+
+ /**
+ * The font key
+ */
+ private String _fontKey;
+
+ /**
+ * The font
+ */
+ private AFPFont _font;
+
+ /**
+ * The point size
+ */
+ private int _pointSize;
+
+ /**
+ * Constructor for the AFPFontAttributes
+ * @param fontKey the font key
+ * @param font the font
+ * @param pointSize the point size
+ */
+ public AFPFontAttributes(
+
+ String fontKey,
+ AFPFont font,
+ int pointSize) {
+
+ _fontKey = fontKey;
+ _font = font;
+ _pointSize = pointSize;
+
+ }
+ /**
+ * @return the font
+ */
+ public AFPFont getFont() {
+ return _font;
+ }
+
+ /**
+ * @return the FontKey attribute
+ */
+ public String getFontKey() {
+
+ return _fontKey + _pointSize;
+
+ }
+
+ /**
+ * @return the point size attribute
+ */
+ public int getPointSize() {
+ return _pointSize;
+ }
+
+ /**
+ * @return the FontReference attribute
+ */
+ public byte getFontReference() {
+ return _fontReference;
+ }
+
+ /**
+ * Sets the FontReference attribute
+ * @param fontReference the FontReference to set
+ */
+ public void setFontReference(int fontReference) {
+
+ String id = String.valueOf(fontReference);
+ _fontReference = BinaryUtils.convert(id)[0];
+
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/AFPFontColor.java b/src/sandbox/org/apache/fop/render/afp/AFPFontColor.java
new file mode 100644
index 000000000..be3f678e3
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/AFPFontColor.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.afp;
+
+import java.awt.Color;
+import org.apache.fop.datatypes.ColorType;
+
+/**
+ * AFP only supports very basic colours and this object provides a simple
+ * bean for the colour attributes.
+ *
+ */
+public class AFPFontColor {
+
+ /**
+ * Red value.
+ */
+ private int _red = 0;
+
+ /**
+ * Green value.
+ */
+ private int _green = 0;
+
+ /**
+ * Blue value.
+ */
+ private int _blue = 0;
+
+ /**
+ * Constructor for the AFPColor Object
+ * @param red The red color intensity (0-255)
+ * @param green The green color intensity (0-255)
+ * @param blue The blue color intensity (0-255)
+ */
+ public AFPFontColor(int red, int green, int blue) {
+
+ _red = red;
+ _green = green;
+ _blue = blue;
+
+ }
+
+ /**
+ * Constructor for the AFPColor Object
+ * @param col the org.apache.fop.datatypes.ColorType object
+ */
+ public AFPFontColor(ColorType col) {
+
+ _red = (int)(col.getRed() * 255);
+ _green = (int)(col.getGreen() * 255);
+ _blue = (int)(col.getBlue() * 255);
+
+ }
+
+ /**
+ * Constructor for the AFPColor Object
+ * @param col The java.awt.Color object
+ */
+ public AFPFontColor(Color col) {
+
+ _red = col.getRed();
+ _green = col.getGreen();
+ _blue = col.getBlue();
+
+ }
+
+ /**
+ * Returns the blue attribute
+ * @return int
+ */
+ public int getBlue() {
+ return _blue;
+ }
+
+ /**
+ * Returns the green attribute
+ * @return int
+ */
+ public int getGreen() {
+ return _green;
+ }
+
+ /**
+ * Returns the red attribute
+ * @return int
+ */
+ public int getRed() {
+ return _red;
+ }
+
+ /**
+ * Sets the blue attribute
+ * @param blue The blue value to set
+ */
+ public void setBlue(int blue) {
+ _blue = blue;
+ }
+
+ /**
+ * Sets the green attribute
+ * @param green The green value to set
+ */
+ public void setGreen(int green) {
+ _green = green;
+ }
+
+ /**
+ * Sets the red attribute
+ * @param red The red value to set
+ */
+ public void setRed(int red) {
+ _red = red;
+ }
+
+ /**
+ * Sets this color object to the same values
+ * as the given object.
+ * @param col the source color
+ */
+ public void setTo(AFPFontColor col) {
+ _red = col.getRed();
+ _green = col.getGreen();
+ _blue = col.getBlue();
+ }
+
+ /**
+ * Checks whether this object is equal to the parameter passed
+ * as an argument. If the parameter is an instance of AFPColor
+ * then the value are compared, otherwise the generalized equals
+ * method is invoked on the parent class.
+ *
+ * @param obj the object to compare
+ * @return boolean true if the object is equal
+ */
+ public boolean equals(Object obj) {
+
+ if (obj instanceof AFPFontColor) {
+ AFPFontColor c = (AFPFontColor) obj;
+ if (c.getRed() == _red
+ && c.getGreen() == _green
+ && c.getBlue() == _blue) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return super.equals(obj);
+ }
+
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/AFPRenderer.java b/src/sandbox/org/apache/fop/render/afp/AFPRenderer.java
new file mode 100644
index 000000000..e4505d050
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/AFPRenderer.java
@@ -0,0 +1,1796 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.afp;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+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.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.Character;
+import org.apache.fop.area.inline.Leader;
+import org.apache.fop.area.inline.Image;
+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.ColorType;
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.extensions.ExtensionAttachment;
+import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.fonts.FontMetrics;
+import org.apache.fop.fonts.FontTriplet;
+import org.apache.fop.fonts.FontUtil;
+import org.apache.fop.fonts.Typeface;
+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.image.FopImage;
+import org.apache.fop.image.ImageFactory;
+import org.apache.fop.image.TIFFImage;
+import org.apache.fop.image.XMLImage;
+import org.apache.fop.render.AbstractPathOrientedRenderer;
+import org.apache.fop.render.Graphics2DAdapter;
+import org.apache.fop.render.afp.extensions.AFPElementMapping;
+import org.apache.fop.render.afp.extensions.AFPPageSetup;
+import org.apache.fop.render.afp.fonts.AFPFontInfo;
+import org.apache.fop.render.afp.fonts.AFPFont;
+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.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;
+
+
+/**
+ * This is an implementation of a FOP Renderer that renders areas to AFP.
+ * <p>
+ * A renderer is primarily designed to convert a given area tree into the output
+ * document format. It should be able to produce pages and fill the pages with
+ * the text and graphical content. Usually the output is sent to an output
+ * stream. Some output formats may support extra information that is not
+ * available from the area tree or depends on the destination of the document.
+ * Each renderer is given an area tree to render to its output format. The area
+ * tree is simply a representation of the pages and the placement of text and
+ * graphical objects on those pages.
+ * </p>
+ * <p>
+ * The renderer will be given each page as it is ready and an output stream to
+ * write the data out. All pages are supplied in the order they appear in the
+ * document. In order to save memory it is possble to render the pages out of
+ * order. Any page that is not ready to be rendered is setup by the renderer
+ * first so that it can reserve a space or reference for when the page is ready
+ * to be rendered.The renderer is responsible for managing the output format and
+ * associated data and flow.
+ * </p>
+ * <p>
+ * Each renderer is totally responsible for its output format. Because font
+ * metrics (and therefore layout) are obtained in two different ways depending
+ * on the renderer, the renderer actually sets up the fonts being used. The font
+ * metrics are used during the layout process to determine the size of
+ * characters.
+ * </p>
+ * <p>
+ * The render context is used by handlers. It contains information about the
+ * current state of the renderer, such as the page, the position, and any other
+ * miscellanous objects that are required to draw into the page.
+ * </p>
+ * <p>
+ * A renderer is created by implementing the Renderer interface. However, the
+ * AbstractRenderer does most of what is needed, including iterating through the
+ * tree parts, so it is this that is extended. This means that this object only
+ * need to implement the basic functionality such as text, images, and lines.
+ * AbstractRenderer's methods can easily be overridden to handle things in a
+ * different way or do some extra processing.
+ * </p>
+ * <p>
+ * The relevent AreaTree structures that will need to be rendered are Page,
+ * Viewport, Region, Span, Block, Line, Inline. A renderer implementation
+ * renders each individual page, clips and aligns child areas to a viewport,
+ * handle all types of inline area, text, image etc and draws various lines and
+ * rectangles.
+ * </p>
+ *
+ * Note: There are specific extensions that have been added to the
+ * FO. They are specific to their location within the FO and have to be
+ * processed accordingly (ie. at the start or end of the page).
+ *
+ */
+public class AFPRenderer extends AbstractPathOrientedRenderer {
+
+ /**
+ * AFP factor for a 240 resolution = 72000/240 = 300
+ */
+ private static final int DPI_CONVERSION_FACTOR_240 = 300;
+
+ /**
+ * The afp data stream object responsible for generating afp data
+ */
+ private AFPDataStream _afpDataStream = null;
+
+ /**
+ * The map of afp root extensions
+ */
+ private HashMap _rootExtensionMap = null;
+
+ /**
+ * The map of page segments
+ */
+ private HashMap _pageSegmentsMap = null;
+
+ /**
+ * The fonts on the current page
+ */
+ private HashMap _currentPageFonts = null;
+
+ /**
+ * The current color object
+ */
+ private AFPFontColor _currentColor = null;
+
+ /**
+ * The page font number counter, used to determine the next font reference
+ */
+ private int _pageFontCounter = 0;
+
+ /**
+ * The current font family
+ */
+ private String _currentFontFamily = "";
+
+ /**
+ * The current font size
+ */
+ private int _currentFontSize = 0;
+
+ /**
+ * The Options to be set on the AFPRenderer
+ */
+ private Map _afpOptions = null;
+
+ /**
+ * The page width
+ */
+ private int _pageWidth = 0;
+
+ /**
+ * The page height
+ */
+ private int _pageHeight = 0;
+
+ /**
+ * The current page sequence id
+ */
+ private String _pageSequenceId = null;
+
+ /**
+ * The portrait rotation
+ */
+ private int _portraitRotation = 0;
+
+ /**
+ * The landscape rotation
+ */
+ private int _landscapeRotation = 270;
+
+ /**
+ * The line cache, avoids drawing duplicate lines in tables.
+ */
+ private HashSet _lineCache = null;
+
+ /**
+ * The current x position for line drawing
+ */
+ private float _x;
+
+ /**
+ * The current y position for line drawing
+ */
+ 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;
+
+ /**
+ * Constructor for AFPRenderer.
+ */
+ public AFPRenderer() {
+ super();
+ }
+
+ /**
+ * Set up the font info
+ *
+ * @param inFontInfo font info to set up
+ */
+ public void setupFontInfo(FontInfo inFontInfo) {
+ this.fontInfo = inFontInfo;
+ int num = 1;
+ if (this.fontList != null && this.fontList.size() > 0) {
+ for (Iterator it = this.fontList.iterator(); it.hasNext(); ) {
+ AFPFontInfo afi = (AFPFontInfo)it.next();
+ AFPFont bf = (AFPFont)afi.getAFPFont();
+ for (Iterator it2 = afi.getFontTriplets().iterator(); it2.hasNext(); ) {
+ FontTriplet ft = (FontTriplet)it2.next();
+ this.fontInfo.addFontProperties("F" + num, ft.getName()
+ , ft.getStyle(), ft.getWeight());
+ this.fontInfo.addMetrics("F" + num, bf);
+ num++;
+ }
+ }
+ } else {
+ log.warn("No AFP fonts configured - using default setup");
+ }
+ if (this.fontInfo.fontLookup("sans-serif", "normal", 400) == null) {
+ CharacterSet cs = new FopCharacterSet("T1V10500", "Cp500", "CZH200 ", 1, new Helvetica());
+ AFPFont bf = new OutlineFont("Helvetica", cs);
+ this.fontInfo.addFontProperties("F" + num, "sans-serif", "normal", 400);
+ this.fontInfo.addMetrics("F" + num, bf);
+ num++;
+ }
+ if (this.fontInfo.fontLookup("serif", "normal", 400) == null) {
+ CharacterSet cs = new FopCharacterSet("T1V10500", "Cp500", "CZN200 ", 1, new TimesRoman());
+ AFPFont bf = new OutlineFont("Helvetica", cs);
+ this.fontInfo.addFontProperties("F" + num, "serif", "normal", 400);
+ this.fontInfo.addMetrics("F" + num, bf);
+ num++;
+ }
+ if (this.fontInfo.fontLookup("monospace", "normal", 400) == null) {
+ CharacterSet cs = new FopCharacterSet("T1V10500", "Cp500", "CZ4200 ", 1, new Courier());
+ AFPFont bf = new OutlineFont("Helvetica", cs);
+ this.fontInfo.addFontProperties("F" + num, "monospace", "normal", 400);
+ this.fontInfo.addMetrics("F" + num, bf);
+ num++;
+ }
+ if (this.fontInfo.fontLookup("any", "normal", 400) == null) {
+ FontTriplet ft = this.fontInfo.fontLookup("sans-serif", "normal", 400);
+ this.fontInfo.addFontProperties(this.fontInfo.getInternalFontKey(ft), "any", "normal", 400);
+ }
+ }
+
+ /**
+ */
+ private AFPFontInfo buildFont(Configuration fontCfg, String _path)
+ throws ConfigurationException {
+
+ Configuration[] triple = fontCfg.getChildren("font-triplet");
+ List tripleList = new java.util.ArrayList();
+ 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));
+ }
+
+ //build the fonts
+ Configuration afpFontCfg = fontCfg.getChild("afp-font");
+ if (afpFontCfg == null) {
+ log.error("Mandatory font configuration element '<afp-font...' is missing");
+ return null;
+ }
+ String path = afpFontCfg.getAttribute("path", _path);
+ String type = afpFontCfg.getAttribute("type");
+ if (type == null) {
+ log.error("Mandatory afp-font configuration attribute 'type=' is missing");
+ return null;
+ }
+ String codepage = afpFontCfg.getAttribute("codepage");
+ if (codepage == null) {
+ log.error("Mandatory afp-font configuration attribute 'code=' is missing");
+ return null;
+ }
+ String encoding = afpFontCfg.getAttribute("encoding");
+ if (encoding == null) {
+ log.error("Mandatory afp-font configuration attribute 'encoding=' is missing");
+ return null;
+ }
+
+ if ("raster".equalsIgnoreCase(type)) {
+
+ String name = afpFontCfg.getAttribute("name", "Unknown");
+
+ // Create a new font object
+ RasterFont font = new RasterFont(name);
+
+ Configuration[] rasters = afpFontCfg.getChildren("afp-raster-font");
+ if (rasters.length == 0) {
+ log.error("Mandatory font configuration elements '<afp-raster-font...' are missing");
+ return null;
+ }
+ for (int j = 0; j < rasters.length; j++) {
+ Configuration rasterCfg = rasters[j];
+
+ String characterset = rasterCfg.getAttribute("characterset");
+ if (characterset == null) {
+ log.error("Mandatory afp-raster-font configuration attribute 'characterset=' is missing");
+ return null;
+ }
+ int size = rasterCfg.getAttributeAsInteger("size");
+ String base14 = rasterCfg.getAttribute("base14-font", null);
+
+ if (base14 != null) {
+ try {
+ Class clazz = Class.forName("org.apache.fop.fonts.base14."
+ + base14);
+ try {
+ Typeface tf = (Typeface)clazz.newInstance();
+ font.addCharacterSet(size, new FopCharacterSet(
+ codepage, encoding, characterset, size, tf));
+ } catch (Exception ie) {
+ String msg = "The base 14 font class " + clazz.getName()
+ + " could not be instantiated";
+ log.error(msg);
+ }
+ } catch (ClassNotFoundException cnfe) {
+ String msg = "The base 14 font class for " + characterset
+ + " could not be found";
+ log.error(msg);
+ }
+ } else {
+ font.addCharacterSet(size, new CharacterSet(
+ codepage, encoding, characterset, path));
+ }
+ }
+ return new AFPFontInfo(font, tripleList);
+
+ } 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."
+ + base14);
+ try {
+ Typeface tf = (Typeface)clazz.newInstance();
+ characterSet = new FopCharacterSet(
+ codepage, encoding, characterset, 1, tf);
+ } catch (Exception ie) {
+ String msg = "The base 14 font class " + clazz.getName()
+ + " could not be instantiated";
+ log.error(msg);
+ }
+ } catch (ClassNotFoundException cnfe) {
+ String msg = "The base 14 font class for " + characterset
+ + " could not be found";
+ log.error(msg);
+ }
+ } else {
+ characterSet = new CharacterSet(codepage, encoding, characterset, path);
+ }
+ // Create a new font object
+ OutlineFont font = new OutlineFont(name, characterSet);
+ return new AFPFontInfo(font, tripleList);
+ } else {
+ log.error("No or incorrect type attribute");
+ }
+ return null;
+ }
+
+ /**
+ * 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
+ */
+ public List buildFontListFromConfiguration(Configuration cfg)
+ throws ConfigurationException {
+ List fontList = new java.util.ArrayList();
+ Configuration[] font = cfg.getChild("fonts").getChildren("font");
+ for (int i = 0; i < font.length; i++) {
+ AFPFontInfo afi = buildFont(font[i], null);
+ 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);
+ log.debug("Font triplet "
+ + triplet.getName() + ", "
+ + triplet.getStyle() + ", "
+ + triplet.getWeight());
+ }
+ }
+
+ fontList.add(afi);
+ }
+ }
+ return fontList;
+ }
+
+ /**
+ * Configure the AFP renderer.
+ * Get the configuration to be used for fonts etc.
+ * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
+ */
+ public void configure(Configuration cfg) throws ConfigurationException {
+ //Font configuration
+ this.fontList = buildFontListFromConfiguration(cfg);
+ Configuration images = cfg.getChild("images");
+ if (!"color".equalsIgnoreCase(images.getAttribute("mode", "b+w"))) {
+ bitsPerPixel = images.getAttributeAsInteger("bits-per-pixel", 8);
+ 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;
+ }
+ } else {
+ colorImages = true;
+ }
+
+ }
+
+ /**
+ * @see org.apache.fop.render.Renderer#setUserAgent(FOUserAgent)
+ */
+ public void setUserAgent(FOUserAgent agent) {
+ super.setUserAgent(agent);
+ }
+
+ /**
+ * @see org.apache.fop.render.Renderer#startRenderer(java.io.OutputStream)
+ */
+ public void startRenderer(OutputStream outputStream) throws IOException {
+ _currentPageFonts = new HashMap();
+ _currentColor = new AFPFontColor(255, 255, 255);
+ _afpDataStream = new AFPDataStream();
+ _afpDataStream.setPortraitRotation(_portraitRotation);
+ _afpDataStream.setLandscapeRotation(_landscapeRotation);
+ _afpDataStream.startDocument(outputStream);
+ }
+
+ /**
+ * @see org.apache.fop.render.Renderer#stopRenderer(java.io.OutputStream)
+ */
+ public void stopRenderer() throws IOException {
+ _afpDataStream.endDocument();
+ }
+
+ /**
+ * @see org.apache.fop.render.Renderer#supportsOutOfOrder()
+ */
+ public boolean supportsOutOfOrder() {
+ //return false;
+ return true;
+ }
+
+ /**
+ * Prepare a page for rendering. This is called if the renderer supports
+ * out of order rendering. The renderer should prepare the page so that a
+ * page further on in the set of pages can be rendered. The body of the
+ * page should not be rendered. The page will be rendered at a later time
+ * by the call to render page.
+ *
+ * @see org.apache.fop.render.Renderer#preparePage(PageViewport)
+ */
+ public void preparePage(PageViewport page) {
+ // initializeRootExtensions(page);
+
+ _currentFontFamily = "";
+ _currentFontSize = 0;
+ _pageFontCounter = 0;
+ _currentPageFonts.clear();
+ _lineCache = new HashSet();
+
+ Rectangle2D bounds = page.getViewArea();
+
+ _pageWidth = mpts2units(bounds.getWidth());
+ _pageHeight = mpts2units(bounds.getHeight());
+
+ // renderPageGroupExtensions(page);
+
+ _afpDataStream.startPage(_pageWidth, _pageHeight, 0);
+
+ renderPageObjectExtensions(page);
+
+ if (_pages == null) {
+ _pages = new HashMap();
+ }
+ _pages.put(page, _afpDataStream.savePage());
+
+ }
+
+ /**
+ * @see org.apache.fop.render.Renderer#processOffDocumentItem(OffDocumentItem)
+ */
+ public void processOffDocumentItem(OffDocumentItem odi) {
+ // TODO
+ }
+
+ /** @see org.apache.fop.render.Renderer#getGraphics2DAdapter() */
+ public Graphics2DAdapter getGraphics2DAdapter() {
+ // TODO
+ return null;
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#startVParea(CTM, Rectangle2D)
+ */
+ public void startVParea(CTM ctm, Rectangle2D clippingRect) {
+ // dummy not used
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#endVParea()
+ */
+ 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();
+ }
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List)
+ */
+ protected void renderBlockViewport(BlockViewport bv, List children) {
+ // clip and position viewport if necessary
+
+ // save positions
+ int saveIP = currentIPPosition;
+ int saveBP = currentBPPosition;
+ //String saveFontName = currentFontName;
+
+ CTM ctm = bv.getCTM();
+ int borderPaddingStart = bv.getBorderAndPaddingWidthStart();
+ int borderPaddingBefore = bv.getBorderAndPaddingWidthBefore();
+ float x, y;
+ x = (float)(bv.getXOffset() + containingIPPosition) / 1000f;
+ y = (float)(bv.getYOffset() + containingBPPosition) / 1000f;
+ //This is the content-rect
+ float width = (float)bv.getIPD() / 1000f;
+ float height = (float)bv.getBPD() / 1000f;
+
+
+ if (bv.getPositioning() == Block.ABSOLUTE
+ || bv.getPositioning() == Block.FIXED) {
+
+ currentIPPosition = bv.getXOffset();
+ currentBPPosition = bv.getYOffset();
+
+ //For FIXED, we need to break out of the current viewports to the
+ //one established by the page. We save the state stack for restoration
+ //after the block-container has been painted. See below.
+ List breakOutList = null;
+ if (bv.getPositioning() == Block.FIXED) {
+ breakOutList = breakOutOfStateStack();
+ }
+
+ CTM tempctm = new CTM(containingIPPosition, containingBPPosition);
+ ctm = tempctm.multiply(ctm);
+
+ //Adjust for spaces (from margin or indirectly by start-indent etc.
+ x += bv.getSpaceStart() / 1000f;
+ currentIPPosition += bv.getSpaceStart();
+
+ y += bv.getSpaceBefore() / 1000f;
+ currentBPPosition += bv.getSpaceBefore();
+
+ float bpwidth = (borderPaddingStart + bv.getBorderAndPaddingWidthEnd()) / 1000f;
+ float bpheight = (borderPaddingBefore + bv.getBorderAndPaddingWidthAfter()) / 1000f;
+
+ drawBackAndBorders(bv, x, y, width + bpwidth, height + bpheight);
+
+ //Now adjust for border/padding
+ currentIPPosition += borderPaddingStart;
+ 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();
+
+ 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());
+ }
+ //currentFontName = saveFontName;
+ }
+
+ /**
+ * @see org.apache.fop.render.Renderer#renderPage(PageViewport)
+ */
+ public void renderPage(PageViewport page) {
+
+ // initializeRootExtensions(page);
+
+ _currentFontFamily = "";
+ _currentFontSize = 0;
+ _pageFontCounter = 0;
+ _currentPageFonts.clear();
+ _lineCache = new HashSet();
+
+ Rectangle2D bounds = page.getViewArea();
+
+ _pageWidth = mpts2units(bounds.getWidth());
+ _pageHeight = mpts2units(bounds.getHeight());
+
+ if (_pages != null && _pages.containsKey(page)) {
+
+ _afpDataStream.restorePage((PageObject)_pages.remove(page));
+
+ } else {
+ // renderPageGroupExtensions(page);
+
+ _afpDataStream.startPage(_pageWidth, _pageHeight, 0);
+
+ renderPageObjectExtensions(page);
+
+ }
+
+ pushViewPortPos(new ViewPortPos());
+
+ renderPageAreas(page.getPage());
+
+ Iterator i = _currentPageFonts.values().iterator();
+ while (i.hasNext()) {
+ AFPFontAttributes afpFontAttributes = (AFPFontAttributes) i.next();
+
+ _afpDataStream.createFont(
+ afpFontAttributes.getFontReference(),
+ afpFontAttributes.getFont(),
+ afpFontAttributes.getPointSize());
+
+ }
+
+ try {
+ _afpDataStream.endPage();
+ } catch (IOException ioex) {
+ // TODO What shall we do?
+ }
+
+ popViewPortPos();
+
+ }
+
+ /**
+ * Clip using the current path.
+ * @see org.apache.fop.render.AbstractRenderer#clip
+ */
+ public void clip() {
+ // TODO
+ }
+
+ /**
+ * Clip using a rectangular area.
+ * @see org.apache.fop.render.AbstractRenderer#clipRect(float, float, float, float)
+ */
+ public void clipRect(float x, float y, float width, float height) {
+ // TODO
+ }
+
+ /**
+ * Moves the current point to (x, y), omitting any connecting line segment.
+ * @see org.apache.fop.render.AbstractRenderer#moveTo(float, float)
+ */
+ public void moveTo(float x, float y) {
+ // TODO
+ }
+
+ /**
+ * Appends a straight line segment from the current point to (x, y). The
+ * new current point is (x, y).
+ * @see org.apache.fop.render.AbstractRenderer#lineTo(float, float)
+ */
+ public void lineTo(float x, float y) {
+ // TODO
+ }
+
+ /**
+ * Closes the current subpath by appending a straight line segment from
+ * the current point to the starting point of the subpath.
+ * @see org.apache.fop.render.AbstractRenderer#closePath
+ */
+ public void closePath() {
+ // TODO
+ }
+
+ /**
+ * Fill a rectangular area.
+ * @see org.apache.fop.render.AbstractRenderer#fillRect(float, float, float, float)
+ */
+ 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);
+ }
+
+ /**
+ * Draw a border segment of an XSL-FO style border.
+ * @see org.apache.fop.render.AbstractRenderer#drawBorderLine(float, float, float, float,
+ * boolean, boolean, int, ColorType)
+ */
+ public void drawBorderLine(float x1, float y1, float x2, float y2,
+ boolean horz, boolean startOrBefore, int style, ColorType 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),
+ new AFPFontColor(col)
+ );
+ _afpDataStream.createLine(
+ pts2units(x1),
+ pts2units(ym2),
+ pts2units(x2),
+ pts2units(ym2),
+ pts2units(h3),
+ new AFPFontColor(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),
+ new AFPFontColor(col)
+ );
+ _afpDataStream.createLine(
+ pts2units(xm2),
+ pts2units(y1),
+ pts2units(xm2),
+ pts2units(y2),
+ pts2units(w3),
+ new AFPFontColor(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),
+ new AFPFontColor(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),
+ new AFPFontColor(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),
+ new AFPFontColor(col)
+ );
+ x1 += 2 * h;
+ }
+ } else {
+ while (y1 + w < y2) {
+ _afpDataStream.createLine(
+ pts2units(x1),
+ pts2units(y1),
+ pts2units(x1),
+ pts2units(y1 + w),
+ pts2units(w),
+ new AFPFontColor(col)
+ );
+ y1 += 2 * w;
+ }
+ }
+ break;
+ case Constants.EN_GROOVE:
+ case Constants.EN_RIDGE:
+ {
+ float colFactor = (style == EN_GROOVE ? 0.4f : -0.4f);
+ Color c = toColor(col);
+ if (horz) {
+ Color uppercol = lightenColor(c, -colFactor);
+ Color lowercol = lightenColor(c, colFactor);
+ float h3 = h / 3;
+ float ym1 = y1;
+ _afpDataStream.createLine(
+ pts2units(x1),
+ pts2units(ym1),
+ pts2units(x2),
+ pts2units(ym1),
+ pts2units(h3),
+ new AFPFontColor(uppercol)
+ );
+ _afpDataStream.createLine(
+ pts2units(x1),
+ pts2units(ym1 + h3),
+ pts2units(x2),
+ pts2units(ym1 + h3),
+ pts2units(h3),
+ new AFPFontColor(c)
+ );
+ _afpDataStream.createLine(
+ pts2units(x1),
+ pts2units(ym1 + h3 + h3),
+ pts2units(x2),
+ pts2units(ym1 + h3 + h3),
+ pts2units(h3),
+ new AFPFontColor(lowercol)
+ );
+ } else {
+ Color leftcol = lightenColor(c, -colFactor);
+ Color rightcol = lightenColor(c, colFactor);
+ float w3 = w / 3;
+ float xm1 = x1 + (w3 / 2);
+ _afpDataStream.createLine(
+ pts2units(xm1),
+ pts2units(y1),
+ pts2units(xm1),
+ pts2units(y2),
+ pts2units(w3),
+ new AFPFontColor(leftcol)
+ );
+ _afpDataStream.createLine(
+ pts2units(xm1 + w3),
+ pts2units(y1),
+ pts2units(xm1 + w3),
+ pts2units(y2),
+ pts2units(w3),
+ new AFPFontColor(c)
+ );
+ _afpDataStream.createLine(
+ pts2units(xm1 + w3 + w3),
+ pts2units(y1),
+ pts2units(xm1 + w3 + w3),
+ pts2units(y2),
+ pts2units(w3),
+ new AFPFontColor(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))),
+ new AFPFontColor(col));
+ }
+ }
+
+ /**
+ * Draw an image at the indicated location.
+ * @see org.apache.fop.render.AbstractRenderer#drawImage(String, Rectangle2D)
+ */
+ public void drawImage(String url, Rectangle2D pos) {
+ String name = null;
+ if (_pageSegmentsMap != null) {
+ name = (String)_pageSegmentsMap.get(url);
+ }
+ if (name != null) {
+ int x = mpts2units(pos.getX() + currentIPPosition);
+ int y = mpts2units(pos.getY() + currentBPPosition);
+ _afpDataStream.createIncludePageSegment(name, x, y);
+ } else {
+ url = ImageFactory.getURL(url);
+ 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)) {
+ } else if (MimeConstants.MIME_SVG.equals(mime)) {
+ if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
+ return;
+ }
+ 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);
+ io.setImageParameters(
+ (int)(fopimage.getHorizontalResolution() * 10),
+ (int)(fopimage.getVerticalResolution() * 10),
+ fopimage.getWidth(),
+ fopimage.getHeight()
+ );
+ if (colorImages) {
+ io.setImageIDESize((byte)24);
+ io.setImageData(SVGConverter.convertToTIFF((XMLImage)fopimage));
+ } else {
+ convertToGrayScaleImage(io, SVGConverter.convertToTIFF((XMLImage)fopimage));
+ }
+ } else if (MimeConstants.MIME_EPS.equals(mime)) {
+ /*
+ } 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);
+ 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());
+ }
+ }
+ else
+ {
+ if (!fopimage.load(FopImage.BITMAP)) {
+ return;
+ }
+ convertToGrayScaleImage(io, fopimage.getBitmaps());
+ }
+ } 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);
+ 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());
+ }
+ }
+ }
+ }
+
+ /**
+ * Establishes a new foreground or fill color.
+ * @see org.apache.fop.render.AbstractRenderer#updateColor(ColorType, boolean)
+ */
+ public void updateColor(ColorType col, boolean fill) {
+ if (fill) {
+ _currentColor = new AFPFontColor(col);
+ }
+ }
+
+ /**
+ * Restores the state stack after a break out.
+ * @param breakOutList the state stack to restore.
+ */
+ public void restoreStateStackAfterBreakOut(List breakOutList) {
+
+ }
+
+ /**
+ * Breaks out of the state stack to handle fixed block-containers.
+ * @return the saved state stack to recreate later
+ */
+ public List breakOutOfStateStack() {
+ return null;
+ }
+
+ /** Saves the graphics state of the rendering engine. */
+ public void saveGraphicsState() {
+
+ }
+
+ /** Restores the last graphics state of the rendering engine. */
+ public void restoreGraphicsState() {
+
+ }
+
+ /** Indicates the beginning of a text object. */
+ public void beginTextObject() {
+
+ }
+
+ /** Indicates the end of a text object. */
+ public void endTextObject() {
+
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderImage(Image, Rectangle2D)
+ */
+ public void renderImage(Image image, Rectangle2D pos) {
+ String url = image.getURL();
+ drawImage(url, pos);
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderCharacter(Character)
+ */
+ public void renderCharacter(Character ch) {
+ renderInlineAreaBackAndBorders(ch);
+
+ String name = getInternalFontNameForArea(ch);
+ _currentFontSize = ((Integer) ch.getTrait(Trait.FONT_SIZE)).intValue();
+ AFPFont tf = (AFPFont) fontInfo.getFonts().get(name);
+ _currentFontFamily = name;
+
+ ColorType ct = (ColorType) ch.getTrait(Trait.COLOR);
+
+ int vsci = mpts2units(tf.getWidth(' ', _currentFontSize) / 1000
+ + ch.getTextWordSpaceAdjust()
+ + ch.getTextLetterSpaceAdjust());
+
+ // word.getOffset() = only height of text itself
+ // currentBlockIPPosition: 0 for beginning of line; nonzero
+ // where previous line area failed to take up entire allocated space
+ int rx = currentIPPosition + ch.getBorderAndPaddingWidthStart();
+ int bl = currentBPPosition + ch.getOffset() + ch.getBaselineOffset();
+
+ // Set letterSpacing
+ //float ls = fs.getLetterSpacing() / this.currentFontSize;
+
+ String worddata = ch.getChar();
+
+ // Create an AFPFontAttributes object from the current font details
+ AFPFontAttributes afpFontAttributes =
+ new AFPFontAttributes(name, tf,_currentFontSize);
+
+ if (!_currentPageFonts.containsKey(afpFontAttributes.getFontKey())) {
+ // Font not found on current page, so add the new one
+ _pageFontCounter++;
+ afpFontAttributes.setFontReference(_pageFontCounter);
+ _currentPageFonts.put(
+ afpFontAttributes.getFontKey(),
+ afpFontAttributes);
+
+ } else {
+ // Use the previously stored font attributes
+ afpFontAttributes =
+ (AFPFontAttributes) _currentPageFonts.get(afpFontAttributes.getFontKey());
+
+ }
+
+ // Try and get the encoding to use for the font
+ String encoding = null;
+
+ try {
+ encoding = tf.getCharacterSet(_currentFontSize).getEncoding();
+ } catch (Throwable ex) {
+ encoding = AFPConstants.EBCIDIC_ENCODING;
+ log.warn(
+ "renderTextArea():: Error getting encoding for font "
+ + " - using default encoding "
+ + encoding);
+ }
+
+ try {
+ _afpDataStream.createText(
+ afpFontAttributes.getFontReference(),
+ mpts2units(rx),
+ mpts2units(bl),
+ new AFPFontColor(ct),
+ vsci,
+ mpts2units(ch.getTextLetterSpaceAdjust()),
+ worddata.getBytes(encoding));
+
+ } catch (UnsupportedEncodingException usee) {
+ log.error(
+ "renderWordArea:: Font "
+ + afpFontAttributes.getFontKey()
+ + " caused UnsupportedEncodingException");
+
+ }
+
+ super.renderCharacter(ch);
+
+ renderTextDecoration(tf, _currentFontSize, ch, bl, rx);
+
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderText(TextArea)
+ */
+ 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);
+
+ ColorType ct = (ColorType) text.getTrait(Trait.COLOR);
+
+ int vsci = mpts2units(tf.getWidth(' ', _currentFontSize) / 1000
+ + text.getTextWordSpaceAdjust()
+ + text.getTextLetterSpaceAdjust());
+
+ // word.getOffset() = only height of text itself
+ // currentBlockIPPosition: 0 for beginning of line; nonzero
+ // where previous line area failed to take up entire allocated space
+ int rx = currentIPPosition + text.getBorderAndPaddingWidthStart();
+ int bl = currentBPPosition + text.getOffset() + text.getBaselineOffset();
+
+ // Set letterSpacing
+ //float ls = fs.getLetterSpacing() / this.currentFontSize;
+
+ String worddata = text.getText();
+
+ // Create an AFPFontAttributes object from the current font details
+ AFPFontAttributes afpFontAttributes =
+ new AFPFontAttributes(name, tf, _currentFontSize);
+
+ if (!_currentPageFonts.containsKey(afpFontAttributes.getFontKey())) {
+ // Font not found on current page, so add the new one
+ _pageFontCounter++;
+ afpFontAttributes.setFontReference(_pageFontCounter);
+ _currentPageFonts.put(
+ afpFontAttributes.getFontKey(),
+ afpFontAttributes);
+
+ } else {
+ // Use the previously stored font attributes
+ afpFontAttributes =
+ (AFPFontAttributes) _currentPageFonts.get(
+ afpFontAttributes.getFontKey());
+ }
+
+ // Try and get the encoding to use for the font
+ String encoding = null;
+
+ try {
+ encoding = tf.getCharacterSet(_currentFontSize).getEncoding();
+ } catch (Throwable ex) {
+ encoding = AFPConstants.EBCIDIC_ENCODING;
+ log.warn(
+ "renderText():: Error getting encoding for font "
+ + " - using default encoding "
+ + encoding);
+ }
+
+ try {
+ _afpDataStream.createText(
+ afpFontAttributes.getFontReference(),
+ mpts2units(rx),
+ mpts2units(bl),
+ new AFPFontColor(ct),
+ vsci,
+ mpts2units(text.getTextLetterSpaceAdjust()),
+ worddata.getBytes(encoding));
+ } catch (UnsupportedEncodingException usee) {
+ log.error(
+ "renderText:: Font "
+ + afpFontAttributes.getFontKey()
+ + " caused UnsupportedEncodingException");
+ }
+
+ super.renderText(text);
+
+ renderTextDecoration(tf, _currentFontSize, text, bl, rx);
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderWord(WordArea)
+ */
+ public void renderWord(WordArea word) {
+ 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);
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderSpace(SpaceArea)
+ */
+ public void renderSpace(SpaceArea space) {
+ 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
+ */
+ public void renderLeader(Leader area) {
+ renderInlineAreaBackAndBorders(area);
+
+ int style = area.getRuleStyle();
+ float startx = (currentIPPosition + area.getBorderAndPaddingWidthStart()) / 1000f;
+ float starty = (currentBPPosition + area.getOffset()) / 1000f;
+ float endx = (currentIPPosition + area.getBorderAndPaddingWidthStart()
+ + area.getIPD()) / 1000f;
+ float ruleThickness = area.getRuleThickness() / 1000f;
+ ColorType col = (ColorType)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");
+ }
+ super.renderLeader(area);
+ }
+
+ /**
+ * @see org.apache.fop.render.Renderer#setProducer(String)
+ */
+ public void setProducer(String producer) {
+ _afpDataStream.setProducer(producer);
+ }
+
+ /**
+ * @see org.apache.fop.render.Renderer#setOptions(Map)
+ */
+ public void setOptions(Map options) {
+
+ _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
+ */
+ 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
+ */
+ public String getMimeType() {
+ return MimeConstants.MIME_AFP;
+ }
+
+ /**
+ * Method to render the page extension.
+ * <p>
+ *
+ * @param page
+ * the page object
+ */
+ private void renderPageObjectExtensions(PageViewport page) {
+
+ _pageSegmentsMap = null;
+ if (page.getExtensionAttachments().size() > 0) {
+ //Extract all AFPPageSetup instances from the attachment list on the s-p-m
+ Iterator i = page.getExtensionAttachments().iterator();
+ while (i.hasNext()) {
+ ExtensionAttachment attachment = (ExtensionAttachment)i.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);
+ }
+ } 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);
+ } 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);
+ }
+ }
+ }
+ }
+
+ }
+
+ /**
+ * 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
+ * @param mpt the millipoints value
+ */
+ private int mpts2units(double mpt) {
+ return (int)Math.round(mpt / DPI_CONVERSION_FACTOR_240);
+ }
+
+ private void convertToGrayScaleImage(ImageObject io, byte raw[]) {
+ int pixelsPerByte = 8 / bitsPerPixel;
+ byte bw[] = new byte[raw.length / (3 * pixelsPerByte)];
+ int k = 0;
+ for (int i = 0, j = 0; i < raw.length; i += 3, j++) {
+ if (j == pixelsPerByte) {
+ j = 0;
+ k++;
+ }
+ // 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) {
+ bw[k] |= (byte)(1 << j);
+ }
+ break;
+ case 4:
+ greyVal /= 16;
+ bw[k] |= (byte)((byte)greyVal << (j * 4));
+ break;
+ case 8:
+ bw[k] = (byte)greyVal;
+ break;
+ }
+ }
+ io.setImageIDESize((byte)bitsPerPixel);
+ io.setImageData(bw);
+ }
+
+ private class ViewPortPos {
+ int x = 0;
+ int y = 0;
+ int rot = 0;
+
+ ViewPortPos() {
+ }
+
+ 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;
+ }
+ }
+
+ 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 void popViewPortPos() {
+ 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);
+ }
+ }
+
+}
+
diff --git a/src/sandbox/org/apache/fop/render/afp/AFPRendererMaker.java b/src/sandbox/org/apache/fop/render/afp/AFPRendererMaker.java
new file mode 100644
index 000000000..54715f288
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/AFPRendererMaker.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.apps.FOUserAgent;
+import org.apache.fop.apps.MimeConstants;
+import org.apache.fop.render.AbstractRendererMaker;
+import org.apache.fop.render.Renderer;
+
+/**
+ * RendererMaker for the AFP Renderer.
+ */
+public class AFPRendererMaker extends AbstractRendererMaker {
+
+ private static final String[] MIMES = new String[] {
+ MimeConstants.MIME_AFP,
+ MimeConstants.MIME_AFP_ALT};
+
+
+ /**@see org.apache.fop.render.AbstractRendererMaker */
+ public Renderer makeRenderer(FOUserAgent ua) {
+ return new AFPRenderer();
+ }
+
+ /** @see org.apache.fop.render.AbstractRendererMaker#needsOutputStream() */
+ public boolean needsOutputStream() {
+ return true;
+ }
+
+ /** @see org.apache.fop.render.AbstractRendererMaker#getSupportedMimeTypes() */
+ public String[] getSupportedMimeTypes() {
+ return MIMES;
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/exceptions/FontRuntimeException.java b/src/sandbox/org/apache/fop/render/afp/exceptions/FontRuntimeException.java
new file mode 100644
index 000000000..ea692b1dd
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/exceptions/FontRuntimeException.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.exceptions;
+
+/**
+ * A runtime exception for handling fatal errors in processing fonts.
+ * <p/>
+ */
+public class FontRuntimeException extends NestedRuntimeException {
+
+ /**
+ * Constructs a FontRuntimeException with the specified message.
+ * @param msg the exception mesaage
+ */
+ public FontRuntimeException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a FontRuntimeException with the specified message
+ * wrapping the underlying exception.
+ * @param msg the exception mesaage
+ * @param t the underlying exception
+ */
+ public FontRuntimeException(String msg, Throwable t) {
+ super(msg, t);
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/exceptions/NestedRuntimeException.java b/src/sandbox/org/apache/fop/render/afp/exceptions/NestedRuntimeException.java
new file mode 100644
index 000000000..92254e6e6
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/exceptions/NestedRuntimeException.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.exceptions;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * Handy class for wrapping runtime Exceptions with a root cause.
+ * This technique is no longer necessary in Java 1.4, which provides
+ * built-in support for exception nesting. Thus exceptions in applications
+ * written to use Java 1.4 need not extend this class.
+ *
+ */
+public abstract class NestedRuntimeException extends RuntimeException {
+
+ /** Root cause of this nested exception */
+ private Throwable _underlyingException;
+
+ /**
+ * Construct a <code>NestedRuntimeException</code> with the specified detail message.
+ * @param msg The detail message.
+ */
+ public NestedRuntimeException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Construct a <code>NestedRuntimeException</code> with the specified
+ * detail message and nested exception.
+ * @param msg The detail message.
+ * @param t The nested exception.
+ */
+ public NestedRuntimeException(String msg, Throwable t) {
+ super(msg);
+ _underlyingException = t;
+
+ }
+
+ /**
+ * Gets the original triggering exception
+ * @return The original exception as a throwable.
+ */
+ public Throwable getUnderlyingException() {
+
+ return _underlyingException;
+
+ }
+
+ /**
+ * Return the detail message, including the message from the nested
+ * exception if there is one.
+ * @return The detail message.
+ */
+ public String getMessage() {
+
+ if (_underlyingException == null) {
+ return super.getMessage();
+ } else {
+ return super.getMessage()
+ + "; nested exception is "
+ + _underlyingException.getClass().getName();
+ }
+
+ }
+
+ /**
+ * Print the composite message and the embedded stack trace to the specified stream.
+ * @param ps the print stream
+ */
+ public void printStackTrace(PrintStream ps) {
+ if (_underlyingException == null) {
+ super.printStackTrace(ps);
+ } else {
+ ps.println(this);
+ _underlyingException.printStackTrace(ps);
+ }
+ }
+
+ /**
+ * Print the composite message and the embedded stack trace to the specified writer.
+ * @param pw the print writer
+ */
+ public void printStackTrace(PrintWriter pw) {
+ if (_underlyingException == null) {
+ super.printStackTrace(pw);
+ } else {
+ pw.println(this);
+ _underlyingException.printStackTrace(pw);
+ }
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/exceptions/RendererRuntimeException.java b/src/sandbox/org/apache/fop/render/afp/exceptions/RendererRuntimeException.java
new file mode 100644
index 000000000..a3be63ecb
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/exceptions/RendererRuntimeException.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.exceptions;
+
+/**
+ * A runtime exception for handling fatal errors in rendering.
+ * <p/>
+ */
+public class RendererRuntimeException extends NestedRuntimeException {
+
+ /**
+ * Constructs a RendererRuntimeException with the specified message.
+ * @param msg the exception mesaage
+ */
+ public RendererRuntimeException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a RendererRuntimeException with the specified message
+ * wrapping the underlying exception.
+ * @param msg the exception mesaage
+ * @param t the underlying exception
+ */
+ public RendererRuntimeException(String msg, Throwable t) {
+ super(msg, t);
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/extensions/AFPAttribute.java b/src/sandbox/org/apache/fop/render/afp/extensions/AFPAttribute.java
new file mode 100755
index 000000000..a1c63856b
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/extensions/AFPAttribute.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 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
+ * extraction of attributes from formatted objects based on the static list
+ * as defined in the AFPElementMapping implementation.
+ * <p/>
+ */
+public class AFPAttribute extends StringProperty.Maker {
+
+ /**
+ * The attribute property.
+ */
+ private Property _property;
+
+ /**
+ * Constructor for the AFPAttribute.
+ * @param name The attribute name
+ */
+ protected AFPAttribute(String name) {
+ super(0);
+ _property = null;
+ }
+
+ /**
+ * Overide the make method to return the property object
+ * @return property The property object.
+ */
+ public Property make(PropertyList propertyList) {
+ if (_property == null) {
+ _property = make(propertyList, "", propertyList.getParentFObj());
+ }
+ return _property;
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/extensions/AFPElementMapping.java b/src/sandbox/org/apache/fop/render/afp/extensions/AFPElementMapping.java
new file mode 100755
index 000000000..350b75c1e
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/extensions/AFPElementMapping.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.util.HashMap;
+
+import org.apache.fop.fo.ElementMapping;
+import org.apache.fop.fo.FONode;
+
+
+/**
+ * AFPElementMapping object provides the ability to extract information
+ * from the formatted object that reside in the afp namespace. This is used
+ * for custom AFP extensions not supported by the FO schema. Examples include
+ * adding overlays or indexing a document using the tag logical element
+ * structured field.
+ * <p/>
+ */
+public class AFPElementMapping extends ElementMapping {
+
+ public static final String PAGE = "page";
+
+ public static final String PAGE_GROUP = "page-group";
+
+ public static final String TAG_LOGICAL_ELEMENT = "tag-logical-element";
+
+ public static final String INCLUDE_PAGE_OVERLAY = "include-page-overlay";
+
+ public static final String INCLUDE_PAGE_SEGMENT = "include-page-segment";
+
+ /**
+ * The namespace used for AFP extensions
+ */
+ public static final String NAMESPACE = "http://org.apache.fop/extensions/afp";
+
+ /**
+ * The usual namespace prefix used for AFP extensions
+ */
+ public static final String NAMESPACE_PREFIX = "afp";
+
+ /** Main constructor */
+ public AFPElementMapping() {
+ this.namespaceURI = NAMESPACE;
+ }
+
+ /**
+ * Private static synchronized method to set up the element and atribute
+ * HashMaps, this defines what elements and attributes are extracted.
+ */
+ protected void initialize() {
+
+ if (foObjs == null) {
+ foObjs = new HashMap();
+ foObjs.put(PAGE, new AFPPageSetupMaker());
+ // foObjs.put(PAGE_GROUP, new AFPMaker());
+ foObjs.put(
+ TAG_LOGICAL_ELEMENT,
+ new AFPTagLogicalElementMaker());
+ foObjs.put(
+ INCLUDE_PAGE_SEGMENT,
+ new AFPIncludePageSegmentMaker());
+ foObjs.put(
+ INCLUDE_PAGE_OVERLAY,
+ new AFPIncludePageOverlayMaker());
+ }
+
+ }
+
+ static class AFPPageSetupMaker extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new AFPPageSetupElement(parent);
+ }
+ }
+
+ static class AFPIncludePageOverlayMaker extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new AFPElement(parent, INCLUDE_PAGE_OVERLAY);
+ }
+ }
+
+ static class AFPIncludePageSegmentMaker extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new AFPElement(parent, INCLUDE_PAGE_SEGMENT);
+ }
+ }
+
+ static class AFPTagLogicalElementMaker extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new AFPElement(parent, TAG_LOGICAL_ELEMENT);
+ }
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/extensions/AFPPageSetup.java b/src/sandbox/org/apache/fop/render/afp/extensions/AFPPageSetup.java
new file mode 100644
index 000000000..d95a3a458
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/extensions/AFPPageSetup.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+/**
+ * This is the pass-through value object for the PostScript extension.
+ */
+public class AFPPageSetup implements ExtensionAttachment, Serializable {
+
+ /** 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;
+
+ /**
+ * Default constructor.
+ * @param name the name of the setup code object, may be null
+ */
+ public AFPPageSetup(String name) {
+ this.elementName = name;
+ }
+
+ /** @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;
+ }
+
+ /**
+ * @return the value
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Sets the value
+ * @param value The value name to set.
+ */
+ public void setValue(String source) {
+ this.value = source;
+ }
+
+ /** @see org.apache.fop.fo.extensions.ExtensionAttachment#getCategory() */
+ public String getCategory() {
+ return CATEGORY;
+ }
+
+ /** @see java.lang.Object#toString() */
+ public String toString() {
+ return "AFPPageSetup(element-name=" + getElementName() + " name=" + getName() + ")";
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java b/src/sandbox/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java
new file mode 100644
index 000000000..cbdde917e
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.ValidationException;
+
+/**
+ * Extension element for fox:ps-page-setup-code.
+ */
+public class AFPPageSetupElement extends AbstractAFPExtensionObject {
+
+ /**
+ * Main constructor
+ * @param parent parent FO node
+ */
+ public AFPPageSetupElement(FONode parent) {
+ super(parent, "page");
+ }
+
+ /** @see org.apache.fop.fo.FONode#startOfNode() */
+ protected void startOfNode() throws FOPException {
+ super.startOfNode();
+ if (parent.getNameId() != Constants.FO_SIMPLE_PAGE_MASTER) {
+ throw new ValidationException(getName() + " must be a child of fo:simple-page-master.");
+ }
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/extensions/AbstractAFPExtensionObject.java b/src/sandbox/org/apache/fop/render/afp/extensions/AbstractAFPExtensionObject.java
new file mode 100644
index 000000000..b8dc7c740
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/extensions/AbstractAFPExtensionObject.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+// FOP
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.PropertyList;
+import org.apache.fop.fo.ValidationException;
+import org.apache.fop.fo.extensions.ExtensionAttachment;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+
+/**
+ * Base class for the AFP-specific extension elements.
+ */
+public abstract class AbstractAFPExtensionObject extends FONode {
+
+ private AFPPageSetup setupCode = null;
+
+ private String _name = null;
+
+ /**
+ * @see org.apache.fop.fo.FONode#FONode(FONode)
+ * @param parent the parent formatting object
+ * @param name the name of the afp element
+ */
+ public AbstractAFPExtensionObject(FONode parent, String name) {
+ super(parent);
+ _name = name;
+ setupCode = new AFPPageSetup(name);
+ }
+
+ /**
+ * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String)
+ * here, blocks XSL FO's from having non-FO parents.
+ */
+ protected void validateChildNode(Locator loc, String nsURI, String localName)
+ throws ValidationException {
+ if (FO_URI.equals(nsURI)) {
+ invalidChildError(loc, nsURI, localName);
+ }
+ }
+
+ /** @see org.apache.fop.fo.FONode */
+ protected void addCharacters(char[] data, int start, int length,
+ PropertyList pList, Locator locator) {
+ }
+
+ /** @see org.apache.fop.fo.FONode#getNamespaceURI() */
+ public String getNamespaceURI() {
+ return AFPElementMapping.NAMESPACE;
+ }
+
+ /**@see org.apache.fop.fo.FONode#getNormalNamespacePrefix() */
+ public String getNormalNamespacePrefix() {
+ return AFPElementMapping.NAMESPACE_PREFIX;
+ }
+
+ /** @see org.apache.fop.fo.FONode#processNode */
+ 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);
+ } 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);
+ } else {
+ throw new FOPException(elementName + " must have a src attribute.");
+ }
+ }
+ if (AFPElementMapping.TAG_LOGICAL_ELEMENT.equals(elementName)) {
+ name = attlist.getValue("value");
+ if (name != null && name.length() > 0) {
+ setupCode.setValue(name);
+ } else {
+ throw new FOPException(elementName + " must have a value attribute.");
+ }
+ }
+ }
+
+ /** @see org.apache.fop.fo.FONode#endOfNode() */
+ protected void endOfNode() throws FOPException {
+ super.endOfNode();
+ }
+
+ /** @see org.apache.fop.fo.FONode#getExtensionAttachment() */
+ public ExtensionAttachment getExtensionAttachment() {
+ return this.setupCode;
+ }
+
+ /** @see org.apache.fop.fo.FONode#getLocalName() */
+ public String getLocalName() {
+ return _name;
+ }
+
+}
+
diff --git a/src/sandbox/org/apache/fop/render/afp/fonts/AFPFont.java b/src/sandbox/org/apache/fop/render/afp/fonts/AFPFont.java
new file mode 100644
index 000000000..d17536a8d
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/fonts/AFPFont.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.Map;
+import org.apache.fop.fonts.FontType;
+import org.apache.fop.fonts.Typeface;
+
+
+/**
+ * All implemenations of AFP fonts should extend this base class,
+ * the object implements the FontMetrics information.
+ * <p/>
+ */
+public abstract class AFPFont extends Typeface {
+
+ /** The font name */
+ protected String _name;
+
+ /**
+ * Constructor for the base font requires the name.
+ * @param name the name of the font
+ */
+ public AFPFont(String name) {
+
+ _name = name;
+
+ }
+
+ /**
+ * @return the name of the font.
+ */
+ public String getFontName() {
+ return _name;
+ }
+
+ /**
+ * Returns the type of the font.
+ * @return the font type
+ */
+ public FontType getFontType() {
+ return FontType.OTHER;
+ }
+
+ /**
+ * Indicates if the font has kering information.
+ * @return True, if kerning is available.
+ */
+ public boolean hasKerningInfo() {
+ return false;
+ }
+
+ /**
+ * Returns the kerning map for the font.
+ * @return the kerning map
+ */
+ public Map getKerningInfo() {
+ return null;
+ }
+
+ /**
+ * Returns the character set for a given size
+ * @param size the font size
+ */
+ public abstract CharacterSet getCharacterSet(int size);
+
+ /**
+ * Determines whether this font contains a particular character/glyph.
+ * @param c character to check
+ * @return True if the character is supported, Falso otherwise
+ */
+ public boolean hasChar(char c) {
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/fonts/AFPFontInfo.java b/src/sandbox/org/apache/fop/render/afp/fonts/AFPFontInfo.java
new file mode 100644
index 000000000..ce08d4131
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/fonts/AFPFontInfo.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.List;
+
+/**
+ * FontInfo contains meta information on fonts
+ */
+public class AFPFontInfo {
+
+ private AFPFont font;
+ private List fontTriplets;
+
+ /**
+ * Main constructor
+ * @param afpFont The AFP Font
+ * @param fontTriplets List of font triplets to associate with this font
+ */
+ public AFPFontInfo(AFPFont afpFont, List fontTriplets) {
+ this.font = afpFont;
+ this.fontTriplets = fontTriplets;
+ }
+
+ /**
+ * Returns the afp font
+ * @return the afp font
+ */
+ public AFPFont getAFPFont() {
+ return font;
+ }
+
+ /**
+ * Returns the list of font triplets associated with this font.
+ * @return List of font triplets
+ */
+ public List getFontTriplets() {
+ return fontTriplets;
+ }
+
+}
+
diff --git a/src/sandbox/org/apache/fop/render/afp/fonts/AFPFontReader.java b/src/sandbox/org/apache/fop/render/afp/fonts/AFPFontReader.java
new file mode 100644
index 000000000..cb8718d8f
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/fonts/AFPFontReader.java
@@ -0,0 +1,608 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.io.File;
+import java.io.FileNotFoundException;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fop.render.afp.exceptions.FontRuntimeException;
+import org.apache.fop.render.afp.modca.AFPConstants;
+import org.apache.fop.render.afp.tools.StructuredFieldReader;
+
+/**
+ * The AFPFontReader is responsible for reading the font attributes from binary
+ * code page files and the character set metric files. In IBM font structure, a
+ * code page maps each character of text to the characters in a character set.
+ * Each character is translated into a code point. When the character is
+ * printed, each code point is matched to a character ID on the code page
+ * specified. The character ID is then matched to the image (raster pattern or
+ * outline pattern) of the character in the character set specified. The image
+ * in the character set is the image that is printed in the document. To be a
+ * valid code page for a particular character set, all character IDs in the code
+ * page must be included in that character set. <p/>This class will read the
+ * font information from the binary code page files and character set metric
+ * files in order to determine the correct metrics to use when rendering the
+ * formatted object. <p/>
+ *
+ * @author <a href="mailto:pete@townsend.uk.com">Pete Townsend </a>
+ */
+public final class AFPFontReader {
+
+ /**
+ * Static logging instance
+ */
+ protected static final Log log = LogFactory.getLog("org.apache.fop.render.afp.fonts");
+
+ /**
+ * Template used to convert lists to arrays.
+ */
+ private static final CharacterSetOrientation[] EMPTY_CSO_ARRAY = new CharacterSetOrientation[0];
+
+ /** Codepage MO:DCA structured field. */
+ private static final byte[] CODEPAGE_SF = new byte[] { (byte) 0xD3,
+ (byte) 0xA8, (byte) 0x87 };
+
+ /** Character table MO:DCA structured field. */
+ private static final byte[] CHARACTER_TABLE_SF = new byte[] { (byte) 0xD3,
+ (byte) 0x8C, (byte) 0x87 };
+
+ /** Font control MO:DCA structured field. */
+ private static final byte[] FONT_CONTROL_SF = new byte[] { (byte) 0xD3,
+ (byte) 0xA7, (byte) 0x89 };
+
+ /** Font orientation MO:DCA structured field. */
+ private static final byte[] FONT_ORIENTATION_SF = new byte[] { (byte) 0xD3,
+ (byte) 0xAE, (byte) 0x89 };
+
+ /** Font position MO:DCA structured field. */
+ private static final byte[] FONT_POSITION_SF = new byte[] { (byte) 0xD3,
+ (byte) 0xAC, (byte) 0x89 };
+
+ /** Font index MO:DCA structured field. */
+ private static final byte[] FONT_INDEX_SF = new byte[] { (byte) 0xD3,
+ (byte) 0x8C, (byte) 0x89 };
+
+ /**
+ * The conversion factor to millipoints for 240 dpi
+ */
+ private static final int FOP_100_DPI_FACTOR = 1;
+
+ /**
+ * The conversion factor to millipoints for 240 dpi
+ */
+ private static final int FOP_240_DPI_FACTOR = 300000;
+
+ /**
+ * The conversion factor to millipoints for 300 dpi
+ */
+ private static final int FOP_300_DPI_FACTOR = 240000;
+
+ /**
+ * The encoding to use to convert from EBCIDIC to ASCII
+ */
+ private static final String ASCII_ENCODING = "UTF8";
+
+ /**
+ * The collection of code pages
+ */
+ private static HashMap _codePages = new HashMap();
+
+ /**
+ * Load the font details and metrics into the CharacterSetMetric object,
+ * this will use the actual afp code page and character set files to load
+ * the object with the necessary metrics.
+ *
+ * @param characterSet the CharacterSetMetric object to populate
+ */
+ public static void loadCharacterSetMetric(CharacterSet characterSet) {
+
+ InputStream inputStream = null;
+
+ try {
+
+ /**
+ * Get the code page which contains the character mapping
+ * information to map the unicode character id to the graphic
+ * chracter global identifier.
+ */
+ String cp = new String(characterSet.getCodePage());
+ String path = characterSet.getPath();
+
+ HashMap codepage = (HashMap) _codePages.get(cp);
+
+ if (codepage == null) {
+ codepage = loadCodePage(cp, characterSet.getEncoding(), path);
+ _codePages.put(cp, codepage);
+ }
+
+ /**
+ * Load the character set metric information, no need to cache this
+ * information as it should be cached by the objects that wish to
+ * load character set metric information.
+ */
+ final String characterset = characterSet.getName();
+
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ if (classLoader == null) {
+ classLoader = AFPFontReader.class.getClassLoader();
+ }
+
+ URL url = classLoader.getResource(path);
+ if (url == null) {
+ try {
+ File file = new File(path);
+ url = file.toURL();
+ if (url == null) {
+ String msg = "CharacterSet file not found for "
+ + characterset + " in classpath: " + path;
+ log.error(msg);
+ throw new FileNotFoundException(msg);
+ }
+ } catch (MalformedURLException ex) {
+ String msg = "CharacterSet file not found for "
+ + characterset + " in classpath: " + path;
+ log.error(msg);
+ throw new FileNotFoundException(msg);
+ }
+
+ }
+
+ File directory = new File(url.getPath());
+
+ final String filterpattern = characterset.trim();
+ FilenameFilter filter = new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.startsWith(filterpattern);
+ }
+ };
+
+ File[] csfont = directory.listFiles(filter);
+ if (csfont.length < 1) {
+ String msg = "CharacterSet file search for " + characterset
+ + " located " + csfont.length + " files";
+ log.error(msg);
+ throw new FileNotFoundException(msg);
+ } else if (csfont.length > 1) {
+ String msg = "CharacterSet file search for " + characterset
+ + " located " + csfont.length + " files";
+ log.warn(msg);
+ }
+
+ inputStream = inputStream = csfont[0].toURL().openStream();
+ if (inputStream == null) {
+ String msg = "Failed to open character set resource "
+ + characterset;
+ log.error(msg);
+ throw new FileNotFoundException(msg);
+ }
+
+ StructuredFieldReader sfr = new StructuredFieldReader(inputStream);
+
+ // Process D3A789 Font Control
+ FontControl fnc = processFontControl(sfr);
+
+ //process D3AE89 Font Orientation
+ CharacterSetOrientation[] csoArray = processFontOrientation(sfr);
+
+ //process D3AC89 Font Position
+ processFontPosition(sfr, csoArray, fnc.getDpi());
+
+ //process D38C89 Font Index (per orientation)
+ for (int i = 0; i < csoArray.length; i++) {
+ processFontIndex(sfr, csoArray[i], codepage, fnc.getDpi());
+ characterSet.addCharacterSetOrientation(csoArray[i]);
+ }
+
+ } catch (Exception ex) {
+ throw new FontRuntimeException(
+ "Failed to load the character set metrics for code page "
+ + characterSet.getCodePage(), ex);
+ } finally {
+ try {
+ inputStream.close();
+ } catch (Exception ex) {
+ // Ignore
+ }
+ }
+
+ }
+
+ /**
+ * Load the code page information from the appropriate file. The file name
+ * to load is determined by the code page name and the file extension 'CDP'.
+ *
+ * @param codePage
+ * the code page identifier
+ * @param encoding
+ * the encoding to use for the character decoding
+ */
+ private static HashMap loadCodePage(String codePage, String encoding,
+ String path) throws IOException, FileNotFoundException {
+
+ // Create the HashMap to store code page information
+ HashMap codepages = new HashMap();
+
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ if (classLoader == null) {
+ classLoader = AFPFontReader.class.getClassLoader();
+ }
+
+ URL url = classLoader.getResource(path);
+
+ if (url == null) {
+ try {
+ File file = new File(path);
+ url = file.toURL();
+ if (url == null) {
+ String msg = "CodePage file not found for " + codePage
+ + " in classpath: " + path;
+ log.error(msg);
+ throw new FileNotFoundException(msg);
+ }
+ } catch (MalformedURLException ex) {
+ String msg = "CodePage file not found for " + codePage
+ + " in classpath: " + path;
+ log.error(msg);
+ throw new FileNotFoundException(msg);
+ }
+
+ }
+
+ File directory = new File(url.getPath());
+
+ final String filterpattern = codePage.trim();
+ FilenameFilter filter = new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.startsWith(filterpattern);
+ }
+ };
+
+ File[] codepage = directory.listFiles(filter);
+
+ if (codepage.length < 1) {
+ String msg = "CodePage file search for " + codePage + " located "
+ + codepage.length + " files";
+ log.error(msg);
+ throw new FileNotFoundException(msg);
+ } else if (codepage.length > 1) {
+ String msg = "CodePage file search for " + codePage + " located "
+ + codepage.length + " files";
+ log.warn(msg);
+ }
+
+ InputStream is = codepage[0].toURL().openStream();
+
+ if (is == null) {
+ String msg = "AFPFontReader:: loadCodePage(String):: code page file not found for "
+ + codePage;
+ log.error(msg);
+ throw new FileNotFoundException(msg);
+ }
+
+ StructuredFieldReader sfr = new StructuredFieldReader(is);
+ byte[] data = sfr.getNext(CHARACTER_TABLE_SF);
+
+ int position = 0;
+ byte[] gcgiBytes = new byte[8];
+ byte[] charBytes = new byte[1];
+
+ // Read data, ignoring bytes 0 - 2
+ for (int index = 3; index < data.length; index++) {
+ if (position < 8) {
+ // Build the graphic character global identifier key
+ gcgiBytes[position] = data[index];
+ position++;
+ } else if (position == 9) {
+ position = 0;
+ // Set the character
+ charBytes[0] = data[index];
+ String gcgiString = new String(gcgiBytes,
+ AFPConstants.EBCIDIC_ENCODING);
+ String charString = new String(charBytes, encoding);
+ int value = charString.charAt(0);
+ codepages.put(gcgiString, charString);
+ } else {
+ position++;
+ }
+ }
+
+ try {
+ is.close();
+ } catch (Exception ex) {
+ // Ignore
+ }
+
+ return codepages;
+
+ }
+
+ /**
+ * Process the font control details using the structured field reader.
+ *
+ * @param sfr
+ * the structured field reader
+ */
+ private static FontControl processFontControl(StructuredFieldReader sfr)
+ throws IOException {
+
+ byte[] fncData = sfr.getNext(FONT_CONTROL_SF);
+
+ int position = 0;
+
+ FontControl fontControl = new AFPFontReader().new FontControl();
+
+ if (fncData[7] == (byte) 0x02) {
+ fontControl.setRelative(true);
+ }
+
+ int dpi = (((fncData[9] & 0xFF) << 8) + (fncData[10] & 0xFF)) / 10;
+
+ fontControl.setDpi(dpi);
+
+ return fontControl;
+
+ }
+
+ /**
+ * Process the font orientation details from using the structured field
+ * reader.
+ *
+ * @param sfr
+ * the structured field reader
+ */
+ private static CharacterSetOrientation[] processFontOrientation(
+ StructuredFieldReader sfr) throws IOException {
+
+ byte[] data = sfr.getNext(FONT_ORIENTATION_SF);
+
+ int position = 0;
+ byte[] fnoData = new byte[26];
+
+ ArrayList orientations = new ArrayList();
+
+ // Read data, ignoring bytes 0 - 2
+ for (int index = 3; index < data.length; index++) {
+ // Build the font orientation record
+ fnoData[position] = data[index];
+ position++;
+
+ if (position == 26) {
+
+ position = 0;
+
+ int orientation = 0;
+
+ switch (fnoData[2]) {
+ case 0x00:
+ orientation = 0;
+ break;
+ case 0x2D:
+ orientation = 90;
+ break;
+ case 0x5A:
+ orientation = 180;
+ break;
+ case (byte) 0x87:
+ orientation = 270;
+ break;
+ default:
+ System.out.println("ERROR: Oriantation");
+ }
+
+ CharacterSetOrientation cso = new CharacterSetOrientation(
+ orientation);
+ orientations.add(cso);
+
+ }
+ }
+
+ return (CharacterSetOrientation[]) orientations
+ .toArray(EMPTY_CSO_ARRAY);
+ }
+
+ /**
+ * Populate the CharacterSetOrientation object in the suplied array with the
+ * font position details using the supplied structured field reader.
+ *
+ * @param sfr
+ * the structured field reader
+ * @param csoArray
+ * the array of CharacterSetOrientation objects
+ */
+ private static void processFontPosition(StructuredFieldReader sfr,
+ CharacterSetOrientation[] csoArray, int dpi) throws IOException {
+
+ byte[] data = sfr.getNext(FONT_POSITION_SF);
+
+ int position = 0;
+ byte[] fpData = new byte[26];
+
+ int csoIndex = 0;
+ int fopFactor = 0;
+
+ switch (dpi) {
+ case 100:
+ fopFactor = FOP_100_DPI_FACTOR;
+ break;
+ case 240:
+ fopFactor = FOP_240_DPI_FACTOR;
+ break;
+ case 300:
+ fopFactor = FOP_300_DPI_FACTOR;
+ break;
+ default:
+ String msg = "Unsupported font resolution of " + dpi + " dpi.";
+ log.error(msg);
+ throw new IOException(msg);
+ }
+
+ // Read data, ignoring bytes 0 - 2
+ for (int index = 3; index < data.length; index++) {
+ if (position < 22) {
+ // Build the font orientation record
+ fpData[position] = data[index];
+ } else if (position == 22) {
+
+ position = 0;
+
+ CharacterSetOrientation cso = csoArray[csoIndex];
+
+ int xHeight = ((fpData[2] & 0xFF) << 8) + (fpData[3] & 0xFF);
+ int capHeight = ((fpData[4] & 0xFF) << 8) + (fpData[5] & 0xFF);
+ int ascHeight = ((fpData[6] & 0xFF) << 8) + (fpData[7] & 0xFF);
+ int dscHeight = ((fpData[8] & 0xFF) << 8) + (fpData[9] & 0xFF);
+
+ dscHeight = dscHeight * -1;
+
+ cso.setXHeight(xHeight * fopFactor);
+ cso.setCapHeight(capHeight * fopFactor);
+ cso.setAscender(ascHeight * fopFactor);
+ cso.setDescender(dscHeight * fopFactor);
+
+ csoIndex++;
+
+ fpData[position] = data[index];
+
+ }
+
+ position++;
+ }
+
+ }
+
+ /**
+ * Process the font index details for the character set orientation.
+ *
+ * @param sfr
+ * the structured field reader
+ * @param cso
+ * the CharacterSetOrientation object to populate
+ * @param codepage
+ * the map of code pages
+ */
+ private static void processFontIndex(StructuredFieldReader sfr,
+ CharacterSetOrientation cso, HashMap codepage, int dpi)
+ throws IOException {
+
+ byte[] data = sfr.getNext(FONT_INDEX_SF);
+
+ int fopFactor = 0;
+
+ switch (dpi) {
+ case 100:
+ fopFactor = FOP_100_DPI_FACTOR;
+ break;
+ case 240:
+ fopFactor = FOP_240_DPI_FACTOR;
+ break;
+ case 300:
+ fopFactor = FOP_300_DPI_FACTOR;
+ break;
+ default:
+ String msg = "Unsupported font resolution of " + dpi + " dpi.";
+ log.error(msg);
+ throw new IOException(msg);
+ }
+
+ int position = 0;
+
+ byte[] gcgid = new byte[8];
+ byte[] fiData = new byte[20];
+
+ int lowest = 255;
+ int highest = 0;
+
+ // Read data, ignoring bytes 0 - 2
+ for (int index = 3; index < data.length; index++) {
+ if (position < 8) {
+ gcgid[position] = (byte) data[index];
+ position++;
+ } else if (position < 27) {
+ fiData[position - 8] = (byte) data[index];
+ position++;
+ } else if (position == 27) {
+
+ fiData[position - 8] = (byte) data[index];
+
+ position = 0;
+
+ String gcgiString = new String(gcgid, AFPConstants.EBCIDIC_ENCODING);
+
+ String idx = (String) codepage.get(gcgiString);
+
+ if (idx != null) {
+
+ int cidx = idx.charAt(0);
+ int width = ((fiData[0] & 0xFF) << 8) + (fiData[1] & 0xFF);
+
+ if (cidx < lowest) {
+ lowest = cidx;
+ }
+
+ if (cidx > highest) {
+ highest = cidx;
+ }
+
+ int a = (width * fopFactor);
+
+ cso.setWidth(cidx, a);
+
+ }
+
+ }
+ }
+
+ cso.setFirstChar(lowest);
+ cso.setLastChar(highest);
+
+ }
+
+ private class FontControl {
+
+ private int _dpi;
+
+ private boolean isRelative = false;
+
+ public int getDpi() {
+ return _dpi;
+ }
+
+ public void setDpi(int i) {
+ _dpi = i;
+ }
+
+ public boolean isRelative() {
+ return isRelative;
+ }
+
+ public void setRelative(boolean b) {
+ isRelative = b;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/fonts/CharacterSet.java b/src/sandbox/org/apache/fop/render/afp/fonts/CharacterSet.java
new file mode 100644
index 000000000..ac39eff85
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/fonts/CharacterSet.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.io.UnsupportedEncodingException;
+import java.util.HashMap;
+
+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;
+
+/**
+ * The IBM Font Object Content Architecture (FOCA) supports presentation
+ * of character shapes by defining their characteristics, which include
+ * font description information for identifying the characters, font metric
+ * information for positioning the characters, and character shape information
+ * for presenting the character images.
+ * <p/>
+ * Presenting a graphic character on a presentation surface requires
+ * information on the rotation and position of character on the physical
+ * or logical page.
+ * <p/>
+ * This class proivdes font metric information for a particular font
+ * as identified by the character set name. This information is obtained
+ * directly from the AFP font files which must be installed in the path
+ * specified in the afp-fonts xml definition file.
+ * <p/>
+ */
+public class CharacterSet {
+
+ /**
+ * Static logging instance
+ */
+ protected static final Log log = LogFactory.getLog(CharacterSet.class.getName());
+
+ /**
+ * The code page to which the character set relates
+ */
+ protected String _codePage;
+
+ /**
+ * The encoding used for the code page
+ */
+ protected String _encoding;
+
+ /**
+ * The character set relating to the font
+ */
+ protected String _name;
+
+ /**
+ * The name of the character set as EBCIDIC bytes
+ */
+ private byte[] _nameBytes;
+
+ /**
+ * The path to the installed fonts
+ */
+ protected String _path;
+
+ /**
+ * Indicator as to whether to metrics have been loaded
+ */
+ private boolean _isMetricsLoaded = false;
+
+ /**
+ * The current orientation (currently only 0 is suppoted by FOP)
+ */
+ private String _currentOrientation = "0";
+
+ /**
+ * The collection of objects for each orientation
+ */
+ private HashMap _characterSetOrientations;
+
+ /**
+ * Constructor for the CharacterSetMetric object, the character set is used
+ * to load the font information from the actual AFP font.
+ * @param codePage the code page identifier
+ * @param encoding the encoding of the font
+ * @param name the character set name
+ * @param path the path to the installed afp fonts
+ */
+ public CharacterSet(
+ String codePage,
+ String encoding,
+ String name,
+ String path) {
+
+ if (name.length() > 8) {
+ String msg = "Character set name must be a maximum of 8 characters " + name;
+ log.error("Constructor:: " + msg);
+ throw new IllegalArgumentException(msg);
+ }
+
+ if (name.length() < 8) {
+ _name = StringUtils.rpad(name, ' ', 8);
+ } else {
+ _name = name;
+ }
+
+ try {
+
+ _nameBytes = name.getBytes(AFPConstants.EBCIDIC_ENCODING);
+
+ } catch (UnsupportedEncodingException usee) {
+
+ _nameBytes = name.getBytes();
+ log.warn(
+ "Constructor:: UnsupportedEncodingException translating the name "
+ + name);
+
+ }
+
+ _codePage = codePage;
+ _encoding = encoding;
+ _path = path;
+ _characterSetOrientations = new HashMap(4);
+
+ }
+
+ /**
+ * Add character set metric information for the different orientations
+ * @param cso the metrics for the orientation
+ */
+ public void addCharacterSetOrientation(CharacterSetOrientation cso) {
+
+ _characterSetOrientations.put(
+ String.valueOf(cso.getOrientation()),
+ cso);
+
+ }
+
+ /**
+ * Ascender height is the distance from the character baseline to the
+ * top of the character box. A negative ascender height signifies that
+ * all of the graphic character is below the character baseline. For
+ * a character rotation other than 0, ascender height loses its
+ * meaning when the character is lying on its side or is upside down
+ * with respect to normal viewing orientation. For the general case,
+ * Ascender Height is the character�s most positive y-axis value.
+ * For bounded character boxes, for a given character having an
+ * ascender, ascender height and baseline offset are equal.
+ * @return the ascender value in millipoints
+ */
+ public int getAscender() {
+ load();
+ return getCharacterSetOrientation().getAscender();
+ }
+
+ /**
+ * Cap height is the average height of the uppercase characters in
+ * a font. This value is specified by the designer of a font and is
+ * usually the height of the uppercase M.
+ * @return the cap height value in millipoints
+ */
+ public int getCapHeight() {
+ load();
+ return getCharacterSetOrientation().getCapHeight();
+ }
+
+ /**
+ * Descender depth is the distance from the character baseline to
+ * the bottom of a character box. A negative descender depth signifies
+ * that all of the graphic character is above the character baseline.
+ * @return the descender value in millipoints
+ */
+ public int getDescender() {
+ load();
+ return getCharacterSetOrientation().getDescender();
+ }
+
+ /**
+ * The first character in the character set
+ * @return the first character
+ */
+ public int getFirstChar() {
+ load();
+ return getCharacterSetOrientation().getFirstChar();
+ }
+
+ /**
+ * The last character in the character set
+ * @return the last character
+ */
+ public int getLastChar() {
+ load();
+ return getCharacterSetOrientation().getLastChar();
+ }
+
+ /**
+ * @return the path where the font resources are installed
+ */
+ public String getPath() {
+ return _path;
+ }
+
+ /**
+ * Get the width (in 1/1000ths of a point size) of all characters
+ * @return the widths of all characters
+ */
+ public int[] getWidths() {
+ load();
+ return getCharacterSetOrientation().getWidths();
+ }
+
+ /**
+ * XHeight refers to the height of the lower case letters above the baseline.
+ * @return the typical height of characters
+ */
+ public int getXHeight() {
+ load();
+ return getCharacterSetOrientation().getXHeight();
+ }
+
+ /**
+ * Get the width (in 1/1000ths of a point size) of the character
+ * identified by the parameter passed.
+ * @param character the character from which the width will be calculated
+ * @return the width of the character
+ */
+ public int width(int character) {
+ load();
+ return getCharacterSetOrientation().width(character);
+ }
+
+ /**
+ * Lazy creation of the character metrics, the afp font file will only
+ * be processed on a method call requiring the metric information.
+ */
+ private void load() {
+
+ if (!_isMetricsLoaded) {
+
+ AFPFontReader.loadCharacterSetMetric(this);
+ _isMetricsLoaded = true;
+
+ }
+
+ }
+
+ /**
+ * Returns the AFP character set identifier
+ * @return String
+ */
+ public String getName() {
+ return _name;
+ }
+
+ /**
+ * Returns the AFP character set identifier
+ * @return byte[]
+ */
+ public byte[] getNameBytes() {
+ return _nameBytes;
+ }
+
+ /**
+ * Returns the AFP code page identifier
+ * @return String
+ */
+ public String getCodePage() {
+ return _codePage;
+ }
+
+ /**
+ * Returns the AFP code page encoding
+ * @return String
+ */
+ public String getEncoding() {
+ return _encoding;
+ }
+
+ /**
+ * Helper method to return the current CharacterSetOrientation, note
+ * that FOP does not yet implement the "reference-orientation"
+ * attribute therefore we always use the orientation zero degrees,
+ * Other orientation information is captured for use by a future
+ * implementation (whenever FOP implement the mechanism). This is also
+ * the case for landscape prints which use an orientation of 270 degrees,
+ * in 99.9% of cases the font metrics will be the same as the 0 degrees
+ * therefore the implementation currely will always use 0 degrees.
+ * @return characterSetOrentation The current orientation metrics.
+ */
+ private CharacterSetOrientation getCharacterSetOrientation() {
+
+ CharacterSetOrientation c =
+ (CharacterSetOrientation) _characterSetOrientations.get(
+ _currentOrientation);
+ return c;
+
+ }
+
+ /**
+ * Map a Unicode character to a code point in the font.
+ * The code tables are already converted to Unicode therefore
+ * we can use the identity mapping.
+ * @param c character to map
+ * @return the mapped character
+ */
+ public char mapChar(char c) {
+ return c;
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/fonts/CharacterSetOrientation.java b/src/sandbox/org/apache/fop/render/afp/fonts/CharacterSetOrientation.java
new file mode 100644
index 000000000..68eb2e413
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/fonts/CharacterSetOrientation.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+
+/**
+ * The IBM Font Object Content Architecture (FOCA) supports presentation
+ * of character shapes by defining their characteristics, which include
+ * Font-Description information for identifying the characters, Font-Metric
+ * information for positioning the characters, and Character-Shape
+ * information for presenting the character images.
+ *
+ * Presenting a graphic character on a presentation surface requires
+ * that you communicate this information clearly to rotate and position
+ * characters correctly on the physical or logical page.
+ *
+ * This class proivdes font metric information for a particular font
+ * as by the orientation.
+ *
+ * This informtaion is obtained directly from the AFP font files which must
+ * be installed in the classpath under in the location specified by the path
+ * attribute in the afp-font.xml file.
+ * <p/>
+ */
+public class CharacterSetOrientation {
+
+ /**
+ * The code page to which the character set relates
+ */
+ private String _codePage;
+
+ /**
+ * The encoding used for the code page
+ */
+ private String _encoding;
+
+ /**
+ * The ascender height for the character set
+ */
+ private int _ascender;
+
+ /**
+ * The descender depth for the character set
+ */
+ private int _descender;
+
+ /**
+ * The height of capital letters
+ */
+ private int _capHeight;
+
+ /**
+ * The characters in the charcater set
+ */
+ private int[] _characters = new int[256];
+
+ /**
+ * The height of lowercase letters
+ */
+ private int _xHeight;
+
+ /**
+ * The first character
+ */
+ private int _firstCharacter;
+
+ /**
+ * The last character
+ */
+ private int _lastCharacter;
+
+
+ /**
+ * The character set orientation
+ */
+ private int _orientation = 0;
+
+ /**
+ * Constructor for the CharacterSetOrientation, the orientation is
+ * expressed as the degrees rotation (i.e 0, 90, 180, 270)
+ * @param orientation the character set orientation
+ */
+ public CharacterSetOrientation(int orientation) {
+
+ _orientation = orientation;
+
+ }
+
+ /**
+ * Ascender height is the distance from the character baseline to the
+ * top of the character box. A negative ascender height signifies that
+ * all of the graphic character is below the character baseline. For
+ * a character rotation other than 0, ascender height loses its
+ * meaning when the character is lying on its side or is upside down
+ * with respect to normal viewing orientation. For the general case,
+ * Ascender Height is the character�s most positive y-axis value.
+ * For bounded character boxes, for a given character having an
+ * ascender, ascender height and baseline offset are equal.
+ * @return the ascender value in millipoints
+ */
+ public int getAscender() {
+ return _ascender;
+ }
+
+ /**
+ * Cap height is the average height of the uppercase characters in
+ * a font. This value is specified by the designer of a font and is
+ * usually the height of the uppercase M.
+ * @return the cap height value in millipoints
+ */
+ public int getCapHeight() {
+ return _capHeight;
+ }
+
+ /**
+ * Descender depth is the distance from the character baseline to
+ * the bottom of a character box. A negative descender depth signifies
+ * that all of the graphic character is above the character baseline.
+ * @return the descender value in millipoints
+ */
+ public int getDescender() {
+ return _descender;
+ }
+
+ /**
+ * The first character in the character set
+ * @return the first character
+ */
+ public int getFirstChar() {
+ return _firstCharacter;
+ }
+
+ /**
+ * The last character in the character set
+ * @return the last character
+ */
+ public int getLastChar() {
+ return _lastCharacter;
+ }
+
+ /**
+ * The orientation for these metrics in the character set
+ * @return the orientation
+ */
+ public int getOrientation() {
+ return _orientation;
+ }
+
+ /**
+ * Get the width (in 1/1000ths of a point size) of all characters
+ * in this character set.
+ * @return the widths of all characters
+ */
+ public int[] getWidths() {
+
+ int arr[] = new int[(getLastChar() - getFirstChar()) + 1];
+ System.arraycopy(_characters, getFirstChar(), arr, 0, (getLastChar() - getFirstChar()) + 1);
+ return arr;
+
+ }
+
+ /**
+ * XHeight refers to the height of the lower case letters above
+ * the baseline.
+ * @return heightX the typical height of characters
+ */
+ public int getXHeight() {
+ return _xHeight;
+ }
+
+ /**
+ * Get the width (in 1/1000ths of a point size) of the character
+ * identified by the parameter passed.
+ * @param character the character to evaluate
+ * @return the widths of the character
+ */
+ public int width(int character) {
+ return _characters[character];
+ }
+
+ /**
+ * Ascender height is the distance from the character baseline to the
+ * top of the character box. A negative ascender height signifies that
+ * all of the graphic character is below the character baseline. For
+ * a character rotation other than 0, ascender height loses its
+ * meaning when the character is lying on its side or is upside down
+ * with respect to normal viewing orientation. For the general case,
+ * Ascender Height is the character�s most positive y-axis value.
+ * For bounded character boxes, for a given character having an
+ * ascender, ascender height and baseline offset are equal.
+ * @param ascender the ascender to set
+ */
+ public void setAscender(int ascender) {
+ _ascender = ascender;
+ }
+
+ /**
+ * Cap height is the average height of the uppercase characters in
+ * a font. This value is specified by the designer of a font and is
+ * usually the height of the uppercase M.
+ * @param capHeight the cap height to set
+ */
+ public void setCapHeight(int capHeight) {
+ _capHeight = capHeight;
+ }
+
+ /**
+ * Descender depth is the distance from the character baseline to
+ * the bottom of a character box. A negative descender depth signifies
+ * that all of the graphic character is above the character baseline.
+ * @param descender the descender value in millipoints
+ */
+ public void setDescender(int descender) {
+ _descender = descender;
+ }
+
+ /**
+ * The first character in the character set
+ * @param firstCharacter the first character
+ */
+ public void setFirstChar(int firstCharacter) {
+ _firstCharacter = firstCharacter;
+ }
+
+ /**
+ * The last character in the character set
+ * @param lastCharacter the last character
+ */
+ public void setLastChar(int lastCharacter) {
+ _lastCharacter = lastCharacter;
+ }
+
+ /**
+ * Set the width (in 1/1000ths of a point size) of the character
+ * identified by the parameter passed.
+ * @param character the character for which the width is being set
+ * @param width the widths of the character
+ */
+ public void setWidth(int character, int width) {
+
+ if (character >= _characters.length) {
+ // Increase the size of the array if necessary
+ int arr[] = new int[(character - _firstCharacter) + 1];
+ System.arraycopy(_characters, 0, arr, 0, _characters.length);
+ _characters = arr;
+ }
+ _characters[character] = width;
+
+ }
+
+ /**
+ * XHeight refers to the height of the lower case letters above
+ * the baseline.
+ * @param xHeight the typical height of characters
+ */
+ public void setXHeight(int xHeight) {
+ _xHeight = xHeight;
+ }
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/fonts/FopCharacterSet.java b/src/sandbox/org/apache/fop/render/afp/fonts/FopCharacterSet.java
new file mode 100644
index 000000000..635cef025
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/fonts/FopCharacterSet.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 org.apache.fop.fonts.Typeface;
+
+/**
+ * A Character set for a normal FOP font<p/>
+ */
+public class FopCharacterSet extends CharacterSet {
+
+ /** The character set for this font */
+ private Typeface _characterSet = null;
+ private int _size = 0;
+
+ /**
+ * Constructor for the CharacterSetMetric object, the character set is used
+ * to load the font information from the actual AFP font.
+ * @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 Typeface the fop character set
+ */
+ public FopCharacterSet(
+ String codePage,
+ String encoding,
+ String name,
+ int size,
+ Typeface characterSet) {
+ super(codePage, encoding, name, null);
+ _characterSet = characterSet;
+ _size = size * 1000;
+ }
+
+ /**
+ * Ascender height is the distance from the character baseline to the
+ * top of the character box. A negative ascender height signifies that
+ * all of the graphic character is below the character baseline. For
+ * a character rotation other than 0, ascender height loses its
+ * meaning when the character is lying on its side or is upside down
+ * with respect to normal viewing orientation. For the general case,
+ * Ascender Height is the character�s most positive y-axis value.
+ * For bounded character boxes, for a given character having an
+ * ascender, ascender height and baseline offset are equal.
+ * @return the ascender value in millipoints
+ */
+ public int getAscender() {
+ return _characterSet.getAscender(_size);
+ }
+
+ /**
+ * Cap height is the average height of the uppercase characters in
+ * a font. This value is specified by the designer of a font and is
+ * usually the height of the uppercase M.
+ * @return the cap height value in millipoints
+ */
+ public int getCapHeight() {
+ return _characterSet.getCapHeight(_size);
+ }
+
+ /**
+ * Descender depth is the distance from the character baseline to
+ * the bottom of a character box. A negative descender depth signifies
+ * that all of the graphic character is above the character baseline.
+ * @return the descender value in millipoints
+ */
+ public int getDescender() {
+ return _characterSet.getDescender(_size);
+ }
+
+ /**
+ * The first character in the character set
+ * @return the first character
+ */
+ public int getFirstChar() {
+ return 0;
+ }
+
+ /**
+ * The last character in the character set
+ * @return the last character
+ */
+ public int getLastChar() {
+ return 0;
+ }
+
+ /**
+ * Get the width (in 1/1000ths of a point size) of all characters
+ * @return the widths of all characters
+ */
+ public int[] getWidths() {
+ return _characterSet.getWidths();
+ }
+
+ /**
+ * XHeight refers to the height of the lower case letters above the baseline.
+ * @return the typical height of characters
+ */
+ public int getXHeight() {
+ return _characterSet.getXHeight(_size);
+ }
+
+ /**
+ * Get the width (in 1/1000ths of a point size) of the character
+ * identified by the parameter passed.
+ * @param character the character from which the width will be calculated
+ * @return the width of the character
+ */
+ public int width(int character) {
+ return _characterSet.getWidth(character, _size);
+ }
+
+ /**
+ * Map a Unicode character to a code point in the font.
+ * @param c character to map
+ * @return the mapped character
+ */
+ public char mapChar(char c) {
+ return _characterSet.mapChar(c);
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/fonts/OutlineFont.java b/src/sandbox/org/apache/fop/render/afp/fonts/OutlineFont.java
new file mode 100644
index 000000000..00757f4ba
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/fonts/OutlineFont.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+
+/**
+ * A font defined as a set of lines and curves as opposed to a bitmap font. An
+ * outline font can be scaled to any size and otherwise transformed more easily
+ * than a bitmap font, and with more attractive results. <p/>
+ *
+ */
+public class OutlineFont extends AFPFont {
+
+ /** The character set for this font */
+ private CharacterSet _characterSet = null;
+
+ /**
+ * Constructor for an outline font.
+ *
+ * @param name
+ * the name of the font
+ * @param characterSet
+ * the chracter set
+ */
+ public OutlineFont(String name, CharacterSet characterSet) {
+ super(name);
+ _characterSet = characterSet;
+ }
+
+ /**
+ * Get the character set metrics.
+ *
+ * @return the character set
+ */
+ public CharacterSet getCharacterSet() {
+
+ return _characterSet;
+
+ }
+
+ /**
+ * Get the character set metrics.
+ * @param size ignored
+ * @return the character set
+ */
+ public CharacterSet getCharacterSet(int size) {
+
+ return _characterSet;
+
+ }
+
+ /**
+ * Get the first character in this font.
+ */
+ public int getFirstChar() {
+
+ return _characterSet.getFirstChar();
+
+ }
+
+ /**
+ * Get the last character in this font.
+ */
+ public int getLastChar() {
+
+ return _characterSet.getLastChar();
+
+ }
+
+ /**
+ * The ascender is the part of a lowercase letter that extends above the
+ * "x-height" (the height of the letter "x"), such as "d", "t", or "h". Also
+ * used to denote the part of the letter extending above the x-height.
+ *
+ * @param size
+ * the point size
+ */
+ public int getAscender(int size) {
+
+ return _characterSet.getAscender() / 1000 * size;
+
+ }
+
+ /**
+ * Obtains the height of capital letters for the specified point size.
+ *
+ * @param size
+ * the point size
+ */
+ public int getCapHeight(int size) {
+
+ return _characterSet.getCapHeight() / 1000 * size;
+
+ }
+
+ /**
+ * The descender is the part of a lowercase letter that extends below the
+ * base line, such as "g", "j", or "p". Also used to denote the part of the
+ * letter extending below the base line.
+ *
+ * @param size
+ * the point size
+ */
+ public int getDescender(int size) {
+
+ return _characterSet.getDescender() / 1000 * size;
+
+ }
+
+ /**
+ * The "x-height" (the height of the letter "x").
+ *
+ * @param size
+ * the point size
+ */
+ public int getXHeight(int size) {
+
+ return _characterSet.getXHeight() / 1000 * size;
+
+ }
+
+ /**
+ * Obtain the width of the character for the specified point size.
+ */
+ public int getWidth(int character, int size) {
+
+ return _characterSet.width(character) / 1000 * size;
+
+ }
+
+ /**
+ * Get the getWidth (in 1/1000ths of a point size) of all characters in this
+ * character set.
+ *
+ * @param size
+ * the point size
+ * @return the widths of all characters
+ */
+ public int[] getWidths(int size) {
+
+ int[] widths = _characterSet.getWidths();
+ for (int i = 0 ; i < widths.length; i++) {
+ widths[i] = widths[i] / 1000 * size;
+ }
+ return widths;
+
+ }
+
+ /**
+ * Get the getWidth (in 1/1000ths of a point size) of all characters in this
+ * character set.
+ *
+ * @return the widths of all characters
+ */
+ public int[] getWidths() {
+
+ return getWidths(1000);
+
+ }
+
+ /**
+ * Map a Unicode character to a code point in the font.
+ * @param c character to map
+ * @return the mapped character
+ */
+ public char mapChar(char c) {
+ return _characterSet.mapChar(c);
+ }
+
+ /**
+ * Get the encoding of the font.
+ * @return the encoding
+ */
+ public String getEncoding() {
+ return _characterSet.getEncoding();
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/fonts/RasterFont.java b/src/sandbox/org/apache/fop/render/afp/fonts/RasterFont.java
new file mode 100644
index 000000000..cec80c59c
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/fonts/RasterFont.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.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.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
+ * of font, the font metrics information is held in character set files (one for
+ * each size and style). <p/>
+ *
+ */
+public class RasterFont extends AFPFont {
+
+ /** Static logging instance */
+ protected static final Log log = LogFactory.getLog("org.apache.fop.render.afp.fonts");
+
+ private HashMap _characterSets = new HashMap();
+
+ private CharacterSet _characterSet = null;
+
+ /**
+ * Constructor for the raster font requires the name, weight and style
+ * attribute to be available as this forms the key to the font.
+ *
+ * @param name
+ * the name of the font
+ */
+ public RasterFont(String name) {
+ super(name);
+ }
+
+ public void addCharacterSet(int size, CharacterSet characterSet) {
+
+ _characterSets.put(String.valueOf(size), characterSet);
+
+ _characterSet = characterSet;
+
+ }
+
+ /**
+ * Get the character set metrics for the specified point size.
+ *
+ * @param size the point size
+ * @return the character set metrics
+ */
+ public CharacterSet getCharacterSet(int size) {
+
+ String pointsize = String.valueOf(size / 1000);
+ CharacterSet csm = (CharacterSet) _characterSets.get(pointsize);
+ if (csm == null) {
+ csm = (CharacterSet) _characterSets.get(size + "mpt");
+ }
+ if (csm == null) {
+ // Get char set with nearest font size
+ int distance = Integer.MAX_VALUE;
+ for (Iterator it = _characterSets.entrySet().iterator(); it.hasNext(); ) {
+ Map.Entry me = (Map.Entry)it.next();
+ String key = (String)me.getKey();
+ if (!key.endsWith("mpt")) {
+ int mpt = Integer.parseInt(key) * 1000;
+ if (Math.abs(size - mpt) < distance) {
+ distance = Math.abs(size - mpt);
+ pointsize = (String)me.getKey();
+ csm = (CharacterSet)me.getValue();
+ }
+ }
+ }
+ if (csm != null) {
+ _characterSets.put(size + "mpt", csm);
+ String msg = "No " + (size / 1000) + "pt font " + _name
+ + " found, substituted with " + pointsize + "pt font";
+ log.warn(msg);
+ }
+ }
+ if (csm == null) {
+ String msg = "No font found for font " + _name
+ + " with point size " + pointsize;
+ log.error(msg);
+ throw new FontRuntimeException(msg);
+ }
+ return csm;
+
+ }
+
+ /**
+ * Get the first character in this font.
+ */
+ public int getFirstChar() {
+
+ Iterator i = _characterSets.values().iterator();
+ if (i.hasNext()) {
+ CharacterSet csm = (CharacterSet) i.next();
+ return csm.getFirstChar();
+ } else {
+ String msg = "getFirstChar() - No character set found for font:" + _name;
+ log.error(msg);
+ throw new FontRuntimeException(msg);
+ }
+
+ }
+
+ /**
+ * Get the last character in this font.
+ */
+ public int getLastChar() {
+
+ Iterator i = _characterSets.values().iterator();
+ if (i.hasNext()) {
+ CharacterSet csm = (CharacterSet) i.next();
+ return csm.getLastChar();
+ } else {
+ String msg = "getLastChar() - No character set found for font:" + _name;
+ log.error(msg);
+ throw new FontRuntimeException(msg);
+ }
+
+ }
+
+ /**
+ * The ascender is the part of a lowercase letter that extends above the
+ * "x-height" (the height of the letter "x"), such as "d", "t", or "h". Also
+ * used to denote the part of the letter extending above the x-height.
+ *
+ * @param size the point size
+ */
+ public int getAscender(int size) {
+
+ return getCharacterSet(size).getAscender();
+
+ }
+
+ /**
+ * Obtains the height of capital letters for the specified point size.
+ *
+ * @param size the point size
+ */
+ public int getCapHeight(int size) {
+
+ return getCharacterSet(size).getCapHeight();
+
+ }
+
+ /**
+ * The descender is the part of a lowercase letter that extends below the
+ * base line, such as "g", "j", or "p". Also used to denote the part of the
+ * letter extending below the base line.
+ *
+ * @param size the point size
+ */
+ public int getDescender(int size) {
+
+ return getCharacterSet(size).getDescender();
+
+ }
+
+ /**
+ * The "x-height" (the height of the letter "x").
+ *
+ * @param size the point size
+ */
+ public int getXHeight(int size) {
+
+ return getCharacterSet(size).getXHeight();
+
+ }
+
+ /**
+ * Obtain the width of the character for the specified point size.
+ */
+ public int getWidth(int character, int size) {
+
+ return getCharacterSet(size).width(character);
+
+ }
+
+ /**
+ * Get the getWidth (in 1/1000ths of a point size) of all characters in this
+ * character set.
+ *
+ * @param size
+ * the point size
+ * @return the widths of all characters
+ */
+ public int[] getWidths(int size) {
+
+ return getCharacterSet(size).getWidths();
+
+ }
+
+ /**
+ * Get the getWidth (in 1/1000ths of a point size) of all characters in this
+ * character set.
+ *
+ * @return the widths of all characters
+ */
+ public int[] getWidths() {
+
+ return getWidths(1000);
+
+ }
+
+ /**
+ * Map a Unicode character to a code point in the font.
+ * @param c character to map
+ * @return the mapped character
+ */
+ public char mapChar(char c) {
+ return _characterSet.mapChar(c);
+ }
+
+ /**
+ * Get the encoding of the font.
+ * @return the encoding
+ */
+ public String getEncoding() {
+ return _characterSet.getEncoding();
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/AFPConstants.java b/src/sandbox/org/apache/fop/render/afp/modca/AFPConstants.java
new file mode 100644
index 000000000..9c23e3fbd
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/AFPConstants.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+/**
+ * Constants used by the AFP renderer.
+ *
+ */
+public interface AFPConstants {
+
+ /**
+ * The encoding to use to convert to EBCIDIC
+ */
+ public String EBCIDIC_ENCODING = "Cp1146";
+
+ /**
+ * The encoding to use to convert to ASCII
+ */
+ public String ASCII_ENCODING = "Cp1252";
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/AFPDataStream.java b/src/sandbox/org/apache/fop/render/afp/modca/AFPDataStream.java
new file mode 100644
index 000000000..32fc29831
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/AFPDataStream.java
@@ -0,0 +1,650 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fop.render.afp.AFPFontColor;
+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 final Log log = LogFactory.getLog("org.apache.fop.render.afp.modca");
+
+ /**
+ * Boolean completion indicator
+ */
+ private boolean _complete = false;
+
+ /**
+ * The application producing the AFP document
+ */
+ 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
+ */
+ 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.
+ */
+ public void startDocument(OutputStream outputStream) {
+
+ if (_document != null) {
+ String msg = "Invalid state - document already started.";
+ log.warn("startDocument():: " + msg);
+ throw new IllegalStateException(msg);
+ }
+
+ _document = new Document();
+ _outputStream = outputStream;
+
+ }
+
+ /**
+ * 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.
+ */
+ 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(_outputStream);
+ _outputStream.flush();
+
+ _complete = true;
+
+ _document = null;
+
+ _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
+ */
+ public void startPage(int pageWidth, int pageHeight, int pageRotation) {
+
+ String pageName = "PGN"
+ + StringUtils.lpad(String.valueOf(_pageCount++), '0', 5);
+
+ _currentPageObject = new PageObject(pageName, pageWidth, pageHeight, pageRotation);
+ _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 overlayRotation
+ * the rotation of the overlay
+ */
+ public void startOverlay(int overlayX, int overlayY, int overlayWidth, int overlayHeight, int overlayRotation) {
+
+ String overlayName = "OVL"
+ + StringUtils.lpad(String.valueOf(_ovlCount++), '0', 5);
+
+ _currentOverlay = new Overlay(overlayName, overlayWidth, overlayHeight, 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.
+ */
+ 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.
+ */
+ public void restorePage(PageObject pageObject) {
+
+ _currentPageObject = pageObject;
+ _currentPage = pageObject;
+
+ }
+
+ /**
+ * Helper method to mark the end of the current page.
+ */
+ public void endPage()
+ throws IOException {
+
+ _currentPageObject.endPage();
+ if (_currentPageGroup != null) {
+ _currentPageGroup.addPage(_currentPageObject);
+ } else {
+ _document.addPage(_currentPageObject);
+ _document.writeDataStream(_outputStream);
+ }
+
+ _currentPageObject = null;
+ _currentPage = null;
+
+ }
+
+ /**
+ * Sets the offsets to be used for element positioning
+ *
+ * @param xOffset
+ * the offset in the x direction
+ * @param yOffset
+ * the offset in the y direction
+ * @param rotation
+ * the rotation
+ */
+ public void setOffsets(int xOffset, int yOffset, int rotation) {
+ _xOffset = xOffset;
+ _yOffset = yOffset;
+ _rotation = rotation;
+ }
+
+ /**
+ * 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, AFPFontColor 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
+ */
+ public ImageObject getImageObject(int x, int y, int w, int h) {
+
+ int xOrigin;
+ int yOrigin;
+ int width;
+ int height;
+ switch (_rotation) {
+ case 90:
+ xOrigin = _currentPage.getWidth() - y - _yOffset;
+ yOrigin = x + _xOffset;
+ width = h;
+ height = w;
+ break;
+ case 180:
+ xOrigin = _currentPage.getWidth() - x - _xOffset;
+ yOrigin = _currentPage.getHeight() - y - _yOffset;
+ width = w;
+ height = h;
+ break;
+ case 270:
+ xOrigin = y + _yOffset;
+ yOrigin = _currentPage.getHeight() - x - _xOffset;
+ width = h;
+ height = w;
+ break;
+ default:
+ xOrigin = x + _xOffset;
+ yOrigin = y + _yOffset;
+ width = w;
+ height = h;
+ break;
+ }
+ ImageObject io = _currentPage.getImageObject();
+ io.setImageViewport(xOrigin, yOrigin, width, height, _rotation);
+ 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, AFPFontColor col) {
+
+ _currentPage.createLine(x1 + _xOffset, y1 + _yOffset, x2 + _xOffset, y2 + _yOffset, thickness, _rotation, col);
+
+ }
+
+ /**
+ * Sets the application producing the AFP.
+ *
+ * @param producer
+ * the application producing the AFP datastream
+ */
+ public void setProducer(String producer) {
+ _producer = producer;
+ }
+
+ /**
+ * 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);
+ }
+
+ }
+
+ /**
+ * 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.
+ *
+ * @param name
+ * the name of the page group
+ */
+ 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.
+ */
+ 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 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 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");
+ }
+
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/AbstractAFPObject.java b/src/sandbox/org/apache/fop/render/afp/modca/AbstractAFPObject.java
new file mode 100644
index 000000000..c7905ea76
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/AbstractAFPObject.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ * @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/sandbox/org/apache/fop/render/afp/modca/AbstractPageObject.java b/src/sandbox/org/apache/fop/render/afp/modca/AbstractPageObject.java
new file mode 100644
index 000000000..5056e9b21
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/AbstractPageObject.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.fop.render.afp.AFPFontColor;
+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.
+ */
+ public AbstractPageObject(String name, int width, int height, int rotation) {
+
+ super(name);
+
+ _name = name;
+
+ _rotation = rotation;
+ _width = width;
+ _height = height;
+
+ /**
+ * Every page object must have an ActiveEnvironmentGroup
+ */
+ _activeEnvironmentGroup = new ActiveEnvironmentGroup(_width, _height);
+
+ 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;
+ }
+ }
+
+ /**
+ * 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 rotation
+ * the rotation of the line
+ * @param col
+ * The text color.
+ */
+ public void createLine(int x1, int y1, int x2, int y2, int thickness, int rotation, AFPFontColor col) {
+
+ if (_presentationTextObject == null) {
+ _presentationTextObject = new PresentationTextObject();
+ _objects.add(_presentationTextObject);
+ }
+ _presentationTextObject.createLineData(x1, y1, x2, y2, thickness, rotation, 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 rotation
+ * 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 rotation, AFPFontColor col, int vsci, int ica, byte[] data) {
+
+ if (_presentationTextObject == null) {
+ _presentationTextObject = new PresentationTextObject();
+ _objects.add(_presentationTextObject);
+ }
+ _presentationTextObject.createTextData(fontNumber, x, y, rotation, 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() {
+
+ _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 width = 0;
+ int height = 0;
+
+ switch (_rotation) {
+ case 90:
+ xCoord = _width - y - h;
+ yCoord = x;
+ width = h;
+ height = w;
+ break;
+ case 180:
+ xCoord = _width - x - w;
+ yCoord = _height - y - h;
+ width = w;
+ height = h;
+ break;
+ case 270:
+ xCoord = y;
+ yCoord = _height - x - w;
+ width = h;
+ height = w;
+ break;
+ default:
+ xCoord = x;
+ yCoord = y;
+ width = w;
+ height = 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(width);
+ icp.setYFillSize(height);
+ icp.setXSize(64);
+ icp.setYSize(8);
+
+ //defing 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.
+ */
+ 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 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
+ */
+ public boolean isComplete() {
+ return _complete;
+ }
+
+ /**
+ * Returns the height of the page
+ */
+ public int getHeight() {
+ return _height;
+ }
+
+ /**
+ * Returns the width of the page
+ */
+ public int getWidth() {
+ return _width;
+ }
+
+ /**
+ * Returns the rotation of the page
+ */
+ public int getRotation() {
+ return _rotation;
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/ActiveEnvironmentGroup.java b/src/sandbox/org/apache/fop/render/afp/modca/ActiveEnvironmentGroup.java
new file mode 100644
index 000000000..3fb7ac224
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/ActiveEnvironmentGroup.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+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
+ */
+ public ActiveEnvironmentGroup(int width, int height) {
+
+ this(DEFAULT_NAME, width, height);
+
+ }
+
+ /**
+ * 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
+ */
+ public ActiveEnvironmentGroup(String name, int width, int height) {
+
+ super(name);
+
+ // Create PageDescriptor
+ _pageDescriptor = new PageDescriptor(width, height);
+
+ // Create ObjectAreaDescriptor
+ _objectAreaDescriptor = new ObjectAreaDescriptor(width, height);
+
+ // Create PresentationTextDataDescriptor
+ _presentationTextDataDescriptor =
+ new PresentationTextDescriptor(width, height);
+
+ }
+
+ /**
+ * 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
+ */
+ 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/sandbox/org/apache/fop/render/afp/modca/Document.java b/src/sandbox/org/apache/fop/render/afp/modca/Document.java
new file mode 100644
index 000000000..10e5a4b31
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/Document.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+
+/**
+ * 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 final static String DEFAULT_NAME = "DOC00001";
+
+ /**
+ * A list of the objects in the document
+ */
+ private ArrayList _objects = new 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
+ */
+ 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
+ */
+ 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/sandbox/org/apache/fop/render/afp/modca/EndPageGroup.java b/src/sandbox/org/apache/fop/render/afp/modca/EndPageGroup.java
new file mode 100644
index 000000000..afa720d71
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/EndPageGroup.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+/**
+ * The End Named Page Group (ENG) structured field terminates a page group that was
+ * initiated by a Begin Named Page Group structured field.
+ *
+ * Note :This object will be used to represent an ENG
+ * structured field. It is necessary as you can't end
+ * a PageGroup because you don't know where the group
+ * will end (as this is controlled by the tags in the FO).
+ * <p>
+ *
+ */
+public class EndPageGroup extends AbstractNamedAFPObject {
+
+ public EndPageGroup(String groupId) {
+
+ super(groupId);
+
+ log.debug("A ENG is being created for group: " + groupId);
+
+ }
+
+ /**
+ * Accessor method to write the AFP datastream for the End Page Group.
+ * @param os The stream to write to
+ * @throws java.io.IOException
+ */
+ public void writeDataStream(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);
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/IMImageObject.java b/src/sandbox/org/apache/fop/render/afp/modca/IMImageObject.java
new file mode 100644
index 000000000..aa510da6b
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/IMImageObject.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 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
+ * either simple or complex. A simple image is composed of one or more Image
+ * Raster Data (IRD) structured fields that define the raster pattern for the
+ * entire image. A complex image is divided into regions called image cells.
+ * Each image cell is composed of one or more IRD structured fields that define
+ * the raster pattern for the image cell, and one Image Cell Position (ICP)
+ * structured field that defines the position of the image cell relative to
+ * the origin of the entire image. Each ICP also specifies the size of the
+ * image cell and a fill rectangle into which the cell is replicated.
+ * <p/>
+ */
+public class IMImageObject extends AbstractNamedAFPObject {
+
+ /**
+ * The image output control
+ */
+ private ImageOutputControl _imageOutputControl = null;
+
+ /**
+ * The image input descriptor
+ */
+ private ImageInputDescriptor _imageInputDescriptor = null;
+
+ /**
+ * The image cell position
+ */
+ private ImageCellPosition _imageCellPosition = null;
+
+ /**
+ * The image rastor data
+ */
+ private ImageRasterData _imageRastorData = 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 IMImageObject(String name) {
+
+ super(name);
+
+ }
+
+ /**
+ * Sets the ImageOutputControl.
+ * @param imageOutputControl The imageOutputControl to set
+ */
+ public void setImageOutputControl(ImageOutputControl imageOutputControl) {
+ _imageOutputControl = imageOutputControl;
+ }
+
+ /**
+ * Sets the ImageCellPosition.
+ * @param imageCellPosition The imageCellPosition to set
+ */
+ public void setImageCellPosition(ImageCellPosition imageCellPosition) {
+ _imageCellPosition = imageCellPosition;
+ }
+
+ /**
+ * Sets the ImageInputDescriptor.
+ * @param imageInputDescriptor The imageInputDescriptor to set
+ */
+ public void setImageInputDescriptor(ImageInputDescriptor imageInputDescriptor) {
+ _imageInputDescriptor = imageInputDescriptor;
+ }
+
+ /**
+ * Sets the ImageRastorData.
+ * @param imageRastorData The imageRastorData to set
+ */
+ public void setImageRasterData(ImageRasterData imageRastorData) {
+ _imageRastorData = imageRastorData;
+ }
+
+ /**
+ * Accessor method to write the AFP datastream for the IM Image Objetc
+ * @param os The stream to write to
+ * @throws java.io.IOException
+ */
+ public void writeDataStream(OutputStream os)
+ throws IOException {
+
+ writeStart(os);
+
+ if (_imageOutputControl != null) {
+ _imageOutputControl.writeDataStream(os);
+ }
+
+ if (_imageInputDescriptor != null) {
+ _imageInputDescriptor.writeDataStream(os);
+ }
+
+ if (_imageCellPosition != null) {
+ _imageCellPosition.writeDataStream(os);
+ }
+
+ if (_imageRastorData != null) {
+ _imageRastorData.writeDataStream(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 {
+
+ 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];
+
+ }
+
+ 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 {
+
+ 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];
+
+ }
+
+ os.write(data);
+
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/ImageCellPosition.java b/src/sandbox/org/apache/fop/render/afp/modca/ImageCellPosition.java
new file mode 100644
index 000000000..aa97e585c
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/ImageCellPosition.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 IM Image Cell Position structured field specifies the placement,
+ * size, and replication of IM image cells.
+ */
+public class ImageCellPosition extends AbstractAFPObject {
+
+ /**
+ * Offset of image cell in X direction
+ */
+ private int _XcoSet = 0;
+
+ /**
+ * Offset of image cell in Y direction
+ */
+ private int _YcoSet = 0;
+
+ /**
+ * Size of image cell in X direction
+ */
+ private byte[] _XcSize = new byte[] { (byte)0xFF, (byte)0xFF };
+
+ /**
+ * Size of image cell in Y direction
+ */
+ private byte[] _YcSize = 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 Y direction
+ */
+ private byte[] _YFillSize = new byte[] { (byte)0xFF, (byte)0xFF };
+
+ /**
+ * Constructor for the ImageCellPosition
+ * @param x The offset of image cell in X direction
+ * @param y The offset of image cell in Y direction
+ */
+ public ImageCellPosition(int x, int y) {
+
+ _XcoSet = x;
+ _YcoSet = y;
+
+ }
+
+ /**
+ * Accessor method to write the AFP datastream for the Image Cell Position
+ * @param os The stream to write to
+ * @throws java.io.IOException
+ */
+ public void writeDataStream(OutputStream os)
+ throws IOException {
+
+ byte[] data = new byte[21];
+
+ data[0] = 0x5A;
+
+ data[1] = 0x00;
+ 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.
+ */
+ byte[] x1 = BinaryUtils.convert(_XcoSet, 2);
+ data[9] = x1[0];
+ data[10] = x1[1];
+
+ /**
+ * Specifies the offset along the Yp direction, in image points,
+ * of this image cell from the IM image object area origin.
+ */
+ byte[] x2 = BinaryUtils.convert(_YcoSet, 2);
+ data[11] = x2[0];
+ data[12] = x2[1];
+
+ data[13] = _XcSize[0];
+ data[14] = _XcSize[1];
+
+ data[15] = _YcSize[0];
+ data[16] = _YcSize[1];
+
+ data[17] = _XFillSize[0];
+ data[18] = _XFillSize[1];
+
+ data[19] = _YFillSize[0];
+ data[20] = _YFillSize[1];
+
+ os.write(data);
+
+ }
+
+ /**
+ * Specifies the extent in the X direction, in image points,
+ * 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) {
+
+ byte[] x = BinaryUtils.convert(xcSize, 2);
+ _XcSize[0] = x[0];
+ _XcSize[1] = x[1];
+
+ }
+
+ /**
+ * Specifies the extent of the fill rectangle in the X direction,
+ * in image points. This value can be smaller than, equal to, or
+ * larger than the image cell extent in the X direction (XCSize).
+ * A value of X'FFFF' indicates that the image cell X-extent should
+ * 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 xFillSize The size to set.
+ */
+ public void setXFillSize(int xFillSize) {
+
+ byte[] x = BinaryUtils.convert(xFillSize, 2);
+ _XFillSize[0] = x[0];
+ _XFillSize[1] = x[1];
+
+ }
+
+ /**
+ * Specifies the extent in the Y direction, in image points,
+ * 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 ycSize The size to set.
+ */
+ public void setYSize(int ycSize) {
+
+ byte[] x = BinaryUtils.convert(ycSize, 2);
+ _YcSize[0] = x[0];
+ _YcSize[1] = x[1];
+
+ }
+
+ /**
+ * Specifies the extent of the fill rectangle in the Y direction,
+ * in image points. This value can be smaller than, equal to, or
+ * larger than the image cell extent in the Y direction (YCSize).
+ * A value of X'FFFF' indicates that the image cell Y-extent should
+ * 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 yFillSize The size to set.
+ */
+ public void setYFillSize(int yFillSize) {
+
+ byte[] x = BinaryUtils.convert(yFillSize, 2);
+ _YFillSize[0] = x[0];
+ _YFillSize[1] = x[1];
+
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/ImageContent.java b/src/sandbox/org/apache/fop/render/afp/modca/ImageContent.java
new file mode 100644
index 000000000..9479f4742
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/ImageContent.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 size 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/sandbox/org/apache/fop/render/afp/modca/ImageDataDescriptor.java b/src/sandbox/org/apache/fop/render/afp/modca/ImageDataDescriptor.java
new file mode 100644
index 000000000..25f06c717
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/ImageDataDescriptor.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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/sandbox/org/apache/fop/render/afp/modca/ImageInputDescriptor.java b/src/sandbox/org/apache/fop/render/afp/modca/ImageInputDescriptor.java
new file mode 100644
index 000000000..eeef6b712
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/ImageInputDescriptor.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 IM Image Input Descriptor structured field contains the
+ * descriptor data for an IM image data object. This data specifies
+ * the resolution, size, and color of the IM image.
+ */
+public class ImageInputDescriptor extends AbstractAFPObject {
+
+ /**
+ * 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
+ */
+ public void writeDataStream(OutputStream os)
+ throws IOException {
+
+ byte[] data = new byte[45];
+
+ data[0] = 0x5A;
+ data[1] = 0x00;
+ 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;
+ data[10] = 0x00;
+ data[11] = 0x09;
+ data[12] = 0x60;
+ data[13] = 0x09;
+ data[14] = 0x60;
+ data[15] = 0x00;
+ data[16] = 0x00;
+ data[17] = 0x00;
+ data[18] = 0x00;
+ data[19] = 0x00;
+ data[20] = 0x00;
+
+ // X Base (Fixed x00)
+ data[21] = 0x00;
+ // Y Base (Fixed x00)
+ data[22] = 0x00;
+
+ byte[] imagepoints = BinaryUtils.convert(_resolution * 10, 2);
+
+ /**
+ * Specifies the number of image points per unit base for the X axis
+ * of the image. This value is ten times the resolution of the image
+ * in the X direction.
+ */
+ data[23] = imagepoints[0];
+ data[24] = imagepoints[1];
+
+ /**
+ * Specifies the number of image points per unit base for the Y axis
+ * of the image. This value is ten times the resolution of the image
+ * in the Y direction.
+ */
+ data[25] = imagepoints[0];
+ data[26] = imagepoints[1];
+
+ /**
+ * Specifies the extent in the X direction, in image points, of an
+ * non-celled (simple) image.
+ */
+ data[27] = 0x00;
+ data[28] = 0x01;
+
+ /**
+ * Specifies the extent in the Y direction, in image points, of an
+ * non-celled (simple) image.
+ */
+ data[29] = 0x00;
+ data[30] = 0x01;
+
+ // Constant Data
+ data[31] = 0x00;
+ data[32] = 0x00;
+ data[33] = 0x00;
+ data[34] = 0x00;
+ data[35] = 0x2D;
+ data[36] = 0x00;
+
+ // Default size of image cell in X direction
+ data[37] = 0x00;
+ data[38] = 0x01;
+
+ // Default size of image cell in Y direction
+ data[39] = 0x00;
+ data[40] = 0x01;
+
+ // Constant Data
+ data[41] = 0x00;
+ data[42] = 0x01;
+
+ // Image Color
+ data[43] = (byte)0xFF;
+ 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) {
+ _resolution = resolution;
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/ImageObject.java b/src/sandbox/org/apache/fop/render/afp/modca/ImageObject.java
new file mode 100644
index 000000000..8e4e4c386
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/ImageObject.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 java.io.UnsupportedEncodingException;
+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
+ */
+ public void setImageViewport(int x, int y, int w, int h, int r) {
+ if (_objectEnvironmentGroup == null) {
+ _objectEnvironmentGroup = new ObjectEnvironmentGroup();
+ }
+ _objectEnvironmentGroup.setObjectArea(x, y, w, h, r);
+ }
+
+ /**
+ * 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 size 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) {
+ _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
+ */
+ 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/sandbox/org/apache/fop/render/afp/modca/ImageOutputControl.java b/src/sandbox/org/apache/fop/render/afp/modca/ImageOutputControl.java
new file mode 100644
index 000000000..8a2aaaede
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/ImageOutputControl.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 IM Image Output Control structured field specifies the position and
+ * orientation of the IM image object area and the mapping of the image points
+ * to presentation device pels.
+ *
+ */
+public class ImageOutputControl extends AbstractAFPObject {
+
+ /**
+ * The orientation of the image
+ */
+ private int _orientation = 0;
+
+ /**
+ * Specifies the offset, along the X-axis, of the IM image object area
+ * origin to the origin of the including page
+ */
+ private int _Xcoordinate = 0;
+
+ /**
+ * Specifies the offset, along the Y-axis, of the IM image object area
+ * origin to the origin of the including page
+ */
+ private int _Ycoordinate = 0;
+
+ /**
+ * Map an image point to a single presentation device pel
+ */
+ private boolean _singlepoint = true;
+
+ /**
+ * Constructor for the ImageOutputControl The x parameter specifies the
+ * offset, along the X-axis, of the IM image object area origin to the
+ * origin of the including page and the y parameter specifies the offset
+ * along the Y-axis. The offset is specified in image points and is resolved
+ * using the units of measure specified for the image in the IID structured
+ * field.
+ *
+ * @param x
+ * The X-axis offset.
+ * @param y
+ * The Y-axis offset.
+ */
+ public ImageOutputControl(int x, int y) {
+
+ _Xcoordinate = x;
+ _Ycoordinate = y;
+
+ }
+
+ /**
+ * Accessor method to write the AFP datastream for the Image Output Control
+ * @param os The stream to write to
+ * @throws java.io.IOException
+ */
+ public void writeDataStream(OutputStream os)
+ throws IOException {
+
+ byte[] data = new byte[33];
+
+ data[0] = 0x5A;
+ data[1] = 0x00;
+ data[2] = 0x20;
+ data[3] = (byte) 0xD3;
+ data[4] = (byte) 0xA7;
+ data[5] = (byte) 0x7B;
+ data[6] = 0x00;
+ data[7] = 0x00;
+ data[8] = 0x00;
+
+ // XoaOset
+ byte[] x1 = BinaryUtils.convert(_Xcoordinate, 3);
+ data[9] = x1[0];
+ data[10] = x1[1];
+ data[11] = x1[2];
+
+ // YoaOset
+ byte[] x2 = BinaryUtils.convert(_Ycoordinate, 3);
+ data[12] = x2[0];
+ data[13] = x2[1];
+ data[14] = x2[2];
+
+ switch (_orientation) {
+ case 0:
+ // 0 and 90 degrees respectively
+ data[15] = 0x00;
+ data[16] = 0x00;
+ data[17] = 0x2D;
+ data[18] = 0x00;
+ break;
+ case 90:
+ // 90 and 180 degrees respectively
+ data[15] = 0x2D;
+ data[16] = 0x00;
+ data[17] = 0x5A;
+ data[18] = 0x00;
+ break;
+ case 180:
+ // 180 and 270 degrees respectively
+ data[15] = 0x5A;
+ data[16] = 0x00;
+ data[17] = (byte) 0x87;
+ data[18] = 0x00;
+ break;
+ case 270:
+ // 270 and 0 degrees respectively
+ data[15] = (byte) 0x87;
+ data[16] = 0x00;
+ data[17] = 0x00;
+ data[18] = 0x00;
+ break;
+ default:
+ // 0 and 90 degrees respectively
+ data[15] = 0x00;
+ data[16] = 0x00;
+ data[17] = 0x2D;
+ data[18] = 0x00;
+ break;
+
+ }
+
+ // Constant Data
+ data[19] = 0x00;
+ data[20] = 0x00;
+ data[21] = 0x00;
+ data[22] = 0x00;
+ data[23] = 0x00;
+ data[24] = 0x00;
+ data[25] = 0x00;
+ data[26] = 0x00;
+
+ if (_singlepoint) {
+ data[27] = 0x03;
+ data[28] = (byte) 0xE8;
+ data[29] = 0x03;
+ data[30] = (byte) 0xE8;
+ } else {
+ data[27] = 0x07;
+ data[28] = (byte) 0xD0;
+ data[29] = 0x07;
+ data[30] = (byte) 0xD0;
+ }
+
+ // Constant Data
+ data[31] = (byte) 0xFF;
+ data[32] = (byte) 0xFF;
+
+ os.write(data);
+
+ }
+
+ /**
+ * Sets the orientation which specifies the amount of clockwise rotation of
+ * the IM image object area.
+ *
+ * @param orientation
+ * The orientation to set.
+ */
+ public void setOrientation(int orientation) {
+
+ if (orientation == 0 || orientation == 90 || orientation == 180
+ || orientation == 270) {
+ _orientation = orientation;
+ } else {
+ throw new IllegalArgumentException(
+ "The orientation must be one of the values 0, 90, 180, 270");
+ }
+
+ }
+
+ /**
+ * Sets the singlepoint, if true map an image point to a single presentation
+ * device pel in the IM image object area. If false map an image point to
+ * two presentation device pels in the IM image object area (double-dot)
+ *
+ * @param singlepoint
+ * Use the singlepoint basis when true.
+ */
+ public void setSinglepoint(boolean singlepoint) {
+ _singlepoint = singlepoint;
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/ImageRasterData.java b/src/sandbox/org/apache/fop/render/afp/modca/ImageRasterData.java
new file mode 100644
index 000000000..9c815cb6f
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/ImageRasterData.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+/**
+ * Contains the image points that define the IM image raster pattern.
+ *
+ * A raster pattern is the array of presentation device pels that forms
+ * the image. The image data is uncompressed. Bits are grouped into
+ * bytes and are ordered from left to right within each byte. Each bit
+ * in the image data represents an image point and is mapped to
+ * presentation device pels as specified in the IOC structured field.
+ * A bit with value B'1' indicates a significant image point; a bit
+ * with value B'0' indicates an insignificant image point.
+ * Image points are recorded from left to right in rows that represents
+ * scan lines (X direction), and rows representing scan lines are
+ * recorded from top to bottom (Y direction). When the image is
+ * presented, all image points in a row are presented before any
+ * image points in the next sequential row are presented, and all rows
+ * have the same number of image points. If the total number of image
+ * points is not a multiple of 8, the last byte of the image data is
+ * padded to a byte boundary. The padding bits do not represent image
+ * points and are ignored by presentation devices.
+ */
+public class ImageRasterData extends AbstractAFPObject {
+
+ /**
+ * The image raster data
+ */
+ private byte[] _rasterdata;
+
+ /**
+ * Constructor for the image raster data object
+ * @param rasterdata The raster image data
+ */
+ public ImageRasterData(byte[] rasterdata) {
+
+ _rasterdata = rasterdata;
+
+ }
+
+ /**
+ * Accessor method to write the AFP datastream for the Image Raster Data
+ * @param os The stream to write to
+ * @throws java.io.IOException
+ */
+ public void writeDataStream(OutputStream os)
+ throws IOException {
+
+ byte[] data = new byte[9];
+
+ data[0] = 0x5A;
+
+ // 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;
+
+ os.write(data);
+ os.write(_rasterdata);
+
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/ImageRasterPattern.java b/src/sandbox/org/apache/fop/render/afp/modca/ImageRasterPattern.java
new file mode 100644
index 000000000..c49f392b5
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/ImageRasterPattern.java
@@ -0,0 +1,762 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+/**
+ * Raster data is a grid of cells covering an area of interest.
+ * Each pixel, the smallest unit of information in the grid, displays
+ * a unique attribute. This static class generates raster data for different
+ * shades of grey (betweeen 0 and 16) the lower the number being the
+ * darker the shade. The image data dimensions are 64 x 8.
+ */
+public class ImageRasterPattern {
+
+ /**
+ * The Raster Pattern for Greyscale 16
+ */
+ private static final byte[] GREYSCALE16 = new byte[] {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ };
+
+ /**
+ * The Raster Pattern for Greyscale 15
+ */
+ private static final byte[] GREYSCALE15 = new byte[] {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ };
+
+ /**
+ * The Raster Pattern for Greyscale 14
+ */
+ private static final byte[] GREYSCALE14 = new byte[] {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x44,
+ };
+
+
+ /**
+ * The Raster Pattern for Greyscale 13
+ */
+ private static final byte[] GREYSCALE13 = new byte[] {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ };
+
+ /**
+ * The Raster Pattern for Greyscale 12
+ */
+ private static final byte[] GREYSCALE12 = new byte[] {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ };
+
+ /**
+ * The Raster Pattern for Greyscale 11
+ */
+ private static final byte[] GREYSCALE11 = new byte[] {
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ };
+
+ /**
+ * The Raster Pattern for Greyscale 10
+ */
+ private static final byte[] GREYSCALE10 = new byte[] {
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x44,
+ 0x44,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ };
+
+ /**
+ * The Raster Pattern for Greyscale 9
+ */
+ private static final byte[] GREYSCALE09 = new byte[] {
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ };
+
+ /**
+ * The Raster Pattern for Greyscale 8
+ */
+ private static final byte[] GREYSCALE08 = new byte[] {
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ };
+
+
+ /**
+ * The Raster Pattern for Greyscale 7
+ */
+ private static final byte[] GREYSCALE07 = new byte[] {
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ };
+
+
+ /**
+ * The Raster Pattern for Greyscale 6
+ */
+ private static final byte[] GREYSCALE06 = new byte[] {
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ (byte)0xEE,
+ (byte)0xEE,
+ (byte)0xEE,
+ (byte)0xEE,
+ (byte)0xEE,
+ (byte)0xEE,
+ (byte)0xEE,
+ (byte)0xEE,
+ };
+
+ /**
+ * The Raster Pattern for Greyscale 5
+ */
+ private static final byte[] GREYSCALE05 = new byte[] {
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xEE,
+ (byte)0xEE,
+ (byte)0xEE,
+ (byte)0xEE,
+ (byte)0xEE,
+ (byte)0xEE,
+ (byte)0xEE,
+ (byte)0xEE,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ };
+
+
+ /**
+ * The Raster Pattern for Greyscale 4
+ */
+ private static final byte[] GREYSCALE04 = new byte[] {
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xAA,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ };
+
+ /**
+ * The Raster Pattern for Greyscale 3
+ */
+ private static final byte[] GREYSCALE03 = new byte[] {
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ 0x55,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xBB,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ };
+
+ /**
+ * The Raster Pattern for Greyscale 2
+ */
+ private static final byte[] GREYSCALE02 = new byte[] {
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xDD,
+ (byte)0xDD,
+ (byte)0xDD,
+ (byte)0xDD,
+ (byte)0xDD,
+ (byte)0xDD,
+ (byte)0xDD,
+ (byte)0xDD,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ };
+
+
+ /**
+ * The Raster Pattern for Greyscale 1
+ */
+ private static final byte[] GREYSCALE01 = new byte[] {
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ 0x77,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ };
+
+
+ /**
+ * The Raster Pattern for Greyscale 00
+ */
+ private static final byte[] GREYSCALE00 = new byte[] {
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ (byte)0xFF,
+ };
+
+ /**
+ * Static method to return the raster image data for the
+ * grey scale specified. The scale should be between 0 (darkest)
+ * and 16 (lightest).
+ * @param greyscale The grey scale value (0 - 16)
+ */
+ public static byte[] getRasterData(int greyscale) {
+
+ int repeat = 16;
+
+ byte[] greypattern = new byte[32];
+ byte[] rasterdata = new byte[32 * repeat];
+
+ switch (greyscale) {
+ case 0:
+ System.arraycopy(GREYSCALE00, 0, greypattern, 0, 32);
+ break;
+ case 1:
+ System.arraycopy(GREYSCALE01, 0, greypattern, 0, 32);
+ break;
+ case 2:
+ System.arraycopy(GREYSCALE02, 0, greypattern, 0, 32);
+ break;
+ case 3:
+ System.arraycopy(GREYSCALE03, 0, greypattern, 0, 32);
+ break;
+ case 4:
+ System.arraycopy(GREYSCALE04, 0, greypattern, 0, 32);
+ break;
+ case 5:
+ System.arraycopy(GREYSCALE05, 0, greypattern, 0, 32);
+ break;
+ case 6:
+ System.arraycopy(GREYSCALE06, 0, greypattern, 0, 32);
+ break;
+ case 7:
+ System.arraycopy(GREYSCALE07, 0, greypattern, 0, 32);
+ break;
+ case 8:
+ System.arraycopy(GREYSCALE08, 0, greypattern, 0, 32);
+ break;
+ case 9:
+ System.arraycopy(GREYSCALE09, 0, greypattern, 0, 32);
+ break;
+ case 10:
+ System.arraycopy(GREYSCALE10, 0, greypattern, 0, 32);
+ break;
+ case 11:
+ System.arraycopy(GREYSCALE11, 0, greypattern, 0, 32);
+ break;
+ case 12:
+ System.arraycopy(GREYSCALE12, 0, greypattern, 0, 32);
+ break;
+ case 13:
+ System.arraycopy(GREYSCALE13, 0, greypattern, 0, 32);
+ break;
+ case 14:
+ System.arraycopy(GREYSCALE14, 0, greypattern, 0, 32);
+ break;
+ case 15:
+ System.arraycopy(GREYSCALE15, 0, greypattern, 0, 32);
+ break;
+ case 16:
+ System.arraycopy(GREYSCALE16, 0, greypattern, 0, 32);
+ break;
+ default :
+ System.arraycopy(GREYSCALE00, 0, greypattern, 0, 32);
+ break;
+ }
+
+ for(int i = 0; i < repeat; i++) {
+
+ System.arraycopy(greypattern, 0, rasterdata, i * 32, 32);
+
+ }
+
+ return rasterdata;
+
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/ImageSegment.java b/src/sandbox/org/apache/fop/render/afp/modca/ImageSegment.java
new file mode 100644
index 000000000..0e5a2f691
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/ImageSegment.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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);
+ }
+
+ _name = name;
+
+ try {
+
+ _nameBytes = name.getBytes(AFPConstants.EBCIDIC_ENCODING);
+
+ } catch (UnsupportedEncodingException usee) {
+
+ _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 size 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
+ */
+ 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/sandbox/org/apache/fop/render/afp/modca/ImageSizeParameter.java b/src/sandbox/org/apache/fop/render/afp/modca/ImageSizeParameter.java
new file mode 100644
index 000000000..46e93181e
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/ImageSizeParameter.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+/**
+ * Describes the measurement characteristics of the image when it is created.
+ */
+public class ImageSizeParameter extends AbstractAFPObject {
+
+ private int _hresol = 0;
+ private int _vresol = 0;
+ private int _hsize = 0;
+ private int _vsize = 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 hsize of the image.
+ * @param vsize The vsize of the vsize.
+ */
+ public ImageSizeParameter(int hresol, int vresol, int hsize, int vsize) {
+
+ _hresol = hresol;
+ _vresol = vresol;
+ _hsize = hsize;
+ _vsize = vsize;
+
+ }
+
+ /**
+ * Accessor method to write the AFP datastream for the Image Size Parameter
+ * @param os The stream to write to
+ * @throws java.io.IOException
+ */
+ public void writeDataStream(OutputStream os)
+ throws IOException {
+
+ byte[] data = new byte[] {
+ (byte)0x94, // ID = Image Size Parameter
+ 0x09, // Length
+ 0x00, // Unit base - 10 Inches
+ 0x00, // HRESOL
+ 0x00, //
+ 0x00, // VRESOL
+ 0x00, //
+ 0x00, // HSIZE
+ 0x00, //
+ 0x00, // VSIZE
+ 0x00, //
+ };
+
+ byte[] x = BinaryUtils.convert(_hresol, 2);
+ data[3] = x[0];
+ data[4] = x[1];
+
+ byte[] y = BinaryUtils.convert(_vresol, 2);
+ data[5] = y[0];
+ data[6] = y[1];
+
+ byte[] w = BinaryUtils.convert(_hsize, 2);
+ data[7] = w[0];
+ data[8] = w[1];
+
+ byte[] h = BinaryUtils.convert(_vsize, 2);
+ data[9] = h[0];
+ data[10] = h[1];
+
+ os.write(data);
+
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/IncludeObject.java b/src/sandbox/org/apache/fop/render/afp/modca/IncludeObject.java
new file mode 100644
index 000000000..257cf1ee1
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/IncludeObject.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+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 orienation 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) {
+ _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
+ */
+ 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/sandbox/org/apache/fop/render/afp/modca/IncludePageOverlay.java b/src/sandbox/org/apache/fop/render/afp/modca/IncludePageOverlay.java
new file mode 100644
index 000000000..4fb8b9cfe
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/IncludePageOverlay.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+import org.apache.fop.render.afp.tools.BinaryUtils;
+
+/**
+ *
+ * The Include Page Overlay structured field references an overlay resource
+ * definition that is to be positioned on the page. A page overlay can be
+ * referenced at any time during the page state, but not during an object state.
+ * The overlay contains its own active environment group definition.
+ *
+ * Note: There is no need for the triplets, so I have ignored them.
+ *
+ * A real example of where this will be used is for static overlays, such as an
+ * address on the page.
+ *
+ */
+public class IncludePageOverlay extends AbstractNamedAFPObject {
+
+ /**
+ * The x coordinate
+ */
+ private int _xCoor = 0;
+
+ /**
+ * The y coordinate
+ */
+ private int _yCoor = 0;
+
+ /**
+ * The orientation
+ */
+ private int _orientation = 0;
+
+ /**
+ * Constructor for the Include Page Overlay
+ * @param overlayName Name of the page segment
+ * @param x The x position
+ * @param y The y position
+ * @param orientation The orientation
+ */
+ public IncludePageOverlay(String overlayName, int x, int y, int orientation) {
+
+ super(overlayName);
+
+ _xCoor = x;
+ _yCoor = y;
+ setOrientation(orientation);
+ }
+
+ /**
+ * Sets the orienation to use for the overlay.
+ *
+ * @param orientation
+ * The orientation (0,90, 180, 270)
+ */
+ public void setOrientation(int orientation) {
+
+ if (orientation == 0 || orientation == 90 || orientation == 180
+ || orientation == 270) {
+ _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 Page Overlay
+ * @param os The stream to write to
+ * @throws java.io.IOException
+ */
+ public void writeDataStream(OutputStream os)
+ throws IOException {
+
+ byte[] data = new byte[25]; //(9 +16)
+
+ data[0] = 0x5A;
+
+ // Set the total record length
+ byte[] rl1 = BinaryUtils.convert(24, 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) 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[] r2 = BinaryUtils.convert(_xCoor, 3);
+ data[17] = r2[0]; // x coordinate
+ data[18] = r2[1];
+ data[19] = r2[2];
+
+ byte[] r3 = BinaryUtils.convert(_yCoor, 3);
+ data[20] = r3[0]; // y coordinate
+ data[21] = r3[1];
+ data[22] = r3[2];
+
+ switch (_orientation) {
+ case 90:
+ data[23] = 0x2D;
+ data[24] = 0x00;
+ break;
+ case 180:
+ data[23] = 0x5A;
+ data[24] = 0x00;
+ break;
+ case 270:
+ data[23] = (byte) 0x87;
+ data[24] = 0x00;
+ break;
+ default:
+ data[23] = 0x00;
+ data[24] = 0x00;
+ break;
+ }
+
+ os.write(data);
+
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/IncludePageSegment.java b/src/sandbox/org/apache/fop/render/afp/modca/IncludePageSegment.java
new file mode 100644
index 000000000..5db736d57
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/IncludePageSegment.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+import org.apache.fop.render.afp.tools.BinaryUtils;
+
+/**
+ * The Include Page Segment structured field references a page segment resource
+ * object that is to be presented on the page or overlay presentation space. The IPS
+ * specifies a reference point on the including page or overlay coordinate system that
+ * may be used to position objects contained in the page segment. A page segment
+ * can be referenced at any time during page or overlay state, but not during an
+ * object state. The page segment inherits the active environment group definition of
+ * the including page or overlay.
+ *
+ * Note : No use for Triplets.
+ *
+ * A 'real' example for where this will be used is for
+ * the dynamic placing of overlay objects, such as signatures
+ * that may have to be placed at different positions on a document.
+ *
+ */
+public class IncludePageSegment extends AbstractNamedAFPObject{
+
+ /**
+ * The x position where we need to put this object on the page
+ */
+ private byte [] _xCoor;
+
+ /**
+ * The y position where we need to put this object on the page
+ */
+ private byte [] _yCoor;
+
+ /**
+ * Constructor for the Include Page Segment
+ * @param name Name of the page segment
+ * @param xVal The x position
+ * @param yVal The y position
+ */
+ public IncludePageSegment(String name, int xVal, int yVal){
+
+ super(name);
+ _xCoor = BinaryUtils.convert(xVal, 3);
+ _yCoor = BinaryUtils.convert(yVal, 3);
+
+ }
+
+ /**
+ * Accessor method to write the AFP datastream for the Include Page Segment
+ * @param os The stream to write to
+ * @throws java.io.IOException
+ */
+ public void writeDataStream(OutputStream os)
+ throws IOException {
+
+ byte[] data = new byte[23]; //(9 +14)
+
+ data[0] = 0x5A;
+
+ // 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] = _xCoor[0]; // x coordinate
+ data[18] = _xCoor[1];
+ data[19] = _xCoor[2];
+
+ data[20] = _yCoor[0]; // y coordinate
+ data[21] = _yCoor[1];
+ data[22] = _yCoor[2];
+
+ os.write(data);
+
+ }
+
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/InvokeMediumMap.java b/src/sandbox/org/apache/fop/render/afp/modca/InvokeMediumMap.java
new file mode 100644
index 000000000..14570ec27
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/InvokeMediumMap.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+import org.apache.fop.render.afp.tools.BinaryUtils;
+
+/**
+ * The Invoke Medium Map structured field identifies the Medium Map that is to
+ * become active for the document. An Invoke Medium Map structured field affects
+ * the document's current environment. The Medium Map's effect on current environment
+ * parameter values lasts until a new Medium Map is invoked.
+ */
+public class InvokeMediumMap extends AbstractNamedAFPObject {
+
+ /**
+ * Constructor for the Invoke Medium Map
+ * @param mediumMapName Name of the medium map
+ */
+ public InvokeMediumMap(String mediumMapName) {
+
+ super(mediumMapName);
+
+ }
+
+ /**
+ * Accessor method to write the AFP datastream for the Invoke Medium Map
+ * @param os The stream to write to
+ * @throws java.io.IOException
+ */
+ public void writeDataStream(OutputStream os)
+ throws IOException {
+
+ byte[] data = new byte[17];
+
+ data[0] = 0x5A;
+
+ // 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];
+
+ }
+
+ os.write(data);
+
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/MapCodedFont.java b/src/sandbox/org/apache/fop/render/afp/modca/MapCodedFont.java
new file mode 100644
index 000000000..9290dfcdd
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/MapCodedFont.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+
+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;
+
+/**
+ * The Map Coded Font structured field maps a unique coded font resource local
+ * ID, which may be embedded one or more times within an object's data and
+ * 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 {
+
+ /**
+ * The collection of map coded fonts (maximum of 254)
+ */
+ private ArrayList _fontlist = null;
+
+ /**
+ * Constructor for the MapCodedFont
+ */
+ public MapCodedFont() {
+
+ _fontlist = new ArrayList();
+
+ }
+
+ /**
+ * Accessor method to write the AFP datastream for the Map Coded Font
+ * @param os The stream to write to
+ * @throws java.io.IOException
+ */
+ public void writeDataStream(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 });
+
+ for (int i = 0; i < _fontlist.size(); i++) {
+
+ FontDefinition fd = (FontDefinition) _fontlist.get(i);
+
+ // Start of repeating groups (occurs 1 to 254)
+ baos.write(0x00);
+
+ if (fd._scale == 0) {
+ // Raster Font
+ baos.write(0x22); // Length of 34
+ } else {
+ // Outline Font
+ baos.write(0x3A); // Length of 58
+ }
+
+ // Font Character Set Name Reference
+ baos.write(0x0C);
+ baos.write(0x02);
+ baos.write((byte) 0x86);
+ baos.write(0x00);
+ baos.write(fd._characterset);
+
+ // Font Code Page Name Reference
+ baos.write(0x0C);
+ baos.write(0x02);
+ baos.write((byte) 0x85);
+ baos.write(0x00);
+ baos.write(fd._codepage);
+
+ // Character Rotation
+ baos.write(0x04);
+ baos.write(0x26);
+ baos.write(fd._orientation);
+ baos.write(0x00);
+
+ // Resource Local Identifier
+ baos.write(0x04);
+ baos.write(0x24);
+ baos.write(0x05);
+ baos.write(fd._fontReferenceKey);
+
+ if (fd._scale != 0) {
+ // Outline Font (triplet '1F')
+ baos.write(0x14);
+ baos.write(0x1F);
+ baos.write(0x00);
+ baos.write(0x00);
+
+ baos.write(BinaryUtils.convert(fd._scale, 2)); // Height
+ baos.write(new byte[] { 0x00, 0x00 }); // Width
+
+ baos.write(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00 });
+
+ baos.write(0x60);
+
+ // Outline Font (triplet '5D')
+ baos.write(0x04);
+ baos.write(0x5D);
+ baos.write(BinaryUtils.convert(fd._scale, 2));
+ }
+
+ }
+
+ byte[] data = baos.toByteArray();
+
+ // Set the total record length
+ byte[] rl1 = BinaryUtils.convert(data.length - 1, 2);
+ data[1] = rl1[0];
+ data[2] = rl1[1];
+
+ os.write(data);
+
+ }
+
+ /**
+ * Add a font definition on the the map coded font object.
+ *
+ * @param fontReference
+ * the font number used as the resource identifier
+ * @param font
+ * the font
+ * @param size
+ * the size of the font
+ * @param orientation
+ * the orientation of the font
+ */
+ public void addFont(byte fontReference, AFPFont font, int size, int orientation)
+ throws MaximumSizeExceededException {
+
+ FontDefinition fd = new FontDefinition();
+
+ fd._fontReferenceKey = fontReference;
+
+ switch (orientation) {
+ case 90:
+ fd._orientation = 0x2D;
+ break;
+ case 180:
+ fd._orientation = 0x5A;
+ break;
+ case 270:
+ fd._orientation = (byte) 0x87;
+ break;
+ default:
+ fd._orientation = 0x00;
+ break;
+ }
+
+ try {
+
+ if (font instanceof RasterFont) {
+
+ RasterFont raster = (RasterFont) font;
+ CharacterSet cs = raster.getCharacterSet(size);
+ if (cs == null) {
+ String msg = "Character set not found for font "
+ + font.getFontName() + " with point size " + size;
+ log.error(msg);
+ throw new FontRuntimeException(msg);
+ }
+
+ fd._characterset = cs.getNameBytes();
+
+ if (fd._characterset.length != 8) {
+ throw new IllegalArgumentException("The character set "
+ + new String(fd._characterset,
+ AFPConstants.EBCIDIC_ENCODING)
+ + " must have a fixed length of 8 characters.");
+ }
+
+ fd._codepage = cs.getCodePage().getBytes(
+ AFPConstants.EBCIDIC_ENCODING);
+
+ if (fd._codepage.length != 8) {
+ throw new IllegalArgumentException("The code page "
+ + new String(fd._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();
+
+ // There are approximately 72 points to 1 inch or 20 1440ths per point.
+
+ fd._scale = ((size / 1000) * 20);
+
+ fd._codepage = cs.getCodePage().getBytes(
+ AFPConstants.EBCIDIC_ENCODING);
+
+ if (fd._codepage.length != 8) {
+ throw new IllegalArgumentException("The code page "
+ + new String(fd._codepage,
+ AFPConstants.EBCIDIC_ENCODING)
+ + " must have a fixed length of 8 characters.");
+ }
+
+ } else {
+ String msg = "Font of type " + font.getClass().getName()
+ + " not recognized.";
+ log.error(msg);
+ throw new FontRuntimeException(msg);
+ }
+
+ if (_fontlist.size() > 253) {
+
+ // Throw an exception if the size is exceeded
+ throw new MaximumSizeExceededException();
+
+ } else {
+
+ _fontlist.add(fd);
+
+ }
+
+ } 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
+ */
+ private class FontDefinition {
+
+ /**
+ * The code page of the font
+ */
+ private byte[] _codepage;
+
+ /**
+ * The character set of the font
+ */
+ private byte[] _characterset;
+
+ /**
+ * The font reference key
+ */
+ private byte _fontReferenceKey;
+
+ /**
+ * The orientation of the font
+ */
+ private byte _orientation;
+
+ /**
+ * The scale (only specified for outline fonts)
+ */
+ private int _scale = 0;
+
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/MapPageOverlay.java b/src/sandbox/org/apache/fop/render/afp/modca/MapPageOverlay.java
new file mode 100644
index 000000000..b2821b650
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/MapPageOverlay.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+import java.util.ArrayList;
+
+import org.apache.fop.render.afp.tools.BinaryUtils;
+
+/**
+ * The Map Page Overlay structured field maps a Resource Local ID to the name of
+ * a Begin Overlay structured field. A Map Page Overlay structured field may
+ * contain from one to 254 repeating groups.
+ *
+ */
+public class MapPageOverlay extends AbstractAFPObject {
+
+ /**
+ * The collection of overlays (maximum of 254 stored as byte[])
+ */
+ private ArrayList _overLays = new ArrayList();
+
+ /**
+ * Constructor for the Map Page Overlay
+ */
+ public MapPageOverlay() {
+
+ }
+
+ /**
+ * Add an overlay to to the map page overlay object.
+ *
+ * @param name
+ * The name of the overlay.
+ */
+ public void addOverlay(String name) throws MaximumSizeExceededException {
+
+ if (_overLays.size() > 253) {
+ 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);
+ }
+
+ byte[] data;
+
+ try {
+
+ data = name.getBytes(AFPConstants.EBCIDIC_ENCODING);
+ _overLays.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
+ */
+ public void writeDataStream(OutputStream os)
+ throws IOException {
+
+
+ int oLayCount = _overLays.size();
+ int recordlength = oLayCount * 18;
+
+ byte[] data = new byte[recordlength + 9];
+
+ data[0] = 0x5A;
+
+ // Set the total record length
+ byte[] rl1 = BinaryUtils.convert(recordlength + 8, 2); //Ignore the
+ // first byte in
+ // the length
+ data[1] = rl1[0];
+ data[2] = rl1[1];
+
+ // Structured field ID for a MPO
+ data[3] = (byte) 0xD3;
+ data[4] = (byte) 0xAB;
+ data[5] = (byte) 0xD8;
+
+ data[6] = 0x00; // Reserved
+ data[7] = 0x00; // Reserved
+ data[8] = 0x00; // Reserved
+
+ int pos = 8;
+
+ //For each overlay
+ byte olayref = 0x00;
+
+ for (int i = 0; i < oLayCount; i++) {
+
+ olayref = (byte) (olayref + 1);
+
+ data[++pos] = 0x00;
+ data[++pos] = 0x12; //the length of repeating group
+
+ data[++pos] = 0x0C; //Fully Qualified Name
+ data[++pos] = 0x02;
+ data[++pos] = (byte) 0x84;
+ data[++pos] = 0x00;
+
+ //now add the name
+ byte[] name = (byte[]) _overLays.get(i);
+
+ for (int j = 0; j < name.length; j++) {
+
+ data[++pos] = name[j];
+
+ }
+
+ data[++pos] = 0x04; //Resource Local Identifier (RLI)
+ data[++pos] = 0x24;
+ data[++pos] = 0x02;
+
+ //now add the unique id to the RLI
+ data[++pos] = olayref;
+
+ }
+
+ os.write(data);
+
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/MaximumSizeExceededException.java b/src/sandbox/org/apache/fop/render/afp/modca/MaximumSizeExceededException.java
new file mode 100644
index 000000000..add47a00f
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/MaximumSizeExceededException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.afp.modca;
+
+/**
+ * An exception to handle maximum sizes being exceeded.
+ *
+ */
+public class MaximumSizeExceededException extends Exception {
+
+ public MaximumSizeExceededException() {
+ super();
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/ObjectAreaDescriptor.java b/src/sandbox/org/apache/fop/render/afp/modca/ObjectAreaDescriptor.java
new file mode 100644
index 000000000..fbefef066
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/ObjectAreaDescriptor.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 AbstractAFPObject {
+
+ private int _width = 0;
+ private int _height = 0;
+
+ /**
+ * Construct an object area descriptor for the specified object width
+ * and object height.
+ * @param width The page width.
+ * @param height The page height.
+ */
+ public ObjectAreaDescriptor(int width, int height) {
+
+ _width = width;
+ _height = height;
+
+ }
+
+ /**
+ * Accessor method to write the AFP datastream for the Object Area 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, // Length
+ 0x1C, // Length
+ (byte) 0xD3,
+ (byte) 0xA6,
+ (byte) 0x6B,
+ 0x00, // Flags
+ 0x00, // Reserved
+ 0x00, // Reserved
+ 0x03, // Triplet length
+ 0x43, // tid = Descriptor Position Triplet
+ 0x01, // DesPosId = 1
+ 0x08, // Triplet length
+ 0x4B, // tid = Measurement Units Triplet
+ 0x00, // XaoBase = 10 inches
+ 0x00, // YaoBase = 10 inches
+ 0x09, // XaoUnits = 2400
+ 0x60, // XaoUnits =
+ 0x09, // YaoUnits = 2400
+ 0x60, // YaoUnits =
+ 0x09, // Triplet length
+ 0x4C, // tid = Object Area Size
+ 0x02, // Size Type
+ 0x00, // XoaSize
+ 0x00,
+ 0x00,
+ 0x00, // YoaSize
+ 0x00,
+ 0x00,
+ };
+
+ byte[] l = BinaryUtils.convert(data.length - 1, 2);
+ data[1] = l[0];
+ data[2] = l[1];
+
+ 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/sandbox/org/apache/fop/render/afp/modca/ObjectAreaPosition.java b/src/sandbox/org/apache/fop/render/afp/modca/ObjectAreaPosition.java
new file mode 100644
index 000000000..7089a4103
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/ObjectAreaPosition.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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/sandbox/org/apache/fop/render/afp/modca/ObjectEnvironmentGroup.java b/src/sandbox/org/apache/fop/render/afp/modca/ObjectEnvironmentGroup.java
new file mode 100644
index 000000000..91d697e83
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/ObjectEnvironmentGroup.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 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
+ */
+ public void setObjectArea(int x, int y, int width, int height, int rotation) {
+
+ _objectAreaDescriptor = new ObjectAreaDescriptor(width, height);
+ _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
+ */
+ 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/sandbox/org/apache/fop/render/afp/modca/Overlay.java b/src/sandbox/org/apache/fop/render/afp/modca/Overlay.java
new file mode 100644
index 000000000..85d8b2abb
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/Overlay.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 java.util.Iterator;
+
+/**
+ */
+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.
+ */
+ public Overlay(String name, int width, int height, int rotation) {
+
+ super(name, width, height, rotation);
+
+ }
+
+ /**
+ * Accessor method to write the AFP datastream for the overlay.
+ *
+ * @param os The stream to write to
+ * @throws java.io.IOException
+ */
+ 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/sandbox/org/apache/fop/render/afp/modca/PageDescriptor.java b/src/sandbox/org/apache/fop/render/afp/modca/PageDescriptor.java
new file mode 100644
index 000000000..3132f1778
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/PageDescriptor.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 Page Descriptor structured field specifies the size and attributes of
+ * a page or overlay presentation space.
+ *
+ */
+public class PageDescriptor extends AbstractAFPObject {
+
+ private int _width = 0;
+ private int _height = 0;
+
+ /**
+ * Construct a page descriptor for the specified page width
+ * and page height.
+ * @param width The page width.
+ * @param height The page height.
+ */
+ public PageDescriptor(int width, int height) {
+
+ _width = width;
+ _height = height;
+
+ }
+
+ /**
+ * Accessor method to write the AFP datastream for the Page 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,
+ 0x17,
+ (byte) 0xD3,
+ (byte) 0xA6,
+ (byte) 0xAF,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x09,
+ 0x60,
+ 0x09,
+ 0x60,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ };
+
+ byte[] x = BinaryUtils.convert(_width, 3);
+ data[15] = x[0];
+ data[16] = x[1];
+ data[17] = x[2];
+
+ byte[] y = BinaryUtils.convert(_height, 3);
+ data[18] = y[0];
+ data[19] = y[1];
+ data[20] = y[2];
+
+ os.write(data);
+
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/PageGroup.java b/src/sandbox/org/apache/fop/render/afp/modca/PageGroup.java
new file mode 100644
index 000000000..ea78d7677
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/PageGroup.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+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
+ */
+ 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
+ */
+ 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/sandbox/org/apache/fop/render/afp/modca/PageObject.java b/src/sandbox/org/apache/fop/render/afp/modca/PageObject.java
new file mode 100644
index 000000000..9bf543eee
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/PageObject.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+ public PageObject(String name, int width, int height, int rotation) {
+
+ super(name, width, height, rotation);
+
+ }
+
+ /**
+ * Adds an overlay to the page resources
+ * @param 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
+ */
+ 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/sandbox/org/apache/fop/render/afp/modca/PresentationTextData.java b/src/sandbox/org/apache/fop/render/afp/modca/PresentationTextData.java
new file mode 100644
index 000000000..38495c859
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/PresentationTextData.java
@@ -0,0 +1,598 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.AFPFontColor;
+
+import org.apache.fop.render.afp.tools.BinaryUtils;
+
+/**
+ * Presentation text data contains the graphic characters and the control
+ * sequences necessary to position the characters within the object space. The
+ * data consists of: - graphic characters to be presented - control sequences
+ * that position them - modal control sequences that adjust the positions by
+ * small amounts - other functions causing text to be presented with differences
+ * in appearance.
+ *
+ * The graphic characters are expected to conform to a coded font representation
+ * so that they can be translated from the code point in the object data to the
+ * character in the coded font. The units of measure for linear displacements
+ * are derived from the PresentationTextDescriptor or from the hierarchical
+ * defaults.
+ *
+ * In addition to graphic character code points, Presentation Text data can
+ * contain embedded control sequences. These are strings of two or more bytes
+ * which signal an alternate mode of processing for the content of the current
+ * Presentation Text data.
+ *
+ */
+public class PresentationTextData extends AbstractAFPObject {
+
+ /**
+ * 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 current x coordinate.
+ */
+ private int _currentXCoordinate = -1;
+
+ /**
+ * The current y cooridnate
+ */
+ private int _currentYCoordinate = -1;
+
+ /**
+ * The current font
+ */
+ private String _currentFont = "";
+
+ /**
+ * The current orientation
+ */
+ private int _currentOrientation = 0;
+
+ /**
+ * The current color
+ */
+ private AFPFontColor _currentColor = new AFPFontColor(0, 0, 0);
+
+ /**
+ * The current variable space increment
+ */
+ private int _currentVariableSpaceCharacterIncrement = 0;
+
+ /**
+ * The current inter character adjustment
+ */
+ private int _currentInterCharacterAdjustment = 0;
+
+ /**
+ * Default constructor for the PresentationTextData.
+ */
+ public PresentationTextData() {
+
+ this(false);
+
+ }
+
+ /**
+ * Constructor for the PresentationTextData, the boolean flag indicate
+ * whether the control sequence prefix should be set to indicate the start
+ * of a new control sequence.
+ *
+ * @param controlInd
+ * 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);
+
+ if (controlInd) {
+ _baos.write(new byte[] { 0x2B, (byte) 0xD3 }, 0, 2);
+ }
+
+ }
+
+ /**
+ * The Set Coded Font Local control sequence activates a coded font and
+ * specifies the character attributes to be used. This is a modal control
+ * sequence.
+ *
+ * @param font
+ * The font local identifier.
+ * @param afpdata
+ * 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)) {
+ return;
+ } else {
+ _currentFont = String.valueOf(font);
+ }
+
+ afpdata.write(new byte[] { 0x03, (byte) 0xF1, font, }, 0, 3);
+
+ }
+
+ /**
+ * Establishes the current presentation position on the baseline at a new
+ * I-axis coordinate, which is a specified number of measurement units from
+ * the B-axis. There is no change to the current B-axis coordinate.
+ *
+ * @param coordinate
+ * The coordinate for the inline move.
+ * @param afpdata
+ * The output stream to which data should be written.
+ */
+ private void absoluteMoveInline(int coordinate,
+ ByteArrayOutputStream afpdata) {
+
+ byte[] b = BinaryUtils.convert(coordinate, 2);
+
+ afpdata.write(new byte[] { 0x04, (byte) 0xC7, b[0], b[1], }, 0, 4);
+
+ _currentXCoordinate = coordinate;
+
+ }
+
+ /**
+ * Establishes the baseline and the current presentation position at a new
+ * B-axis coordinate, which is a specified number of measurement units from
+ * the I-axis. There is no change to the current I-axis coordinate.
+ *
+ * @param coordinate
+ * The coordinate for the baseline move.
+ * @param afpdata
+ * The output stream to which data should be written.
+ */
+ private void absoluteMoveBaseline(int coordinate,
+ ByteArrayOutputStream afpdata) {
+
+ byte[] b = BinaryUtils.convert(coordinate, 2);
+
+ afpdata.write(new byte[] { 0x04, (byte) 0xD3, b[0], b[1], }, 0, 4);
+
+ _currentYCoordinate = coordinate;
+
+ }
+
+ /**
+ * The Transparent Data control sequence contains a sequence of code points
+ * that are presented without a scan for embedded control sequences.
+ *
+ * @param data
+ * The text data to add.
+ * @param afpdata
+ * 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);
+ }
+
+ afpdata.write(new byte[] { BinaryUtils.convert(l)[0], (byte) 0xDB, },
+ 0, 2);
+
+ afpdata.write(data, 0, data.length);
+
+ }
+
+ /**
+ * Draws a line of specified length and specified width in the B-direction
+ * from the current presentation position. The location of the current
+ * presentation position is unchanged.
+ *
+ * @param length
+ * The length of the rule.
+ * @param width
+ * The width of the rule.
+ * @param afpdata
+ * 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
+ }, 0, 2);
+
+ // Rule length
+ byte[] data1 = BinaryUtils.shortToByteArray((short) length);
+ afpdata.write(data1, 0, data1.length);
+ // Rule width
+ byte[] data2 = BinaryUtils.shortToByteArray((short) width);
+ afpdata.write(data2, 0, data2.length);
+ // Rule width fraction
+ afpdata.write(0x00);
+
+ }
+
+ /**
+ * Draws a line of specified length and specified width in the I-direction
+ * from the current presentation position. The location of the current
+ * presentation position is unchanged.
+ *
+ * @param length
+ * The length of the rule.
+ * @param width
+ * The width of the rule.
+ * @param afpdata
+ * 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
+ }, 0, 2);
+
+ // Rule length
+ byte[] data1 = BinaryUtils.shortToByteArray((short) length);
+ afpdata.write(data1, 0, data1.length);
+ // Rule width
+ byte[] data2 = BinaryUtils.shortToByteArray((short) width);
+ 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.
+ * @throws MaximumSizeExceededException
+ */
+ public void createTextData(int fontNumber, int x, int y, int orientation,
+ AFPFontColor col, int vsci, int ica, byte[] data)
+ throws MaximumSizeExceededException {
+
+ ByteArrayOutputStream afpdata = new ByteArrayOutputStream();
+
+ if (_currentOrientation != orientation) {
+ setTextOrientation(orientation, afpdata);
+ _currentOrientation = orientation;
+ _currentXCoordinate = -1;
+ _currentYCoordinate = -1;
+ }
+
+ // Avoid unnecessary specification of the Y co-ordinate
+ if (y != _currentYCoordinate) {
+ absoluteMoveBaseline(y, afpdata);
+ _currentXCoordinate = -1;
+ }
+
+ // Avoid unnecessary specification of the X co-ordinate
+ if (x != _currentXCoordinate) {
+ absoluteMoveInline(x, afpdata);
+ }
+
+ // Avoid unnecessary specification of the variable space increment
+ if (vsci != _currentVariableSpaceCharacterIncrement) {
+ setVariableSpaceCharacterIncrement(vsci, afpdata);
+ _currentVariableSpaceCharacterIncrement = vsci;
+ }
+
+ // Avoid unnecessary specification of the inter character adjustment
+ if (ica != _currentInterCharacterAdjustment) {
+ setInterCharacterAdjustment(ica, afpdata);
+ _currentInterCharacterAdjustment = ica;
+ }
+
+ // Avoid unnecessary specification of the text color
+ if (!col.equals(_currentColor)) {
+ setExtendedTextColor(col, afpdata);
+ _currentColor.setTo(col);
+ }
+
+ setCodedFont(BinaryUtils.convert(fontNumber)[0], afpdata);
+ addTransparentData(data, afpdata);
+ _currentXCoordinate = -1;
+
+ int s = afpdata.size();
+
+ if (_baos.size() + s > MAX_SIZE) {
+ _currentXCoordinate = -1;
+ _currentYCoordinate = -1;
+ throw new MaximumSizeExceededException();
+ }
+
+ byte[] outputdata = afpdata.toByteArray();
+ _baos.write(outputdata, 0, outputdata.length);
+
+ }
+
+ /**
+ * 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.
+ */
+ public void createLineData(int x1, int y1, int x2, int y2, int thickness,
+ int orientation, AFPFontColor col) throws MaximumSizeExceededException {
+
+ ByteArrayOutputStream afpdata = new ByteArrayOutputStream();
+
+ if (_currentOrientation != orientation) {
+ setTextOrientation(orientation, afpdata);
+ _currentOrientation = orientation;
+ }
+
+ // Avoid unnecessary specification of the Y coordinate
+ if (y1 != _currentYCoordinate) {
+ absoluteMoveBaseline(y1, afpdata);
+ }
+
+ // Avoid unnecessary specification of the X coordinate
+ if (x1 != _currentXCoordinate) {
+ absoluteMoveInline(x1, afpdata);
+ }
+
+ if (!col.equals(_currentColor)) {
+ setExtendedTextColor(col, afpdata);
+ _currentColor.setTo(col);
+ }
+
+ if (y1 == y2) {
+ drawIaxisRule(x2 - x1, thickness, afpdata);
+ } else if (x1 == x2) {
+ drawBaxisRule(y2 - y1, thickness, afpdata);
+ } else {
+ return;
+ }
+
+ int s = afpdata.size();
+
+ if (_baos.size() + s > MAX_SIZE) {
+ _currentXCoordinate = -1;
+ _currentYCoordinate = -1;
+ throw new MaximumSizeExceededException();
+ }
+
+ byte[] outputdata = afpdata.toByteArray();
+ _baos.write(outputdata, 0, outputdata.length);
+
+ }
+
+ /**
+ * The Set Text Orientation control sequence establishes the I-direction and
+ * B-direction for the subsequent text. This is a modal control sequence.
+ *
+ * Semantics: This control sequence specifies the I-axis and B-axis
+ * orientations with respect to the Xp-axis for the current Presentation
+ * Text object. The orientations are rotational values expressed in degrees
+ * and minutes.
+ *
+ * @param orientation
+ * The text orientation (0,90, 180, 270).
+ * @param afpdata
+ * 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);
+
+ 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;
+ }
+
+ }
+
+ /**
+ * 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.
+ *
+ * @param col
+ * The color to be set.
+ * @param afpdata
+ * The output stream to which data should be written.
+ */
+ private void setExtendedTextColor(AFPFontColor 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);
+
+ }
+
+ /**
+ * //TODO
+ * This is a modal control sequence.
+ *
+ * @param incr
+ * The increment to be set.
+ * @param afpdata
+ * The output stream to which data should be written.
+ */
+ private void setVariableSpaceCharacterIncrement(int incr,
+ ByteArrayOutputStream afpdata) {
+
+ 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);
+
+ }
+
+ /**
+ * //TODO
+ * This is a modal control sequence.
+ *
+ * @param incr
+ * The increment to be set.
+ * @param afpdata
+ * The output stream to which data should be written.
+ */
+ private void setInterCharacterAdjustment(int incr,
+ ByteArrayOutputStream afpdata) {
+
+ 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);
+
+ }
+
+ /**
+ * 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();
+ byte[] size = BinaryUtils.convert(data.length - 1, 2);
+ data[1] = size[0];
+ data[2] = size[1];
+
+ 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.
+ *
+ * @throws MaximumSizeExceededException
+ */
+ public void endControlSequence() throws MaximumSizeExceededException {
+
+ byte[] data = new byte[2];
+ data[0] = 0x02;
+ data[1] = (byte) 0xF8;
+
+ if (data.length + _baos.size() > MAX_SIZE) {
+ throw new MaximumSizeExceededException();
+ }
+
+ _baos.write(data, 0, data.length);
+
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/PresentationTextDescriptor.java b/src/sandbox/org/apache/fop/render/afp/modca/PresentationTextDescriptor.java
new file mode 100644
index 000000000..a205f026f
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/PresentationTextDescriptor.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 Presentation Text Descriptor specifies the units of measure for the
+ * Presentation Text object space, the size of the Presentation Text object
+ * space, and the initial values for modal parameters, called initial text
+ * conditions. Initial values not provided are defaulted by the controlling
+ * environment or the receiving device.
+ *
+ * The Presentation Text Descriptor provides the following initial values:
+ * - Unit base
+ * - Xp-units per unit base
+ * - Yp-units per unit base
+ * - Xp-extent of the presentation space
+ * - Yp-extent of the presentation space
+ * - Initial text conditions.
+ *
+ * The initial text conditions are values provided by the Presentation Text
+ * Descriptor to initialize the modal parameters of the control sequences.
+ * Modal control sequences typically are characterized by the word set in
+ * the name of the control sequence. Modal parameters are identified as such
+ * in their semantic descriptions.
+ *
+ */
+public class PresentationTextDescriptor extends AbstractAFPObject {
+
+ private int _width = 0;
+ private int _height = 0;
+
+ /**
+ * Constructor a PresentationTextDescriptor for the specified
+ * width and height.
+ * @param width The width of the page.
+ * @param height The height of the page.
+ */
+ public PresentationTextDescriptor(int width, int height) {
+
+ _width = width;
+ _height = height;
+
+ }
+
+ /**
+ * Accessor method to write the AFP datastream for the Presentation Text 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,
+ 0x16,
+ (byte) 0xD3,
+ (byte) 0xB1,
+ (byte) 0x9B,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x09,
+ 0x60,
+ 0x09,
+ 0x60,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ };
+
+ byte[] x = BinaryUtils.convert(_width, 3);
+ data[15] = x[0];
+ data[16] = x[1];
+ data[17] = x[2];
+
+ byte[] y = BinaryUtils.convert(_height, 3);
+ data[18] = y[0];
+ data[19] = y[1];
+ data[20] = y[2];
+
+ os.write(data);
+
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/PresentationTextObject.java b/src/sandbox/org/apache/fop/render/afp/modca/PresentationTextObject.java
new file mode 100644
index 000000000..ce54de152
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/PresentationTextObject.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+import java.util.ArrayList;
+import org.apache.fop.render.afp.AFPFontColor;
+
+/**
+ * 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.
+ */
+ 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, AFPFontColor 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,
+ AFPFontColor 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, AFPFontColor 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, AFPFontColor 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
+ */
+ public void writeDataStream(OutputStream os)
+ throws IOException {
+
+ writeStart(os);
+
+ writeObjectList(presentationTextData, os);
+
+ writeEnd(os);
+
+ }
+
+ 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/sandbox/org/apache/fop/render/afp/modca/ResourceGroup.java b/src/sandbox/org/apache/fop/render/afp/modca/ResourceGroup.java
new file mode 100644
index 000000000..0cfb53870
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/ResourceGroup.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+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();
+
+ 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
+ */
+ 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/sandbox/org/apache/fop/render/afp/modca/TagLogicalElement.java b/src/sandbox/org/apache/fop/render/afp/modca/TagLogicalElement.java
new file mode 100644
index 000000000..ca28154e6
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/TagLogicalElement.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+import org.apache.fop.render.afp.tools.BinaryUtils;
+
+/**
+ * A Tag Logical Element structured field assigns an attribute name and an
+ * attribute value to a page or page group. The Tag Logical Element structured
+ * field may be embedded directly in the page or page group, or it may reference
+ * the page or page group from a document index. When a Tag Logical Element
+ * structured field references a page or is embedded in a page following the
+ * active environment group, it is associated with the page. When a Tag Logical
+ * Element structured field references a page group or is embedded in a page
+ * group following the Begin Named Page Group structured field, it is associated
+ * with the page group. When a Tag Logical Element structured field is associated
+ * with a page group, the parameters of the Tag Logical Element structured field
+ * are inherited by all pages in the page group and by all other page groups
+ * that are nested in the page group. The scope of a Tag Logical Element is
+ * determined by its position with respect to other TLEs that reference, or are
+ * embedded in, the same page or page group. The Tag Logical Element structured
+ * field does not provide any presentation specifications and therefore has no
+ * effect on the appearance of a document when it is presented.
+ * <p/>
+ */
+public class TagLogicalElement extends AbstractAFPObject {
+
+ /**
+ * Name of the key, used within the TLE
+ */
+ private String _tleName = 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;
+
+ /**
+ * 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) {
+
+ _tleName = name;
+ _tleValue = value;
+
+ 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);
+
+ }
+
+ }
+
+ /**
+ * Accessor method to obtain the byte array AFP datastream for the
+ * TagLogicalElement.
+ * @param os The outputsteam stream
+ * @throws java.io.IOException
+ */
+ public void writeDataStream(OutputStream os) throws IOException {
+
+ byte[] data = new byte[17 + _tleName.length() + _tleValue.length()];
+
+ data[0] = 0x5A;
+ // Set the total record length
+ byte[] rl1 =
+ BinaryUtils.convert(16 + _tleName.length() + _tleValue.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[6] = 0x00; // Reserved
+ data[7] = 0x00; // Reserved
+ data[8] = 0x00; // Reserved
+
+ //Use 2 triplets, attrubute name and value (the key for indexing)
+
+ byte[] rl2 = BinaryUtils.convert(_tleName.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;
+
+ int pos = 13;
+ for (int i = 0; i < _tleByteName.length; i++) {
+ data[pos++] = _tleByteName[i];
+ }
+
+ byte[] rl3 = BinaryUtils.convert(_tleByteValue.length + 4, 1);
+ data[pos++] = rl3[0]; // length of the triplet, including this field
+ data[pos++] = 0x36; //Identifies the triplet, attribute value
+ data[pos++] = 0x00; // Reserved
+ data[pos++] = 0x00; // Reserved
+
+ for (int i = 0; i < _tleByteValue.length; i++) {
+ data[pos++] = _tleByteValue[i];
+ }
+ os.write(data);
+
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/modca/TagLogicalElementBean.java b/src/sandbox/org/apache/fop/render/afp/modca/TagLogicalElementBean.java
new file mode 100644
index 000000000..1784dfebd
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/modca/TagLogicalElementBean.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+/**
+ * The TagLogicalElementBean provides a bean for holding the attributes of
+ * a tag logical element as key value pairs.
+ * <p/>
+ */
+public class TagLogicalElementBean {
+
+ /** The key attribute */
+ private String _key;
+
+ /** The value attribute */
+ private String _value;
+
+ /**
+ * Constructor for the TagLogicalElementBean.
+ * @param key the key attribute
+ * @param value the value attribute
+ */
+ public TagLogicalElementBean(String key, String value) {
+ _key = key;
+ _value = value;
+ }
+
+ /**
+ * Getter for the key attribute.
+ * @return the key
+ */
+ public String getKey() {
+ return _key;
+ }
+
+ /**
+ * Getter for the value attribute.
+ * @return the value
+ */
+ public String getValue() {
+ return _value;
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/tools/BinaryUtils.java b/src/sandbox/org/apache/fop/render/afp/tools/BinaryUtils.java
new file mode 100644
index 000000000..4dead37ac
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/tools/BinaryUtils.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tools;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * Library of utility useful conversion methods.
+ *
+ */
+public final class BinaryUtils {
+
+ /**
+ * Convert an int into the corresponding byte array by encoding each
+ * two hexadecimal digits as a char. This will return a byte array
+ * to the length specified by bufsize.
+ * @param integer The int representation.
+ * @param bufsize The required byte array size.
+ */
+ public static byte[] convert(int integer, int bufsize) {
+
+ StringBuffer buf = new StringBuffer(Integer.toHexString(integer));
+ if (buf.length() % 2 == 0) {
+ // Ignore even number of digits
+ } else {
+ // Convert to an even number of digits
+ buf.insert(0, "0");
+ }
+ int size = buf.length() / 2;
+ while (size < bufsize) {
+ buf.insert(0, "00");
+ size++;
+ };
+ return convert(buf.toString());
+
+ }
+
+ /**
+ * Convert an int into the corresponding byte array by encoding each
+ * two hexadecimal digits as a char.
+ * @param integer The int representation
+ */
+ public static byte[] convert(int integer) {
+
+ return convert(Integer.toHexString(integer));
+
+ }
+
+ /**
+ * Convert a String of hexadecimal digits into the corresponding
+ * byte array by encoding each two hexadecimal digits as a byte.
+ * @param digits The hexadecimal digits representation.
+ */
+ public static byte[] convert(String digits) {
+
+ if (digits.length() % 2 == 0) {
+ // Even number of digits, so ignore
+ } else {
+ // Convert to an even number of digits
+ digits = "0" + digits;
+ }
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ for (int i = 0; i < digits.length(); i += 2) {
+ char c1 = digits.charAt(i);
+ char c2 = digits.charAt(i + 1);
+ byte b = 0;
+ if ((c1 >= '0') && (c1 <= '9'))
+ b += ((c1 - '0') * 16);
+ else if ((c1 >= 'a') && (c1 <= 'f'))
+ b += ((c1 - 'a' + 10) * 16);
+ else if ((c1 >= 'A') && (c1 <= 'F'))
+ b += ((c1 - 'A' + 10) * 16);
+ else
+ throw new IllegalArgumentException("Bad hexadecimal digit");
+ if ((c2 >= '0') && (c2 <= '9'))
+ b += (c2 - '0');
+ else if ((c2 >= 'a') && (c2 <= 'f'))
+ b += (c2 - 'a' + 10);
+ else if ((c2 >= 'A') && (c2 <= 'F'))
+ b += (c2 - 'A' + 10);
+ else
+ throw new IllegalArgumentException("Bad hexadecimal digit");
+ baos.write(b);
+ }
+ return (baos.toByteArray());
+
+ }
+
+ /**
+ * Convert the specified short into a byte array.
+ * @param value The value to be converted.
+ * @param array The array to receive the data.
+ * @param offset The offset into the byte array for the start of the value.
+ */
+ public static void shortToByteArray(
+ short value,
+ byte[] array,
+ int offset) {
+ array[offset] = (byte) (value >>> 8);
+ array[offset + 1] = (byte) value;
+ }
+
+ /**
+ * Convert the specified short into a byte array.
+ * @param value The value to be converted.
+ * @return The byte array
+ */
+ public static byte[] shortToByteArray(short value) {
+ byte[] serverValue = new byte[2];
+ shortToByteArray(value, serverValue, 0);
+ return serverValue;
+ }
+
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/tools/DTDEntityResolver.java b/src/sandbox/org/apache/fop/render/afp/tools/DTDEntityResolver.java
new file mode 100644
index 000000000..94f4c46bd
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/tools/DTDEntityResolver.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tools;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.apache.fop.render.afp.exceptions.FontRuntimeException;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+
+/**
+ * An entity resolver for both DOM and SAX models of the SAX document.
+ * <p>
+ * The entity resolver only handles queries for the DTD. It will find any URI
+ * with a recognised public id and return an {@link org.xml.sax.InputSource}.
+ * <p>
+ * @author <a href="mailto:joe@exubero.com">Joe Schmetzer</a>
+ */
+public class DTDEntityResolver implements EntityResolver {
+
+ /** Public ID for the AFP fonts 1.0 DTD. */
+ public static final String AFP_DTD_1_0_ID = "-//APACHE/DTD AFP Installed Font Definition DTD 1.0//EN";
+
+ /** Resource location for the AFP fonts 1.0 DTD. */
+ public static final String AFP_DTD_1_0_RESOURCE = "afp-fonts-1.0.dtd";
+
+ /** Public ID for the AFP fonts 1.1 DTD. */
+ public static final String AFP_DTD_1_1_ID = "-//APACHE/DTD AFP Installed Font Definition DTD 1.1//EN";
+
+ /** Resource location for the AFP fonts 1.1 DTD. */
+ public static final String AFP_DTD_1_1_RESOURCE = "afp-fonts-1.1.dtd";
+
+ /** Public ID for the AFP fonts 1.2 DTD. */
+ public static final String AFP_DTD_1_2_ID = "-//APACHE/DTD AFP Installed Font Definition DTD 1.2//EN";
+
+ /** Resource location for the AFP fonts 1.2 DTD. */
+ public static final String AFP_DTD_1_2_RESOURCE = "afp-fonts-1.2.dtd";
+
+ /**
+ * Resolve the combination of system and public identifiers.
+ * If this resolver recognises the publicId, it will handle the resolution
+ * from the classpath, otherwise it will return null and allow the default
+ * resolution to occur.
+ *
+ * @param publicId the public identifier to use
+ * @param systemId the system identifier to resolve
+ * @return An input source to the entity or null if not handled
+ * @throws IOException an error reading the stream
+ */
+ public InputSource resolveEntity(String publicId, String systemId)
+ throws IOException {
+
+ URL resource = null;
+ if( AFP_DTD_1_2_ID.equals(publicId) ) {
+ resource = getResource( AFP_DTD_1_2_RESOURCE );
+ } else if( AFP_DTD_1_1_ID.equals(publicId) ) {
+ resource = getResource( AFP_DTD_1_1_RESOURCE );
+ } else if( AFP_DTD_1_0_ID.equals(publicId) ) {
+ throw new FontRuntimeException(
+ "The AFP Installed Font Definition 1.0 DTD is not longer supported" );
+ } else if( systemId != null && systemId.indexOf("afp-fonts.dtd") >= 0 ) {
+ throw new FontRuntimeException(
+ "The AFP Installed Font Definition DTD must be specified using the public id" );
+ } else {
+ return null;
+ }
+
+ InputSource inputSource = new InputSource( resource.openStream() );
+ inputSource.setPublicId( publicId );
+ inputSource.setSystemId( systemId );
+
+ return inputSource;
+ }
+
+ /**
+ * Returns the URL of a resource on the classpath
+ * @param resourceName the path to the resource relative to the root of the
+ * classpath.
+ * @return the URL of the required resource
+ * @throws FontRuntimeException if the resource could not be found.
+ */
+ private URL getResource( String resourcePath ) {
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ if (cl == null) {
+ cl = ClassLoader.getSystemClassLoader();
+ }
+
+ URL resource = cl.getResource( resourcePath );
+ if( resource == null ) {
+ throw new FontRuntimeException( "Resource " + resourcePath +
+ " could not be found on the classpath" );
+ }
+
+ return resource;
+ }
+}
diff --git a/src/sandbox/org/apache/fop/render/afp/tools/StringUtils.java b/src/sandbox/org/apache/fop/render/afp/tools/StringUtils.java
new file mode 100644
index 000000000..67b578446
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/tools/StringUtils.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tools;
+
+/**
+ * Library of utility methods useful in dealing with strings.
+ *
+ */
+public class StringUtils {
+
+ /**
+ * Padds the string to the left with the given character for
+ * the specified length.
+ * @param input The input string.
+ * @param padding The char used for padding.
+ * @param length The length of the new string.
+ * @return The padded string.
+ */
+ public static String lpad(String input, char padding, int length) {
+
+ if (input == null) {
+ input = new String();
+ }
+
+ if (input.length() >= length) {
+ return input;
+ } else {
+ StringBuffer result = new StringBuffer();
+ int numChars = length - input.length();
+ for (int i = 0; i < numChars; i++) {
+ result.append(padding);
+ }
+ result.append(input);
+ return result.toString();
+ }
+ }
+
+ /**
+ * Padds the string to the right with the given character for
+ * the specified length.
+ * @param input The input string.
+ * @param padding The char used for padding.
+ * @param length The length of the new string.
+ * @return The padded string.
+ */
+ public static String rpad(String input, char padding, int length) {
+
+ if (input == null) {
+ input = new String();
+ }
+
+ if (input.length() >= length) {
+ return input;
+ } else {
+ StringBuffer result = new StringBuffer(input);
+ int numChars = length - input.length();
+ for (int i = 0; i < numChars; i++) {
+ result.append(padding);
+ }
+ return result.toString();
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/afp/tools/StructuredFieldReader.java b/src/sandbox/org/apache/fop/render/afp/tools/StructuredFieldReader.java
new file mode 100644
index 000000000..7df320c27
--- /dev/null
+++ b/src/sandbox/org/apache/fop/render/afp/tools/StructuredFieldReader.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tools;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A helper class to read structured fields from a MO:DCA document. Each
+ * component of a mixed object document is explicitly defined and delimited
+ * in the data. This is accomplished through the use of MO:DCA data structures,
+ * called structured fields. Structured fields are used to envelop document
+ * components and to provide commands and information to applications using
+ * the data. Structured fields may contain one or more parameters. Each
+ * parameter provides one value from a set of values defined by the architecture.
+ * <p/>
+ * MO:DCA structured fields consist of two parts: an introducer that identifies
+ * the length and type of the structured field, and data that provides the
+ * structured field's effect. The data is contained in a set of parameters,
+ * which can consist of other data structures and data elements. The maximum
+ * length of a structured field is 32767 bytes.
+ * <p/>
+ */
+public class StructuredFieldReader {
+
+ /**
+ * The input stream to read
+ */
+ private InputStream _inputStream = null;
+
+ /**
+ * The constructor for the StructuredFieldReader
+ * @param inputStream the input stream to process
+ */
+ public StructuredFieldReader(InputStream inputStream) {
+
+ _inputStream = inputStream;
+
+ }
+
+ /**
+ * Get the next structured field as identified by the identifer
+ * parameter (this must be a valid MO:DCA structured field.
+ * @param identifier the three byte identifier
+ */
+ public byte[] getNext(byte[] identifier) throws IOException {
+
+ int bufferPointer = 0;
+ byte[] bufferData = new byte[identifier.length + 2];
+ for (int x = 0; x < identifier.length; x++) {
+ bufferData[x] = (byte) 0;
+ }
+
+ int c;
+ while ((c = _inputStream.read()) > -1) {
+
+ bufferData[bufferPointer] = (byte) c;
+
+ // Check the last characters in the buffer
+ int index = 0;
+ boolean found = true;
+
+ for (int i = identifier.length - 1; i > -1; i--) {
+
+ int p = bufferPointer - index;
+ if (p < 0) {
+ p = bufferData.length + p;
+ }
+
+ index++;
+
+ if (identifier[i] != bufferData[p]) {
+ found = false;
+ break;
+ }
+
+ }
+
+ if (found) {
+
+ byte[] length = new byte[2];
+
+ int a = bufferPointer - identifier.length;
+ if (a < 0) {
+ a = bufferData.length + a;
+ }
+
+ int b = bufferPointer - identifier.length - 1;
+ if (b < 0) {
+ b = bufferData.length + b;
+ }
+
+ length[0] = bufferData[b];
+ length[1] = bufferData[a];
+
+ int reclength = ((length[0] & 0xFF) << 8) + (length[1] & 0xFF) - identifier.length -2;
+
+ byte[] retval = new byte[reclength];
+
+ _inputStream.read(retval, 0, reclength);
+
+ return retval;
+
+ }
+
+ bufferPointer++;
+ if (bufferPointer >= bufferData.length) {
+ bufferPointer = 0;
+ }
+
+ }
+
+ return new byte[] {
+ };
+
+ }
+
+}