From: Manuel Mall
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * + * @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. + *
+ */ +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 aNestedRuntimeException
with the specified detail message.
+ * @param msg The detail message.
+ */
+ public NestedRuntimeException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Construct a NestedRuntimeException
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.
+ *
+ */
+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.
+ *
+ */
+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.
+ *
+ */
+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.
+ *
+ */
+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. 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.
+ *
+ * @author Pete Townsend
+ */
+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.
+ *
+ * Presenting a graphic character on a presentation surface requires
+ * information on the rotation and position of character on the physical
+ * or logical page.
+ *
+ * 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.
+ *
+ */
+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.
+ *
+ */
+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
+ */
+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.
+ *
+ */
+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).
+ *
+ */
+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).
+ * + * + */ +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. + *
+ */ +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. + *+ * 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. + *
+ */ +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 Pete Townsend + */ +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 Pete Townsend + */ +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. + * + */ +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. + * + */ +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. + *+ * 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}. + *
+ * @author Joe Schmetzer + */ +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. + *
+ * 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. + * + */ +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[] { + }; + + } + +}