From: Manuel Mall Date: Thu, 27 Apr 2006 15:08:17 +0000 (+0000) Subject: AFP Renderer as per IP clearance (http://mail-archives.apache.org/mod_mbox/xmlgraphic... X-Git-Tag: fop-0_93~258 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=0040a29ecce57798e6947fdb33750a4dba1afea0;p=xmlgraphics-fop.git AFP Renderer as per IP clearance (http://mail-archives.apache.org/mod_mbox/xmlgraphics-general/200604.mbox/%3c20060426085421.B456.DEV@jeremias-maerki.ch%3e) plus some further corrections and changes made by manuel@apache.org since git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@397562 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/sandbox/META-INF/services/org.apache.fop.render.Renderer b/src/sandbox/META-INF/services/org.apache.fop.render.Renderer index d75e81eb2..dcd2b38c8 100644 --- a/src/sandbox/META-INF/services/org.apache.fop.render.Renderer +++ b/src/sandbox/META-INF/services/org.apache.fop.render.Renderer @@ -1,2 +1,3 @@ +org.apache.fop.render.afp.AFPRendererMaker org.apache.fop.render.pcl.PCLRendererMaker org.apache.fop.render.svg.SVGRendererMaker \ No newline at end of file diff --git a/src/sandbox/org/apache/fop/render/afp/AFPFontAttributes.java b/src/sandbox/org/apache/fop/render/afp/AFPFontAttributes.java new file mode 100644 index 000000000..2bb446c3a --- /dev/null +++ b/src/sandbox/org/apache/fop/render/afp/AFPFontAttributes.java @@ -0,0 +1,110 @@ +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.afp; + +import org.apache.fop.render.afp.fonts.AFPFont; +import org.apache.fop.render.afp.tools.BinaryUtils; + +/** + * This class encapsulates the font atributes that need to be included + * in the AFP data stream. This class does not assist in converting the + * font attributes to AFP code pages and character set values. + * + */ +public class AFPFontAttributes { + + /** + * The font reference byte + */ + private byte _fontReference; + + /** + * The font key + */ + private String _fontKey; + + /** + * The font + */ + private AFPFont _font; + + /** + * The point size + */ + private int _pointSize; + + /** + * Constructor for the AFPFontAttributes + * @param fontKey the font key + * @param font the font + * @param pointSize the point size + */ + public AFPFontAttributes( + + String fontKey, + AFPFont font, + int pointSize) { + + _fontKey = fontKey; + _font = font; + _pointSize = pointSize; + + } + /** + * @return the font + */ + public AFPFont getFont() { + return _font; + } + + /** + * @return the FontKey attribute + */ + public String getFontKey() { + + return _fontKey + _pointSize; + + } + + /** + * @return the point size attribute + */ + public int getPointSize() { + return _pointSize; + } + + /** + * @return the FontReference attribute + */ + public byte getFontReference() { + return _fontReference; + } + + /** + * Sets the FontReference attribute + * @param fontReference the FontReference to set + */ + public void setFontReference(int fontReference) { + + String id = String.valueOf(fontReference); + _fontReference = BinaryUtils.convert(id)[0]; + + } + +} diff --git a/src/sandbox/org/apache/fop/render/afp/AFPFontColor.java b/src/sandbox/org/apache/fop/render/afp/AFPFontColor.java new file mode 100644 index 000000000..be3f678e3 --- /dev/null +++ b/src/sandbox/org/apache/fop/render/afp/AFPFontColor.java @@ -0,0 +1,169 @@ +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.afp; + +import java.awt.Color; +import org.apache.fop.datatypes.ColorType; + +/** + * AFP only supports very basic colours and this object provides a simple + * bean for the colour attributes. + * + */ +public class AFPFontColor { + + /** + * Red value. + */ + private int _red = 0; + + /** + * Green value. + */ + private int _green = 0; + + /** + * Blue value. + */ + private int _blue = 0; + + /** + * Constructor for the AFPColor Object + * @param red The red color intensity (0-255) + * @param green The green color intensity (0-255) + * @param blue The blue color intensity (0-255) + */ + public AFPFontColor(int red, int green, int blue) { + + _red = red; + _green = green; + _blue = blue; + + } + + /** + * Constructor for the AFPColor Object + * @param col the org.apache.fop.datatypes.ColorType object + */ + public AFPFontColor(ColorType col) { + + _red = (int)(col.getRed() * 255); + _green = (int)(col.getGreen() * 255); + _blue = (int)(col.getBlue() * 255); + + } + + /** + * Constructor for the AFPColor Object + * @param col The java.awt.Color object + */ + public AFPFontColor(Color col) { + + _red = col.getRed(); + _green = col.getGreen(); + _blue = col.getBlue(); + + } + + /** + * Returns the blue attribute + * @return int + */ + public int getBlue() { + return _blue; + } + + /** + * Returns the green attribute + * @return int + */ + public int getGreen() { + return _green; + } + + /** + * Returns the red attribute + * @return int + */ + public int getRed() { + return _red; + } + + /** + * Sets the blue attribute + * @param blue The blue value to set + */ + public void setBlue(int blue) { + _blue = blue; + } + + /** + * Sets the green attribute + * @param green The green value to set + */ + public void setGreen(int green) { + _green = green; + } + + /** + * Sets the red attribute + * @param red The red value to set + */ + public void setRed(int red) { + _red = red; + } + + /** + * Sets this color object to the same values + * as the given object. + * @param col the source color + */ + public void setTo(AFPFontColor col) { + _red = col.getRed(); + _green = col.getGreen(); + _blue = col.getBlue(); + } + + /** + * Checks whether this object is equal to the parameter passed + * as an argument. If the parameter is an instance of AFPColor + * then the value are compared, otherwise the generalized equals + * method is invoked on the parent class. + * + * @param obj the object to compare + * @return boolean true if the object is equal + */ + public boolean equals(Object obj) { + + if (obj instanceof AFPFontColor) { + AFPFontColor c = (AFPFontColor) obj; + if (c.getRed() == _red + && c.getGreen() == _green + && c.getBlue() == _blue) { + return true; + } else { + return false; + } + } else { + return super.equals(obj); + } + + } + +} diff --git a/src/sandbox/org/apache/fop/render/afp/AFPRenderer.java b/src/sandbox/org/apache/fop/render/afp/AFPRenderer.java new file mode 100644 index 000000000..e4505d050 --- /dev/null +++ b/src/sandbox/org/apache/fop/render/afp/AFPRenderer.java @@ -0,0 +1,1796 @@ +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.afp; + +import java.awt.Color; +import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.MimeConstants; +import org.apache.fop.area.Block; +import org.apache.fop.area.BlockViewport; +import org.apache.fop.area.BodyRegion; +import org.apache.fop.area.CTM; +import org.apache.fop.area.OffDocumentItem; +import org.apache.fop.area.PageViewport; +import org.apache.fop.area.RegionReference; +import org.apache.fop.area.RegionViewport; +import org.apache.fop.area.Trait; +import org.apache.fop.area.inline.Character; +import org.apache.fop.area.inline.Leader; +import org.apache.fop.area.inline.Image; +import org.apache.fop.area.inline.SpaceArea; +import org.apache.fop.area.inline.TextArea; +import org.apache.fop.area.inline.WordArea; +import org.apache.fop.datatypes.ColorType; +import org.apache.fop.fo.Constants; +import org.apache.fop.fo.extensions.ExtensionAttachment; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontMetrics; +import org.apache.fop.fonts.FontTriplet; +import org.apache.fop.fonts.FontUtil; +import org.apache.fop.fonts.Typeface; +import org.apache.fop.fonts.base14.Courier; +import org.apache.fop.fonts.base14.Helvetica; +import org.apache.fop.fonts.base14.TimesRoman; +import org.apache.fop.image.FopImage; +import org.apache.fop.image.ImageFactory; +import org.apache.fop.image.TIFFImage; +import org.apache.fop.image.XMLImage; +import org.apache.fop.render.AbstractPathOrientedRenderer; +import org.apache.fop.render.Graphics2DAdapter; +import org.apache.fop.render.afp.extensions.AFPElementMapping; +import org.apache.fop.render.afp.extensions.AFPPageSetup; +import org.apache.fop.render.afp.fonts.AFPFontInfo; +import org.apache.fop.render.afp.fonts.AFPFont; +import org.apache.fop.render.afp.fonts.CharacterSet; +import org.apache.fop.render.afp.fonts.FopCharacterSet; +import org.apache.fop.render.afp.fonts.OutlineFont; +import org.apache.fop.render.afp.fonts.RasterFont; +import org.apache.fop.render.afp.modca.AFPConstants; +import org.apache.fop.render.afp.modca.AFPDataStream; +import org.apache.fop.render.afp.modca.ImageObject; +import org.apache.fop.render.afp.modca.PageObject; + + +/** + * This is an implementation of a FOP Renderer that renders areas to AFP. + *

+ * 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. + *

+ * + * Note: There are specific extensions that have been added to the + * FO. They are specific to their location within the FO and have to be + * processed accordingly (ie. at the start or end of the page). + * + */ +public class AFPRenderer extends AbstractPathOrientedRenderer { + + /** + * AFP factor for a 240 resolution = 72000/240 = 300 + */ + private static final int DPI_CONVERSION_FACTOR_240 = 300; + + /** + * The afp data stream object responsible for generating afp data + */ + private AFPDataStream _afpDataStream = null; + + /** + * The map of afp root extensions + */ + private HashMap _rootExtensionMap = null; + + /** + * The map of page segments + */ + private HashMap _pageSegmentsMap = null; + + /** + * The fonts on the current page + */ + private HashMap _currentPageFonts = null; + + /** + * The current color object + */ + private AFPFontColor _currentColor = null; + + /** + * The page font number counter, used to determine the next font reference + */ + private int _pageFontCounter = 0; + + /** + * The current font family + */ + private String _currentFontFamily = ""; + + /** + * The current font size + */ + private int _currentFontSize = 0; + + /** + * The Options to be set on the AFPRenderer + */ + private Map _afpOptions = null; + + /** + * The page width + */ + private int _pageWidth = 0; + + /** + * The page height + */ + private int _pageHeight = 0; + + /** + * The current page sequence id + */ + private String _pageSequenceId = null; + + /** + * The portrait rotation + */ + private int _portraitRotation = 0; + + /** + * The landscape rotation + */ + private int _landscapeRotation = 270; + + /** + * The line cache, avoids drawing duplicate lines in tables. + */ + private HashSet _lineCache = null; + + /** + * The current x position for line drawing + */ + private float _x; + + /** + * The current y position for line drawing + */ + private float _y; + + /** + * The map of saved incomplete pages + */ + private Map _pages = null; + + /** + * Flag to the set the output object type for images + */ + private boolean colorImages = false; + + /** + * Default value for image depth + */ + private int bitsPerPixel = 8; + + /** + * Constructor for AFPRenderer. + */ + public AFPRenderer() { + super(); + } + + /** + * Set up the font info + * + * @param inFontInfo font info to set up + */ + public void setupFontInfo(FontInfo inFontInfo) { + this.fontInfo = inFontInfo; + int num = 1; + if (this.fontList != null && this.fontList.size() > 0) { + for (Iterator it = this.fontList.iterator(); it.hasNext(); ) { + AFPFontInfo afi = (AFPFontInfo)it.next(); + AFPFont bf = (AFPFont)afi.getAFPFont(); + for (Iterator it2 = afi.getFontTriplets().iterator(); it2.hasNext(); ) { + FontTriplet ft = (FontTriplet)it2.next(); + this.fontInfo.addFontProperties("F" + num, ft.getName() + , ft.getStyle(), ft.getWeight()); + this.fontInfo.addMetrics("F" + num, bf); + num++; + } + } + } else { + log.warn("No AFP fonts configured - using default setup"); + } + if (this.fontInfo.fontLookup("sans-serif", "normal", 400) == null) { + CharacterSet cs = new FopCharacterSet("T1V10500", "Cp500", "CZH200 ", 1, new Helvetica()); + AFPFont bf = new OutlineFont("Helvetica", cs); + this.fontInfo.addFontProperties("F" + num, "sans-serif", "normal", 400); + this.fontInfo.addMetrics("F" + num, bf); + num++; + } + if (this.fontInfo.fontLookup("serif", "normal", 400) == null) { + CharacterSet cs = new FopCharacterSet("T1V10500", "Cp500", "CZN200 ", 1, new TimesRoman()); + AFPFont bf = new OutlineFont("Helvetica", cs); + this.fontInfo.addFontProperties("F" + num, "serif", "normal", 400); + this.fontInfo.addMetrics("F" + num, bf); + num++; + } + if (this.fontInfo.fontLookup("monospace", "normal", 400) == null) { + CharacterSet cs = new FopCharacterSet("T1V10500", "Cp500", "CZ4200 ", 1, new Courier()); + AFPFont bf = new OutlineFont("Helvetica", cs); + this.fontInfo.addFontProperties("F" + num, "monospace", "normal", 400); + this.fontInfo.addMetrics("F" + num, bf); + num++; + } + if (this.fontInfo.fontLookup("any", "normal", 400) == null) { + FontTriplet ft = this.fontInfo.fontLookup("sans-serif", "normal", 400); + this.fontInfo.addFontProperties(this.fontInfo.getInternalFontKey(ft), "any", "normal", 400); + } + } + + /** + */ + private AFPFontInfo buildFont(Configuration fontCfg, String _path) + throws ConfigurationException { + + Configuration[] triple = fontCfg.getChildren("font-triplet"); + List tripleList = new java.util.ArrayList(); + if (triple.length == 0) { + log.error("Mandatory font configuration element ' + * + * The region may clip the area and it establishes a position from where + * the region is placed.

+ * + * @param port The region viewport to be rendered + */ + public void renderRegionViewport(RegionViewport port) { + if (port != null) { + Rectangle2D view = port.getViewArea(); + // The CTM will transform coordinates relative to + // this region-reference area into page coords, so + // set origin for the region to 0,0. + currentBPPosition = 0; + currentIPPosition = 0; + + RegionReference regionReference = port.getRegionReference(); + handleRegionTraits(port); + + /* + _afpDataStream.startOverlay(mpts2units(view.getX()) + , mpts2units(view.getY()) + , mpts2units(view.getWidth()) + , mpts2units(view.getHeight()) + , rotation); + */ + + pushViewPortPos(new ViewPortPos(view, regionReference.getCTM())); + + if (regionReference.getRegionClass() == FO_REGION_BODY) { + renderBodyRegion((BodyRegion) regionReference); + } else { + renderRegion(regionReference); + } + /* + _afpDataStream.endOverlay(); + */ + popViewPortPos(); + } + } + + /** + * @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List) + */ + protected void renderBlockViewport(BlockViewport bv, List children) { + // clip and position viewport if necessary + + // save positions + int saveIP = currentIPPosition; + int saveBP = currentBPPosition; + //String saveFontName = currentFontName; + + CTM ctm = bv.getCTM(); + int borderPaddingStart = bv.getBorderAndPaddingWidthStart(); + int borderPaddingBefore = bv.getBorderAndPaddingWidthBefore(); + float x, y; + x = (float)(bv.getXOffset() + containingIPPosition) / 1000f; + y = (float)(bv.getYOffset() + containingBPPosition) / 1000f; + //This is the content-rect + float width = (float)bv.getIPD() / 1000f; + float height = (float)bv.getBPD() / 1000f; + + + if (bv.getPositioning() == Block.ABSOLUTE + || bv.getPositioning() == Block.FIXED) { + + currentIPPosition = bv.getXOffset(); + currentBPPosition = bv.getYOffset(); + + //For FIXED, we need to break out of the current viewports to the + //one established by the page. We save the state stack for restoration + //after the block-container has been painted. See below. + List breakOutList = null; + if (bv.getPositioning() == Block.FIXED) { + breakOutList = breakOutOfStateStack(); + } + + CTM tempctm = new CTM(containingIPPosition, containingBPPosition); + ctm = tempctm.multiply(ctm); + + //Adjust for spaces (from margin or indirectly by start-indent etc. + x += bv.getSpaceStart() / 1000f; + currentIPPosition += bv.getSpaceStart(); + + y += bv.getSpaceBefore() / 1000f; + currentBPPosition += bv.getSpaceBefore(); + + float bpwidth = (borderPaddingStart + bv.getBorderAndPaddingWidthEnd()) / 1000f; + float bpheight = (borderPaddingBefore + bv.getBorderAndPaddingWidthAfter()) / 1000f; + + drawBackAndBorders(bv, x, y, width + bpwidth, height + bpheight); + + //Now adjust for border/padding + currentIPPosition += borderPaddingStart; + currentBPPosition += borderPaddingBefore; + + Rectangle2D clippingRect = null; + clippingRect = new Rectangle(currentIPPosition, currentBPPosition, + bv.getIPD(), bv.getBPD()); + + // startVParea(ctm, clippingRect); + pushViewPortPos(new ViewPortPos(clippingRect, ctm)); + currentIPPosition = 0; + currentBPPosition = 0; + renderBlocks(bv, children); + //endVParea(); + popViewPortPos(); + + if (breakOutList != null) { + restoreStateStackAfterBreakOut(breakOutList); + } + + currentIPPosition = saveIP; + currentBPPosition = saveBP; + } else { + + currentBPPosition += bv.getSpaceBefore(); + + //borders and background in the old coordinate system + handleBlockTraits(bv); + + //Advance to start of content area + currentIPPosition += bv.getStartIndent(); + + CTM tempctm = new CTM(containingIPPosition, currentBPPosition); + ctm = tempctm.multiply(ctm); + + //Now adjust for border/padding + currentBPPosition += borderPaddingBefore; + + Rectangle2D clippingRect = null; + clippingRect = new Rectangle(currentIPPosition, currentBPPosition, + bv.getIPD(), bv.getBPD()); + + //startVParea(ctm, clippingRect); + pushViewPortPos(new ViewPortPos(clippingRect, ctm)); + + currentIPPosition = 0; + currentBPPosition = 0; + renderBlocks(bv, children); + //endVParea(); + popViewPortPos(); + + currentIPPosition = saveIP; + currentBPPosition = saveBP; + + currentBPPosition += (int)(bv.getAllocBPD()); + } + //currentFontName = saveFontName; + } + + /** + * @see org.apache.fop.render.Renderer#renderPage(PageViewport) + */ + public void renderPage(PageViewport page) { + + // initializeRootExtensions(page); + + _currentFontFamily = ""; + _currentFontSize = 0; + _pageFontCounter = 0; + _currentPageFonts.clear(); + _lineCache = new HashSet(); + + Rectangle2D bounds = page.getViewArea(); + + _pageWidth = mpts2units(bounds.getWidth()); + _pageHeight = mpts2units(bounds.getHeight()); + + if (_pages != null && _pages.containsKey(page)) { + + _afpDataStream.restorePage((PageObject)_pages.remove(page)); + + } else { + // renderPageGroupExtensions(page); + + _afpDataStream.startPage(_pageWidth, _pageHeight, 0); + + renderPageObjectExtensions(page); + + } + + pushViewPortPos(new ViewPortPos()); + + renderPageAreas(page.getPage()); + + Iterator i = _currentPageFonts.values().iterator(); + while (i.hasNext()) { + AFPFontAttributes afpFontAttributes = (AFPFontAttributes) i.next(); + + _afpDataStream.createFont( + afpFontAttributes.getFontReference(), + afpFontAttributes.getFont(), + afpFontAttributes.getPointSize()); + + } + + try { + _afpDataStream.endPage(); + } catch (IOException ioex) { + // TODO What shall we do? + } + + popViewPortPos(); + + } + + /** + * Clip using the current path. + * @see org.apache.fop.render.AbstractRenderer#clip + */ + public void clip() { + // TODO + } + + /** + * Clip using a rectangular area. + * @see org.apache.fop.render.AbstractRenderer#clipRect(float, float, float, float) + */ + public void clipRect(float x, float y, float width, float height) { + // TODO + } + + /** + * Moves the current point to (x, y), omitting any connecting line segment. + * @see org.apache.fop.render.AbstractRenderer#moveTo(float, float) + */ + public void moveTo(float x, float y) { + // TODO + } + + /** + * Appends a straight line segment from the current point to (x, y). The + * new current point is (x, y). + * @see org.apache.fop.render.AbstractRenderer#lineTo(float, float) + */ + public void lineTo(float x, float y) { + // TODO + } + + /** + * Closes the current subpath by appending a straight line segment from + * the current point to the starting point of the subpath. + * @see org.apache.fop.render.AbstractRenderer#closePath + */ + public void closePath() { + // TODO + } + + /** + * Fill a rectangular area. + * @see org.apache.fop.render.AbstractRenderer#fillRect(float, float, float, float) + */ + public void fillRect(float x, float y, float width, float height) { + /* + _afpDataStream.createShading( + pts2units(x), + pts2units(y), + pts2units(width), + pts2units(height), + _currentColor.getRed(), + _currentColor.getGreen(), + _currentColor.getBlue()); + */ + _afpDataStream.createLine( + pts2units(x), + pts2units(y), + pts2units(x + width), + pts2units(y), + pts2units(height), + _currentColor); + } + + /** + * Draw a border segment of an XSL-FO style border. + * @see org.apache.fop.render.AbstractRenderer#drawBorderLine(float, float, float, float, + * boolean, boolean, int, ColorType) + */ + public void drawBorderLine(float x1, float y1, float x2, float y2, + boolean horz, boolean startOrBefore, int style, ColorType col) { + float w = x2 - x1; + float h = y2 - y1; + if ((w < 0) || (h < 0)) { + log.error("Negative extent received. Border won't be painted."); + return; + } + switch (style) { + case Constants.EN_DOUBLE: + if (horz) { + float h3 = h / 3; + float ym1 = y1; + float ym2 = ym1 + h3 + h3; + _afpDataStream.createLine( + pts2units(x1), + pts2units(ym1), + pts2units(x2), + pts2units(ym1), + pts2units(h3), + new AFPFontColor(col) + ); + _afpDataStream.createLine( + pts2units(x1), + pts2units(ym2), + pts2units(x2), + pts2units(ym2), + pts2units(h3), + new AFPFontColor(col) + ); + } else { + float w3 = w / 3; + float xm1 = x1; + float xm2 = xm1 + w3 + w3; + _afpDataStream.createLine( + pts2units(xm1), + pts2units(y1), + pts2units(xm1), + pts2units(y2), + pts2units(w3), + new AFPFontColor(col) + ); + _afpDataStream.createLine( + pts2units(xm2), + pts2units(y1), + pts2units(xm2), + pts2units(y2), + pts2units(w3), + new AFPFontColor(col) + ); + } + break; + case Constants.EN_DASHED: + if (horz) { + float w2 = 2 * h; + while (x1 + w2 < x2) { + _afpDataStream.createLine( + pts2units(x1), + pts2units(y1), + pts2units(x1 + w2), + pts2units(y1), + pts2units(h), + new AFPFontColor(col) + ); + x1 += 2 * w2; + } + } else { + float h2 = 2 * w; + while (y1 + h2 < y2) { + _afpDataStream.createLine( + pts2units(x1), + pts2units(y1), + pts2units(x1), + pts2units(y1 + h2), + pts2units(w), + new AFPFontColor(col) + ); + y1 += 2 * h2; + } + } + break; + case Constants.EN_DOTTED: + if (horz) { + while (x1 + h < x2) { + _afpDataStream.createLine( + pts2units(x1), + pts2units(y1), + pts2units(x1 + h), + pts2units(y1), + pts2units(h), + new AFPFontColor(col) + ); + x1 += 2 * h; + } + } else { + while (y1 + w < y2) { + _afpDataStream.createLine( + pts2units(x1), + pts2units(y1), + pts2units(x1), + pts2units(y1 + w), + pts2units(w), + new AFPFontColor(col) + ); + y1 += 2 * w; + } + } + break; + case Constants.EN_GROOVE: + case Constants.EN_RIDGE: + { + float colFactor = (style == EN_GROOVE ? 0.4f : -0.4f); + Color c = toColor(col); + if (horz) { + Color uppercol = lightenColor(c, -colFactor); + Color lowercol = lightenColor(c, colFactor); + float h3 = h / 3; + float ym1 = y1; + _afpDataStream.createLine( + pts2units(x1), + pts2units(ym1), + pts2units(x2), + pts2units(ym1), + pts2units(h3), + new AFPFontColor(uppercol) + ); + _afpDataStream.createLine( + pts2units(x1), + pts2units(ym1 + h3), + pts2units(x2), + pts2units(ym1 + h3), + pts2units(h3), + new AFPFontColor(c) + ); + _afpDataStream.createLine( + pts2units(x1), + pts2units(ym1 + h3 + h3), + pts2units(x2), + pts2units(ym1 + h3 + h3), + pts2units(h3), + new AFPFontColor(lowercol) + ); + } else { + Color leftcol = lightenColor(c, -colFactor); + Color rightcol = lightenColor(c, colFactor); + float w3 = w / 3; + float xm1 = x1 + (w3 / 2); + _afpDataStream.createLine( + pts2units(xm1), + pts2units(y1), + pts2units(xm1), + pts2units(y2), + pts2units(w3), + new AFPFontColor(leftcol) + ); + _afpDataStream.createLine( + pts2units(xm1 + w3), + pts2units(y1), + pts2units(xm1 + w3), + pts2units(y2), + pts2units(w3), + new AFPFontColor(c) + ); + _afpDataStream.createLine( + pts2units(xm1 + w3 + w3), + pts2units(y1), + pts2units(xm1 + w3 + w3), + pts2units(y2), + pts2units(w3), + new AFPFontColor(rightcol) + ); + } + break; + } + case Constants.EN_HIDDEN: + break; + case Constants.EN_INSET: + case Constants.EN_OUTSET: + default: + _afpDataStream.createLine( + pts2units(x1), + pts2units(y1), + pts2units(horz ? x2 : x1), + pts2units(horz ? y1 : y2), + pts2units(Math.abs(horz ? (y2 - y1) : (x2 - x1))), + new AFPFontColor(col)); + } + } + + /** + * Draw an image at the indicated location. + * @see org.apache.fop.render.AbstractRenderer#drawImage(String, Rectangle2D) + */ + public void drawImage(String url, Rectangle2D pos) { + String name = null; + if (_pageSegmentsMap != null) { + name = (String)_pageSegmentsMap.get(url); + } + if (name != null) { + int x = mpts2units(pos.getX() + currentIPPosition); + int y = mpts2units(pos.getY() + currentBPPosition); + _afpDataStream.createIncludePageSegment(name, x, y); + } else { + url = ImageFactory.getURL(url); + ImageFactory fact = userAgent.getFactory().getImageFactory(); + FopImage fopimage = fact.getImage(url, userAgent); + if (fopimage == null) { + return; + } + if (!fopimage.load(FopImage.DIMENSIONS)) { + return; + } + String mime = fopimage.getMimeType(); + if ("text/xml".equals(mime)) { + } else if (MimeConstants.MIME_SVG.equals(mime)) { + if (!fopimage.load(FopImage.ORIGINAL_DATA)) { + return; + } + int x = mpts2units(pos.getX() + currentIPPosition); + int y = mpts2units(pos.getY() + currentBPPosition); + int w = mpts2units(pos.getWidth()); + int h = mpts2units(pos.getHeight()); + ImageObject io = _afpDataStream.getImageObject(x, y, w, h); + io.setImageParameters( + (int)(fopimage.getHorizontalResolution() * 10), + (int)(fopimage.getVerticalResolution() * 10), + fopimage.getWidth(), + fopimage.getHeight() + ); + if (colorImages) { + io.setImageIDESize((byte)24); + io.setImageData(SVGConverter.convertToTIFF((XMLImage)fopimage)); + } else { + convertToGrayScaleImage(io, SVGConverter.convertToTIFF((XMLImage)fopimage)); + } + } else if (MimeConstants.MIME_EPS.equals(mime)) { + /* + } else if (MimeConstants.MIME_JPEG.equals(mime)) { + if (!fopimage.load(FopImage.ORIGINAL_DATA)) { + return; + } + fact.releaseImage(url, userAgent); + + int x = mpts2units(pos.getX() + currentIPPosition); + int y = mpts2units(pos.getY() + currentBPPosition); + int w = mpts2units(pos.getWidth()); + int h = mpts2units(pos.getHeight()); + ImageObject io = _afpDataStream.getImageObject(); + io.setImageViewport(x, y, w, h); + io.setImageParameters( + (int)(fopimage.getHorizontalResolution() * 10), + (int)(fopimage.getVerticalResolution() * 10), + fopimage.getWidth(), + fopimage.getHeight() + ); + io.setImageIDESize((byte)fopimage.getBitsPerPixel()); + io.setImageEncoding((byte)0x83); + io.setImageData(fopimage.getRessourceBytes()); + */ + } else if (MimeConstants.MIME_TIFF.equals(mime) + && fopimage instanceof TIFFImage) { + TIFFImage tiffImage = (TIFFImage) fopimage; + int x = mpts2units(pos.getX() + currentIPPosition); + int y = mpts2units(pos.getY() + currentBPPosition); + int w = mpts2units(pos.getWidth()); + int h = mpts2units(pos.getHeight()); + ImageObject io = _afpDataStream.getImageObject(x, y, w, h); + io.setImageParameters( + (int)(fopimage.getHorizontalResolution() * 10), + (int)(fopimage.getVerticalResolution() * 10), + fopimage.getWidth(), + fopimage.getHeight() + ); + if (tiffImage.getStripCount() == 1) { + int comp = tiffImage.getCompression(); + if (comp == 3) { + if (!fopimage.load(FopImage.ORIGINAL_DATA)) { + return; + } + io.setImageEncoding((byte)0x81); + io.setImageData(fopimage.getRessourceBytes()); + } else if (comp == 4) { + if (!fopimage.load(FopImage.ORIGINAL_DATA)) { + return; + } + io.setImageEncoding((byte)0x82); + io.setImageData(fopimage.getRessourceBytes()); + } else { + if (!fopimage.load(FopImage.BITMAP)) { + return; + } + convertToGrayScaleImage(io, fopimage.getBitmaps()); + } + } + else + { + if (!fopimage.load(FopImage.BITMAP)) { + return; + } + convertToGrayScaleImage(io, fopimage.getBitmaps()); + } + } else { + if (!fopimage.load(FopImage.BITMAP)) { + return; + } + fact.releaseImage(url, userAgent); + + int x = mpts2units(pos.getX() + currentIPPosition); + int y = mpts2units(pos.getY() + currentBPPosition); + int w = mpts2units(pos.getWidth()); + int h = mpts2units(pos.getHeight()); + ImageObject io = _afpDataStream.getImageObject(x, y, w, h); + io.setImageParameters( + (int)(fopimage.getHorizontalResolution() * 10), + (int)(fopimage.getVerticalResolution() * 10), + fopimage.getWidth(), + fopimage.getHeight() + ); + if (colorImages) { + io.setImageIDESize((byte)24); + io.setImageData(fopimage.getBitmaps()); + } else { + convertToGrayScaleImage(io, fopimage.getBitmaps()); + } + } + } + } + + /** + * Establishes a new foreground or fill color. + * @see org.apache.fop.render.AbstractRenderer#updateColor(ColorType, boolean) + */ + public void updateColor(ColorType col, boolean fill) { + if (fill) { + _currentColor = new AFPFontColor(col); + } + } + + /** + * Restores the state stack after a break out. + * @param breakOutList the state stack to restore. + */ + public void restoreStateStackAfterBreakOut(List breakOutList) { + + } + + /** + * Breaks out of the state stack to handle fixed block-containers. + * @return the saved state stack to recreate later + */ + public List breakOutOfStateStack() { + return null; + } + + /** Saves the graphics state of the rendering engine. */ + public void saveGraphicsState() { + + } + + /** Restores the last graphics state of the rendering engine. */ + public void restoreGraphicsState() { + + } + + /** Indicates the beginning of a text object. */ + public void beginTextObject() { + + } + + /** Indicates the end of a text object. */ + public void endTextObject() { + + } + + /** + * @see org.apache.fop.render.AbstractRenderer#renderImage(Image, Rectangle2D) + */ + public void renderImage(Image image, Rectangle2D pos) { + String url = image.getURL(); + drawImage(url, pos); + } + + /** + * @see org.apache.fop.render.AbstractRenderer#renderCharacter(Character) + */ + public void renderCharacter(Character ch) { + renderInlineAreaBackAndBorders(ch); + + String name = getInternalFontNameForArea(ch); + _currentFontSize = ((Integer) ch.getTrait(Trait.FONT_SIZE)).intValue(); + AFPFont tf = (AFPFont) fontInfo.getFonts().get(name); + _currentFontFamily = name; + + ColorType ct = (ColorType) ch.getTrait(Trait.COLOR); + + int vsci = mpts2units(tf.getWidth(' ', _currentFontSize) / 1000 + + ch.getTextWordSpaceAdjust() + + ch.getTextLetterSpaceAdjust()); + + // word.getOffset() = only height of text itself + // currentBlockIPPosition: 0 for beginning of line; nonzero + // where previous line area failed to take up entire allocated space + int rx = currentIPPosition + ch.getBorderAndPaddingWidthStart(); + int bl = currentBPPosition + ch.getOffset() + ch.getBaselineOffset(); + + // Set letterSpacing + //float ls = fs.getLetterSpacing() / this.currentFontSize; + + String worddata = ch.getChar(); + + // Create an AFPFontAttributes object from the current font details + AFPFontAttributes afpFontAttributes = + new AFPFontAttributes(name, tf,_currentFontSize); + + if (!_currentPageFonts.containsKey(afpFontAttributes.getFontKey())) { + // Font not found on current page, so add the new one + _pageFontCounter++; + afpFontAttributes.setFontReference(_pageFontCounter); + _currentPageFonts.put( + afpFontAttributes.getFontKey(), + afpFontAttributes); + + } else { + // Use the previously stored font attributes + afpFontAttributes = + (AFPFontAttributes) _currentPageFonts.get(afpFontAttributes.getFontKey()); + + } + + // Try and get the encoding to use for the font + String encoding = null; + + try { + encoding = tf.getCharacterSet(_currentFontSize).getEncoding(); + } catch (Throwable ex) { + encoding = AFPConstants.EBCIDIC_ENCODING; + log.warn( + "renderTextArea():: Error getting encoding for font " + + " - using default encoding " + + encoding); + } + + try { + _afpDataStream.createText( + afpFontAttributes.getFontReference(), + mpts2units(rx), + mpts2units(bl), + new AFPFontColor(ct), + vsci, + mpts2units(ch.getTextLetterSpaceAdjust()), + worddata.getBytes(encoding)); + + } catch (UnsupportedEncodingException usee) { + log.error( + "renderWordArea:: Font " + + afpFontAttributes.getFontKey() + + " caused UnsupportedEncodingException"); + + } + + super.renderCharacter(ch); + + renderTextDecoration(tf, _currentFontSize, ch, bl, rx); + + } + + /** + * @see org.apache.fop.render.AbstractRenderer#renderText(TextArea) + */ + public void renderText(TextArea text) { + renderInlineAreaBackAndBorders(text); + + String name = getInternalFontNameForArea(text); + _currentFontSize = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue(); + AFPFont tf = (AFPFont) fontInfo.getFonts().get(name); + + ColorType ct = (ColorType) text.getTrait(Trait.COLOR); + + int vsci = mpts2units(tf.getWidth(' ', _currentFontSize) / 1000 + + text.getTextWordSpaceAdjust() + + text.getTextLetterSpaceAdjust()); + + // word.getOffset() = only height of text itself + // currentBlockIPPosition: 0 for beginning of line; nonzero + // where previous line area failed to take up entire allocated space + int rx = currentIPPosition + text.getBorderAndPaddingWidthStart(); + int bl = currentBPPosition + text.getOffset() + text.getBaselineOffset(); + + // Set letterSpacing + //float ls = fs.getLetterSpacing() / this.currentFontSize; + + String worddata = text.getText(); + + // Create an AFPFontAttributes object from the current font details + AFPFontAttributes afpFontAttributes = + new AFPFontAttributes(name, tf, _currentFontSize); + + if (!_currentPageFonts.containsKey(afpFontAttributes.getFontKey())) { + // Font not found on current page, so add the new one + _pageFontCounter++; + afpFontAttributes.setFontReference(_pageFontCounter); + _currentPageFonts.put( + afpFontAttributes.getFontKey(), + afpFontAttributes); + + } else { + // Use the previously stored font attributes + afpFontAttributes = + (AFPFontAttributes) _currentPageFonts.get( + afpFontAttributes.getFontKey()); + } + + // Try and get the encoding to use for the font + String encoding = null; + + try { + encoding = tf.getCharacterSet(_currentFontSize).getEncoding(); + } catch (Throwable ex) { + encoding = AFPConstants.EBCIDIC_ENCODING; + log.warn( + "renderText():: Error getting encoding for font " + + " - using default encoding " + + encoding); + } + + try { + _afpDataStream.createText( + afpFontAttributes.getFontReference(), + mpts2units(rx), + mpts2units(bl), + new AFPFontColor(ct), + vsci, + mpts2units(text.getTextLetterSpaceAdjust()), + worddata.getBytes(encoding)); + } catch (UnsupportedEncodingException usee) { + log.error( + "renderText:: Font " + + afpFontAttributes.getFontKey() + + " caused UnsupportedEncodingException"); + } + + super.renderText(text); + + renderTextDecoration(tf, _currentFontSize, text, bl, rx); + } + + /** + * @see org.apache.fop.render.AbstractRenderer#renderWord(WordArea) + */ + public void renderWord(WordArea word) { + String name = getInternalFontNameForArea(word.getParentArea()); + int size = ((Integer) word.getParentArea().getTrait(Trait.FONT_SIZE)).intValue(); + AFPFont tf = (AFPFont) fontInfo.getFonts().get(name); + + String s = word.getWord(); + + FontMetrics metrics = fontInfo.getMetricsFor(name); + + super.renderWord(word); + } + + /** + * @see org.apache.fop.render.AbstractRenderer#renderSpace(SpaceArea) + */ + public void renderSpace(SpaceArea space) { + String name = getInternalFontNameForArea(space.getParentArea()); + int size = ((Integer) space.getParentArea().getTrait(Trait.FONT_SIZE)).intValue(); + AFPFont tf = (AFPFont) fontInfo.getFonts().get(name); + + String s = space.getSpace(); + + FontMetrics metrics = fontInfo.getMetricsFor(name); + + super.renderSpace(space); + } + + /** + * Render leader area. + * This renders a leader area which is an area with a rule. + * @param area the leader area to render + */ + public void renderLeader(Leader area) { + renderInlineAreaBackAndBorders(area); + + int style = area.getRuleStyle(); + float startx = (currentIPPosition + area.getBorderAndPaddingWidthStart()) / 1000f; + float starty = (currentBPPosition + area.getOffset()) / 1000f; + float endx = (currentIPPosition + area.getBorderAndPaddingWidthStart() + + area.getIPD()) / 1000f; + float ruleThickness = area.getRuleThickness() / 1000f; + ColorType col = (ColorType)area.getTrait(Trait.COLOR); + + switch (style) { + case EN_SOLID: + case EN_DASHED: + case EN_DOUBLE: + case EN_DOTTED: + case EN_GROOVE: + case EN_RIDGE: + drawBorderLine(startx, starty, endx, starty + ruleThickness, + true, true, style, col); + break; + default: + throw new UnsupportedOperationException("rule style not supported"); + } + super.renderLeader(area); + } + + /** + * @see org.apache.fop.render.Renderer#setProducer(String) + */ + public void setProducer(String producer) { + _afpDataStream.setProducer(producer); + } + + /** + * @see org.apache.fop.render.Renderer#setOptions(Map) + */ + public void setOptions(Map options) { + + _afpOptions = options; + + } + + /** + * Determines the orientation from the string representation, this method + * guarantees to return a value of either 0, 90, 180 or 270. + * + * @return the orientation + */ + private int getOrientation(String orientationString) { + + int orientation = 0; + if (orientationString != null && orientationString.length() > 0) { + try { + orientation = Integer.parseInt(orientationString); + } catch (NumberFormatException nfe) { + log.error( + "Cannot use orientation of " + + orientation + + " defaulting to zero."); + orientation = 0; + } + } else { + orientation = 0; + } + switch (orientation) { + case 0 : + break; + case 90 : + break; + case 180 : + break; + case 270 : + break; + default : + log.error( + "Cannot use orientation of " + + orientation + + " defaulting to zero."); + orientation = 0; + break; + } + + return orientation; + + } + + /** + * Sets the rotation to be used for portrait pages, valid values are 0 + * (default), 90, 180, 270. + * + * @param rotation + * The rotation in degrees. + */ + public void setPortraitRotation(int rotation) { + + if (rotation == 0 + || rotation == 90 + || rotation == 180 + || rotation == 270) { + _portraitRotation = rotation; + } else { + throw new IllegalArgumentException("The portrait rotation must be one of the values 0, 90, 180, 270"); + + } + + } + + /** + * Sets the rotation to be used for landsacpe pages, valid values are 0, 90, + * 180, 270 (default). + * + * @param rotation + * The rotation in degrees. + */ + public void setLandscapeRotation(int rotation) { + + if (rotation == 0 + || rotation == 90 + || rotation == 180 + || rotation == 270) { + _landscapeRotation = rotation; + } else { + throw new IllegalArgumentException("The landscape rotation must be one of the values 0, 90, 180, 270"); + + } + + } + + /** + * Get the MIME type of the renderer. + * + * @return The MIME type of the renderer + */ + public String getMimeType() { + return MimeConstants.MIME_AFP; + } + + /** + * Method to render the page extension. + *

+ * + * @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 a NestedRuntimeException 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[] { + }; + + } + +}