From df913281dcbfc8f647ff92d89fa0c8632aa5c55d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sat, 20 Feb 2021 10:01:49 +0100 Subject: [PATCH] gnujpdf reformat --- libsrc/gnujpdf/src/gnu/jpdf/BoundingBox.java | 1816 ++++++++--------- libsrc/gnujpdf/src/gnu/jpdf/MyRect.java | 1 + libsrc/gnujpdf/src/gnu/jpdf/PDFAnnot.java | 474 ++--- libsrc/gnujpdf/src/gnu/jpdf/PDFBorder.java | 40 +- libsrc/gnujpdf/src/gnu/jpdf/PDFCatalog.java | 147 +- libsrc/gnujpdf/src/gnu/jpdf/PDFDocument.java | 543 ++--- .../gnujpdf/src/gnu/jpdf/PDFEmbeddedFont.java | 4 +- libsrc/gnujpdf/src/gnu/jpdf/PDFFont.java | 410 ++-- libsrc/gnujpdf/src/gnu/jpdf/PDFGraphics.java | 2 +- libsrc/gnujpdf/src/gnu/jpdf/PDFImage.java | 662 +++--- libsrc/gnujpdf/src/gnu/jpdf/PDFInfo.java | 310 +-- libsrc/gnujpdf/src/gnu/jpdf/PDFJob.java | 679 +++--- libsrc/gnujpdf/src/gnu/jpdf/PDFObject.java | 263 ++- libsrc/gnujpdf/src/gnu/jpdf/PDFOutline.java | 193 +- libsrc/gnujpdf/src/gnu/jpdf/PDFOutput.java | 368 ++-- libsrc/gnujpdf/src/gnu/jpdf/PDFPage.java | 338 +-- libsrc/gnujpdf/src/gnu/jpdf/PDFPageList.java | 121 +- .../gnujpdf/src/gnu/jpdf/PDFPrinterJob.java | 393 ++-- libsrc/gnujpdf/src/gnu/jpdf/PDFStream.java | 115 +- .../gnujpdf/src/gnu/jpdf/PDFStringHelper.java | 92 +- libsrc/gnujpdf/src/gnu/jpdf/PDFXref.java | 125 +- .../src/gnu/jpdf/StringTooLongException.java | 41 +- libsrc/gnujpdf/src/gnu/jpdf/Test.java | 22 +- libsrc/gnujpdf/src/gnu/jpdf/TtfParser.java | 2 - 24 files changed, 3587 insertions(+), 3574 deletions(-) diff --git a/libsrc/gnujpdf/src/gnu/jpdf/BoundingBox.java b/libsrc/gnujpdf/src/gnu/jpdf/BoundingBox.java index d1eed5f6b..ea0af2802 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/BoundingBox.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/BoundingBox.java @@ -26,1000 +26,980 @@ import java.awt.*; import java.util.*; /** - *

This class simplifies the placement of Strings within - * a canvas area where the placement of objects is absolute

+ *

+ * This class simplifies the placement of Strings within a canvas area where the + * placement of objects is absolute

* - *

A BoundingBox is just a Rectangle that knows how to - * find the coordinates for a String based on the desired alignment and - * FontMetrics. For each new String, a new child - * BoundingBox is made that can be subtracted from the - * original box so new Strings can be added

+ *

+ * A BoundingBox is just a Rectangle that knows how to find the + * coordinates for a String based on the desired alignment and + * FontMetrics. For each new String, a new child + * BoundingBox is made that can be subtracted from the original box + * so new Strings can be added

* - *

One of the more helpful features of this class is the string wrap - * feature of getStringBounds. The box returned by that method - * will contain an array of strings that have been broken down to fit the - * box. The box's coordinates and size will reflect the size of the - * entire group of strings if it is laid out as expected. Using the - * returned box and iterating through the array of strings from top to - * bottom, getting new bounding boxes for each one (with upper left - * alignment and no padding) will result in the correct string wrap.

+ *

+ * One of the more helpful features of this class is the string wrap feature of + * getStringBounds. The box returned by that method will contain an + * array of strings that have been broken down to fit the box. The box's + * coordinates and size will reflect the size of the entire group of strings if + * it is laid out as expected. Using the returned box and iterating through the + * array of strings from top to bottom, getting new bounding boxes for each one + * (with upper left alignment and no padding) will result in the correct string + * wrap.

* - *

Note that you will need to have Xvfb running on a Unix server to - * use this class

+ *

+ * Note that you will need to have Xvfb running on a Unix server to use this + * class

* * @author Eric Z. Beard, ericzbeard@hotmail.com * @version $Revision: 1.2 $, $Date: 2007/08/26 18:56:35 $ */ -public class BoundingBox extends Rectangle -{ - /** Percent f line height to space lines */ - public static final int LINE_SPACING_PERCENTAGE = 20; +public class BoundingBox extends Rectangle { - /** Used to a align a String centered vertically */ - public static final int VERT_ALIGN_CENTER = 0; + /** + * Percent f line height to space lines + */ + public static final int LINE_SPACING_PERCENTAGE = 20; - /** Used to align a String at the top of the box */ - public static final int VERT_ALIGN_TOP = 1; + /** + * Used to a align a String centered vertically + */ + public static final int VERT_ALIGN_CENTER = 0; - /** Used to align a String at the bottom of the box */ - public static final int VERT_ALIGN_BOTTOM = 2; + /** + * Used to align a String at the top of the box + */ + public static final int VERT_ALIGN_TOP = 1; - /** Used to align a String horizontally in the center of the box */ - public static final int HORIZ_ALIGN_CENTER = 3; + /** + * Used to align a String at the bottom of the box + */ + public static final int VERT_ALIGN_BOTTOM = 2; - /** Used to align a String to the left in the box */ - public static final int HORIZ_ALIGN_LEFT = 4; + /** + * Used to align a String horizontally in the center of the box + */ + public static final int HORIZ_ALIGN_CENTER = 3; - /** Used to aling a String to the right in a box */ - public static final int HORIZ_ALIGN_RIGHT = 5; + /** + * Used to align a String to the left in the box + */ + public static final int HORIZ_ALIGN_LEFT = 4; - /** Used to subtract a child from a box, *leaving* the top portion */ - public static final int SUBTRACT_FROM_TOP = 6; + /** + * Used to aling a String to the right in a box + */ + public static final int HORIZ_ALIGN_RIGHT = 5; - /** Used to subtract a child from a box, *leaving* the bottom portion */ - public static final int SUBTRACT_FROM_BOTTOM = 7; + /** + * Used to subtract a child from a box, *leaving* the top portion + */ + public static final int SUBTRACT_FROM_TOP = 6; - /** Used to subtract a child from a box, *leaving* the left portion */ - public static final int SUBTRACT_FROM_LEFT = 8; + /** + * Used to subtract a child from a box, *leaving* the bottom portion + */ + public static final int SUBTRACT_FROM_BOTTOM = 7; - /** Used to subtract a child from a box, *leaving" the right portion */ - public static final int SUBTRACT_FROM_RIGHT = 9; + /** + * Used to subtract a child from a box, *leaving* the left portion + */ + public static final int SUBTRACT_FROM_LEFT = 8; - private static final int[] VERT_ALIGNS = {VERT_ALIGN_CENTER, - VERT_ALIGN_TOP, - VERT_ALIGN_BOTTOM}; + /** + * Used to subtract a child from a box, *leaving" the right portion + */ + public static final int SUBTRACT_FROM_RIGHT = 9; - private static final int[] HORIZ_ALIGNS = {HORIZ_ALIGN_CENTER, - HORIZ_ALIGN_LEFT, - HORIZ_ALIGN_RIGHT}; + private static final int[] VERT_ALIGNS = {VERT_ALIGN_CENTER, + VERT_ALIGN_TOP, + VERT_ALIGN_BOTTOM}; - private static final int[] SUBTRACTS = {SUBTRACT_FROM_TOP, - SUBTRACT_FROM_BOTTOM, - SUBTRACT_FROM_LEFT, - SUBTRACT_FROM_RIGHT}; + private static final int[] HORIZ_ALIGNS = {HORIZ_ALIGN_CENTER, + HORIZ_ALIGN_LEFT, + HORIZ_ALIGN_RIGHT}; - /** The point to use for Graphics.drawString() */ - private Point drawingPoint; + private static final int[] SUBTRACTS = {SUBTRACT_FROM_TOP, + SUBTRACT_FROM_BOTTOM, + SUBTRACT_FROM_LEFT, + SUBTRACT_FROM_RIGHT}; - /** The absolute, world location of the box */ - private Point absoluteLocation; + /** + * The point to use for Graphics.drawString() + */ + private Point drawingPoint; - /** Link to parent box */ - private BoundingBox parent; - - /** - * If this box was the result of a getStringBounds call, this - * array will hold the broken strings - */ - private String[] stringArray; + /** + * The absolute, world location of the box + */ + private Point absoluteLocation; - /** The string specified in getStringBounds */ - private String fullString; - - /** - * Creates a new BoundingBox instance. - * - * @param p a Point, upper left coords - * @param d a Dimension, used to determine height and width - */ - public BoundingBox(Point p, Dimension d) { - super(p, d); - this.drawingPoint = this.getLocation(); - this.absoluteLocation = this.getLocation(); - } + /** + * Link to parent box + */ + private BoundingBox parent; - + /** + * If this box was the result of a getStringBounds call, this array will + * hold the broken strings + */ + private String[] stringArray; - /** - *

Returns true if this box has a parent. The 'world', or - * enclosing canvas is not considered a parent

- * - * @return a boolean value - */ - public boolean hasParent() { - return parent != null; - } + /** + * The string specified in getStringBounds + */ + private String fullString; - /** - *

Get this box's parent box

- * - * @return a BoundingBox value - */ - public BoundingBox getParent() { - return parent; - } - - - - /** - *

Make the specified box this box's child. Equivalent to - * child.setParent(parent) where the specified 'parent' is - * this instance

- * - * @param child a BoundingBox, any box that can fit inside - * this one. The results of calling - * getAbsoluteLocation() on the child will be - * altered after this to take into account the child's - * new location in the 'world' - * - */ - public void add(BoundingBox child) { - child.setParent(this); - } - - - - /** - *

Make the specified box this box's parent

- * - * @param parent a BoundingBox value - */ - public void setParent(BoundingBox parent) { - // Prevent infinite recursion - if (this == parent) { - return; + /** + * Creates a new BoundingBox instance. + * + * @param p a Point, upper left coords + * @param d a Dimension, used to determine height and width + */ + public BoundingBox(Point p, Dimension d) { + super(p, d); + this.drawingPoint = this.getLocation(); + this.absoluteLocation = this.getLocation(); } - this.parent = parent; - // If this box was created empty, without a String inside, - // determine its absolute location - if (this.getLocation().equals(this.getAbsoluteLocation())) { - int ancestorTranslateX = 0; - int ancestorTranslateY = 0; + /** + *

+ * Returns true if this box has a parent. The 'world', or enclosing canvas + * is not considered a parent

+ * + * @return a boolean value + */ + public boolean hasParent() { + return parent != null; + } - BoundingBox ancestor = this; - while (ancestor.hasParent()) { - BoundingBox oldRef = ancestor; - ancestor = ancestor.getParent(); + /** + *

+ * Get this box's parent box

+ * + * @return a BoundingBox value + */ + public BoundingBox getParent() { + return parent; + } + + /** + *

+ * Make the specified box this box's child. Equivalent to + * child.setParent(parent) where the specified 'parent' is this + * instance

+ * + * @param child a BoundingBox, any box that can fit inside this + * one. The results of calling getAbsoluteLocation() on the + * child will be altered after this to take into account the child's new + * location in the 'world' + * + */ + public void add(BoundingBox child) { + child.setParent(this); + } + + /** + *

+ * Make the specified box this box's parent

+ * + * @param parent a BoundingBox value + */ + public void setParent(BoundingBox parent) { // Prevent infinite recursion - if (ancestor == oldRef) { - break; + if (this == parent) { + return; } - ancestorTranslateX += (int)ancestor.getLocation().getX(); - ancestorTranslateY += (int)ancestor.getLocation().getY(); - } + this.parent = parent; - this.getAbsoluteLocation().translate(ancestorTranslateX, - ancestorTranslateY); - } // end if - } // end setParent + // If this box was created empty, without a String inside, + // determine its absolute location + if (this.getLocation().equals(this.getAbsoluteLocation())) { + int ancestorTranslateX = 0; + int ancestorTranslateY = 0; - - - - - /** - *

Get the wrapped strings if this box was from a call to getStringBounds, - * otherwise this method returns null

- * - * @return a String[] array of strings, top to bottom in layout - */ - public String[] getStringArray() { - return stringArray; - } // end getStringArray - - - - /** - *

Set the value of the string array

- * - * @param strArray a String array - * - */ - public void setStringArray(String[] strArray) { - this.stringArray = strArray; - } - - - /** - *

Set the absolute upper left world location point for this box

- * - * @param point a Point value - */ - public void setAbsoluteLocation(Point point) { - this.absoluteLocation = point; - } - - - - /** - *

Returns false if for any reason this box has negative dimensions

- * - * @return true if the box has positive height and width, false otherwise. - */ - public boolean boxExists() { - return (this.getHeight() > 0 && this.getWidth() > 0); - } // end boxExists - - - - - /** - *

Get the absolute upper left location point for this box

- * - * @return a Point value - */ - public Point getAbsoluteLocation() { - return absoluteLocation; - } - - - /** - *

Returns the full string associated with a call to - * getStringBounds

- * - * @return the full string. - */ - public String getFullString() { - return fullString; - } - - - /** - *

Sets the full string associated with getStringBounds

- * - * @param string a String - */ - public void setFullString(String string) { - this.fullString = string; - } - - /** - *

Gets the location of a String after it is adjusted for - * alignment within this box. The point's coordinates are - * either within this box or within the enclosing area.

- * - * @param string a String, the String to be placed - * @param hAlign an int, HORIZ_ALIGN_CENTER, - * HORIZ_ALIGN_LEFT, HORIX_ALIGN_RIGHT - * @param vAlign an int, VERT_ALIGN_CENTER, - * VERT_ALIGN_TOP, VERT_ALIGN_BOTTOM - * @param fm a FontMetrics object for this String - * @param padding an int, the padding around the String - * @param enforce a boolean, if true the method will throw - * an exception when the string is too big, if not true it will break - * the string down and overrun the bottom of the box. If the box - * is too small for even one word, the exception will be thrown - * @return a Point, the coords to use in drawString() - * @see #HORIZ_ALIGN_LEFT - * @see #HORIZ_ALIGN_CENTER - * @see #HORIZ_ALIGN_RIGHT - * @see #VERT_ALIGN_TOP - * @see #VERT_ALIGN_CENTER - * @see #VERT_ALIGN_BOTTOM - * @throws IllegalArgumentException if the args are invalid - * @throws StringTooLongException if the string won't fit - * and enforce is set to true. The exception can still be thrown - * if enforce is false, but only in cases such as the box having - * no height or width - */ - public BoundingBox getStringBounds(String string, - int hAlign, - int vAlign, - FontMetrics fm, - int padding, - boolean enforce) - throws IllegalArgumentException, StringTooLongException { - // Check to make sure the values passed in are valid - if (!checkHAlign(hAlign)) { - throw new IllegalArgumentException("BoundingBox.getStringBounds, " + - "hAlign invalid : " + hAlign); - } - if (!checkVAlign(vAlign)) { - throw new IllegalArgumentException("BoundingBox.getStringBounds, " + - "vAlign invalid : " + hAlign); - } - if (fm == null) { - throw new IllegalArgumentException("BoundingBox.getStringBounds, " + - "FontMetrics null"); - } - if (string == null) { - throw new IllegalArgumentException("BoundingBox.getStringBounds, " + - "String null"); - } - - // NOTE: For this portion of the method, parent refers - // to this object and child refers to the object about - // to be created. When the absolute point for drawing the - // String is determined, this object's ancestors are checked. - Dimension parentSize = this.getSize(); - - Point childLocation; - Dimension childSize; - - // String ascent, width, height, parent, child width, height - int sa, sw, sh, pw, ph, cw, ch; - - // Child, parent x, y coords for upper left - int cx, cy, px, py; - - sa = fm.getMaxAscent(); - sw = fm.stringWidth(string); - sh = sa + fm.getMaxDescent(); - pw = (int)parentSize.getWidth(); - ph = (int)parentSize.getHeight(); - if (pw < 0) { - throw new StringTooLongException("The parent box has a negative width " + - " (" + pw + ")"); - } - if (ph < 0) { - throw new StringTooLongException("The parent box has a negative height"+ - " (" + ph + ")"); - } - cw = sw + padding*2; - ch = sh + padding*2; - px = (int)this.getX(); - py = (int)this.getY(); - - String[] childStrArray = null; - - if ((cw > pw) || (string.indexOf("\n") != -1)) { - cw = pw - (padding * 2); - childStrArray = createStringArray(string, fm, padding, pw); - ch = getWrappedHeight(childStrArray, fm, padding); - if (ch > ph) { - // If enforce is not true, it means we want the box to - // be returned anyway (along with the strings in the array) - // so we can chop them manually and try again - if (enforce) { - throw new StringTooLongException("The wrapped strings do not " + - "fit into the parent box, pw=" + pw + - ", ph=" + ph + ", ch=" + ch + ", cw=" + cw + - ", string: " + string); - } - } - } - - // Need to have child width and height, and string array set - - // Child location is relative to this (parent) box, not the world - if (vAlign == VERT_ALIGN_TOP) { - cy = 0; - } - else if (vAlign == VERT_ALIGN_CENTER) { - cy = (ph/2) - (ch/2); - } - else { - cy = ph - ch; - } - - if (hAlign == HORIZ_ALIGN_LEFT) { - cx = 0; - } - else if (hAlign == HORIZ_ALIGN_CENTER) { - cx = (pw/2) - (cw/2); - } - else { - cx = pw - cw; - } - - childLocation = new Point(cx, cy); - childSize = new Dimension(cw, ch); - - // Drawing location is based on the baseline of the String, and - // relative to the world, not this box. The drawing point differs - // from the absolute box location because of padding and ascent - int dpx, dpy, abx, aby; - - // If this object also has a parent (maybe grandparents), iterate - // through them and find the absolute 'world' location - int ancestorTranslateX = 0; - int ancestorTranslateY = 0; - - BoundingBox ancestor = this; - while (ancestor.hasParent()) { - BoundingBox oldRef = ancestor; - ancestor = ancestor.getParent(); - // Prevent infinite recursion - if (ancestor == oldRef) { - break; - } - ancestorTranslateX += (int)ancestor.getLocation().getX(); - ancestorTranslateY += (int)ancestor.getLocation().getY(); - } - - // Determine the absolute location for the box - abx = px + cx + ancestorTranslateX; - aby = py + cy + ancestorTranslateY; - - // Determine the absolute drawing point for the String - dpx = abx + padding; - dpy = aby + padding + sa; - - Point drawingPoint = new Point(dpx, dpy); - BoundingBox returnChild = new BoundingBox(childLocation, - childSize, - drawingPoint, - new Point(abx, aby)); - this.add(returnChild); - returnChild.setFullString(string); - returnChild.setStringArray(childStrArray); - return returnChild; - - } // end getStringBounds - - - /** - *

Gets the location of a String after it is adjusted for - * alignment within this box. The point's coordinates are - * either within this box or within the enclosing area.

- * - *

By default, this method enforces string length and throws the - * exception if it is too long

- * - * @param string a String, the String to be placed - * @param hAlign an int, HORIZ_ALIGN_CENTER, - * HORIZ_ALIGN_LEFT, HORIX_ALIGN_RIGHT - * @param vAlign an int, VERT_ALIGN_CENTER, - * VERT_ALIGN_TOP, VERT_ALIGN_BOTTOM - * @param fm a FontMetrics object for this String - * @param padding an int, the padding around the String - * @return a Point, the coords to use in drawString() - * @throws IllegalArgumentException if the args are invalid - * @throws StringTooLongException if the string won't fit - */ - public BoundingBox getStringBounds(String string, - int hAlign, - int vAlign, - FontMetrics fm, - int padding) - throws StringTooLongException, IllegalArgumentException { - return getStringBounds(string, hAlign, vAlign, fm, padding, true); - } // end getStringBounds (enforce true by default) - - - - /** - *

This method is called after getting the box by calling - * getStringBounds on the parent. Wraps the string at - * word boundaries and draws it to the specified Graphics - * context. Make sure padding is the same as specified for the - * getStringBounds call, or you may get an unexpected - * {@link gnu.jpdf.StringTooLongException}

- * - * @param g the Graphics object - * @param fm the FontMetrics to use for sizing - * @param padding an int, the padding around the strings - * @param hAlign the int horizontal alignment - * @throws IllegalArgumentException if the args are invalid - * @throws StringTooLongException if the string - * won't fit this will only happen if the fm or padding has - * been changed since getStringBounds was called succesfully - */ - public void drawWrappedString(Graphics g, - FontMetrics fm, - int padding, - int hAlign) - throws IllegalArgumentException, StringTooLongException { - if (getStringArray() == null) { - Point p = getDrawingPoint(); - int xx = (int)p.getX(); - int yy = (int)p.getY(); - g.drawString(getFullString(), xx, yy); - } - else { - int len = stringArray.length; - for (int i = 0; i < len; i++) { - BoundingBox wrappedBox = null; - wrappedBox = getStringBounds(stringArray[i], - hAlign, - BoundingBox.VERT_ALIGN_TOP, - fm, - 0); - Point pp = wrappedBox.getDrawingPoint(); - int xx = (int)pp.getX(); - if (hAlign == BoundingBox.HORIZ_ALIGN_RIGHT) { - xx -= padding; - } - if (hAlign == BoundingBox.HORIZ_ALIGN_LEFT) { - xx += padding; - } - int yy = (int)pp.getY() + padding; - g.drawString(stringArray[i], xx, yy); - subtract(wrappedBox, BoundingBox.SUBTRACT_FROM_BOTTOM); - } - } - } // end drawWrappedString - - - /** - *

Draws lines from the wrapped string until there is no more room and - * then stops. If there is no string or the box is too small for - * anything to be drawn, does nothing

- * - * @param g the Graphics object to draw to - * @param fm the FontMetrics object to use for string sizing - * @param padding the int amount of padding around the string - * @param hAlign the int horizontal alignment - * - */ - public void drawWrappedStringTruncate(Graphics g, - FontMetrics fm, - int padding, - int hAlign) { - - if (getStringArray() == null) { - Point p = getDrawingPoint(); - int xx = (int)p.getX(); - int yy = (int)p.getY(); - if (getFullString() != null) { - g.drawString(getFullString(), xx, yy); - } - else { - System.err.println("getStringArray and getFullString are null"); - } - } - else { - int totalHeight = 0; - int len = stringArray.length; - for (int i = 0; i < len; i++) { - BoundingBox wrappedBox = null; - try { - wrappedBox = getStringBounds(stringArray[i], - hAlign, - BoundingBox.VERT_ALIGN_TOP, - fm, - 0, - false); - totalHeight += (int)wrappedBox.getHeight(); - if (getParent() != null) { - if (totalHeight > (int)(getParent().getHeight())) { - return; + BoundingBox ancestor = this; + while (ancestor.hasParent()) { + BoundingBox oldRef = ancestor; + ancestor = ancestor.getParent(); + // Prevent infinite recursion + if (ancestor == oldRef) { + break; + } + ancestorTranslateX += (int) ancestor.getLocation().getX(); + ancestorTranslateY += (int) ancestor.getLocation().getY(); } - } + + this.getAbsoluteLocation().translate(ancestorTranslateX, + ancestorTranslateY); + } // end if + } // end setParent + + /** + *

+ * Get the wrapped strings if this box was from a call to getStringBounds, + * otherwise this method returns null

+ * + * @return a String[] array of strings, top to bottom in layout + */ + public String[] getStringArray() { + return stringArray; + } // end getStringArray + + /** + *

+ * Set the value of the string array

+ * + * @param strArray a String array + * + */ + public void setStringArray(String[] strArray) { + this.stringArray = strArray; + } + + /** + *

+ * Set the absolute upper left world location point for this box

+ * + * @param point a Point value + */ + public void setAbsoluteLocation(Point point) { + this.absoluteLocation = point; + } + + /** + *

+ * Returns false if for any reason this box has negative dimensions

+ * + * @return true if the box has positive height and width, false otherwise. + */ + public boolean boxExists() { + return (this.getHeight() > 0 && this.getWidth() > 0); + } // end boxExists + + /** + *

+ * Get the absolute upper left location point for this box

+ * + * @return a Point value + */ + public Point getAbsoluteLocation() { + return absoluteLocation; + } + + /** + *

+ * Returns the full string associated with a call to + * getStringBounds

+ * + * @return the full string. + */ + public String getFullString() { + return fullString; + } + + /** + *

+ * Sets the full string associated with getStringBounds

+ * + * @param string a String + */ + public void setFullString(String string) { + this.fullString = string; + } + + /** + *

+ * Gets the location of a String after it is adjusted for alignment within + * this box. The point's coordinates are either within this box or within + * the enclosing area.

+ * + * @param string a String, the String to be placed + * @param hAlign an int, HORIZ_ALIGN_CENTER, HORIZ_ALIGN_LEFT, + * HORIX_ALIGN_RIGHT + * @param vAlign an int, VERT_ALIGN_CENTER, VERT_ALIGN_TOP, + * VERT_ALIGN_BOTTOM + * @param fm a FontMetrics object for this String + * @param padding an int, the padding around the String + * @param enforce a boolean, if true the method will throw an + * exception when the string is too big, if not true it will break the + * string down and overrun the bottom of the box. If the box is too small + * for even one word, the exception will be thrown + * @return a Point, the coords to use in drawString() + * @see #HORIZ_ALIGN_LEFT + * @see #HORIZ_ALIGN_CENTER + * @see #HORIZ_ALIGN_RIGHT + * @see #VERT_ALIGN_TOP + * @see #VERT_ALIGN_CENTER + * @see #VERT_ALIGN_BOTTOM + * @throws IllegalArgumentException if the args are invalid + * @throws StringTooLongException if the string won't fit and enforce is set + * to true. The exception can still be thrown if enforce is false, but only + * in cases such as the box having no height or width + */ + public BoundingBox getStringBounds(String string, + int hAlign, + int vAlign, + FontMetrics fm, + int padding, + boolean enforce) + throws IllegalArgumentException, StringTooLongException { + // Check to make sure the values passed in are valid + if (!checkHAlign(hAlign)) { + throw new IllegalArgumentException("BoundingBox.getStringBounds, " + + "hAlign invalid : " + hAlign); } - catch (StringTooLongException stle) { - stle.printStackTrace(); - return; + if (!checkVAlign(vAlign)) { + throw new IllegalArgumentException("BoundingBox.getStringBounds, " + + "vAlign invalid : " + hAlign); + } + if (fm == null) { + throw new IllegalArgumentException("BoundingBox.getStringBounds, " + + "FontMetrics null"); + } + if (string == null) { + throw new IllegalArgumentException("BoundingBox.getStringBounds, " + + "String null"); } - wrappedBox.drawChoppedString(g, fm, padding, hAlign); - subtract(wrappedBox, BoundingBox.SUBTRACT_FROM_BOTTOM); - } - } - } // end drawWrappedStringTruncate + // NOTE: For this portion of the method, parent refers + // to this object and child refers to the object about + // to be created. When the absolute point for drawing the + // String is determined, this object's ancestors are checked. + Dimension parentSize = this.getSize(); - /** - *

Take the first line of the string (if it is wrapped, otherwise just - * take the whole string) and chop the end of it off to make it fit in the - * box. If the box is smaller than one letter, draw nothing

- * - * @param g the Graphics object to draw to - * @param fm the FontMetrics object to use for string sizing - * @param padding the int amount of padding around the string - * @param hAlign the int horizontal alignment - */ - public void drawChoppedString(Graphics g, - FontMetrics fm, - int padding, - int hAlign) { + Point childLocation; + Dimension childSize; - String string = ""; - if (getStringArray() != null) { - string = new String(getStringArray()[0]); - } - else { - string = new String(getFullString()); - } - BoundingBox choppedBox = null; - try { - choppedBox = getStringBounds(string, - hAlign, - VERT_ALIGN_TOP, - fm, - padding); - Point p = choppedBox.getDrawingPoint(); - int x = (int)p.getX(); - int y = (int)p.getY(); - g.drawString(string, x, y); - } - catch (StringTooLongException stle) { - // Doesn't fit - start cutting from the end until it does - StringBuffer buf = new StringBuffer().append(string); - if (buf.length() == 0) { - System.out.println("BoundingBox.drawChoppedString, buf len 0 ??"); - //return; - throw new RuntimeException(); - } - buf.deleteCharAt(buf.length()-1); - while ((fm.stringWidth(buf.toString()) > (int)getWidth()) && - (buf.length() > 0)) { - buf.deleteCharAt(buf.length()-1); - } - - try { - choppedBox = getStringBounds(buf.toString(), - hAlign, - VERT_ALIGN_TOP, - fm, - padding); - Point pp = choppedBox.getDrawingPoint(); - int xx = (int)pp.getX(); - int yy = (int)pp.getY(); - g.drawString(string, xx, yy); - } - catch (StringTooLongException sstle) { - // Must be a really small box! - sstle.printStackTrace(); - } - } - } // end drawChoppedString + // String ascent, width, height, parent, child width, height + int sa, sw, sh, pw, ph, cw, ch; + // Child, parent x, y coords for upper left + int cx, cy, px, py; + sa = fm.getMaxAscent(); + sw = fm.stringWidth(string); + sh = sa + fm.getMaxDescent(); + pw = (int) parentSize.getWidth(); + ph = (int) parentSize.getHeight(); + if (pw < 0) { + throw new StringTooLongException("The parent box has a negative width " + + " (" + pw + ")"); + } + if (ph < 0) { + throw new StringTooLongException("The parent box has a negative height" + + " (" + ph + ")"); + } + cw = sw + padding * 2; + ch = sh + padding * 2; + px = (int) this.getX(); + py = (int) this.getY(); + String[] childStrArray = null; + if ((cw > pw) || (string.indexOf("\n") != -1)) { + cw = pw - (padding * 2); + childStrArray = createStringArray(string, fm, padding, pw); + ch = getWrappedHeight(childStrArray, fm, padding); + if (ch > ph) { + // If enforce is not true, it means we want the box to + // be returned anyway (along with the strings in the array) + // so we can chop them manually and try again + if (enforce) { + throw new StringTooLongException("The wrapped strings do not " + + "fit into the parent box, pw=" + pw + + ", ph=" + ph + ", ch=" + ch + ", cw=" + cw + + ", string: " + string); + } + } + } + // Need to have child width and height, and string array set + // Child location is relative to this (parent) box, not the world + if (vAlign == VERT_ALIGN_TOP) { + cy = 0; + } else if (vAlign == VERT_ALIGN_CENTER) { + cy = (ph / 2) - (ch / 2); + } else { + cy = ph - ch; + } + if (hAlign == HORIZ_ALIGN_LEFT) { + cx = 0; + } else if (hAlign == HORIZ_ALIGN_CENTER) { + cx = (pw / 2) - (cw / 2); + } else { + cx = pw - cw; + } + childLocation = new Point(cx, cy); + childSize = new Dimension(cw, ch); + // Drawing location is based on the baseline of the String, and + // relative to the world, not this box. The drawing point differs + // from the absolute box location because of padding and ascent + int dpx, dpy, abx, aby; - /** - *

Get the total height of the box needed to contain the strings in - * the specified array

- */ - private int getWrappedHeight(String[] strings, FontMetrics fm, int padding) { - int ma = fm.getMaxAscent(); - int md = fm.getMaxDescent(); - int sh = ma + md; - int hPad = sh / LINE_SPACING_PERCENTAGE; - sh += hPad; - int total = sh * strings.length; + // If this object also has a parent (maybe grandparents), iterate + // through them and find the absolute 'world' location + int ancestorTranslateX = 0; + int ancestorTranslateY = 0; - return total + (padding*2); - } // end getWrappedHeight + BoundingBox ancestor = this; + while (ancestor.hasParent()) { + BoundingBox oldRef = ancestor; + ancestor = ancestor.getParent(); + // Prevent infinite recursion + if (ancestor == oldRef) { + break; + } + ancestorTranslateX += (int) ancestor.getLocation().getX(); + ancestorTranslateY += (int) ancestor.getLocation().getY(); + } + // Determine the absolute location for the box + abx = px + cx + ancestorTranslateX; + aby = py + cy + ancestorTranslateY; + // Determine the absolute drawing point for the String + dpx = abx + padding; + dpy = aby + padding + sa; - /** - * - *

Make a string array from a string, wrapped to fit the box

- * - *

If the line width is too short, the array is just a - * tokenized version of the string

- * - * @param string - the String to convert to an array - * @param - */ - private String[] createStringArray(String string, - FontMetrics fm, - int padding, - int pw) { - if (string == null) { - System.err.println("Tried createStringArray with null String"); - return null; - } - if (fm == null) { - System.err.println("Tried createStringArray with null FontMetrics"); - } + Point drawingPoint = new Point(dpx, dpy); + BoundingBox returnChild = new BoundingBox(childLocation, + childSize, + drawingPoint, + new Point(abx, aby)); + this.add(returnChild); + returnChild.setFullString(string); + returnChild.setStringArray(childStrArray); + return returnChild; - int lw = pw - (padding*2); + } // end getStringBounds - + /** + *

+ * Gets the location of a String after it is adjusted for alignment within + * this box. The point's coordinates are either within this box or within + * the enclosing area.

+ * + *

+ * By default, this method enforces string length and throws the exception + * if it is too long

+ * + * @param string a String, the String to be placed + * @param hAlign an int, HORIZ_ALIGN_CENTER, HORIZ_ALIGN_LEFT, + * HORIX_ALIGN_RIGHT + * @param vAlign an int, VERT_ALIGN_CENTER, VERT_ALIGN_TOP, + * VERT_ALIGN_BOTTOM + * @param fm a FontMetrics object for this String + * @param padding an int, the padding around the String + * @return a Point, the coords to use in drawString() + * @throws IllegalArgumentException if the args are invalid + * @throws StringTooLongException if the string won't fit + */ + public BoundingBox getStringBounds(String string, + int hAlign, + int vAlign, + FontMetrics fm, + int padding) + throws StringTooLongException, IllegalArgumentException { + return getStringBounds(string, hAlign, vAlign, fm, padding, true); + } // end getStringBounds (enforce true by default) - Vector returnVector = new Vector(); - // Return delimiters as tokens - StringTokenizer st = new StringTokenizer(string, " \t\n\r\f", true); - StringBuffer tempBuffer = new StringBuffer(); - StringBuffer finalBuffer = new StringBuffer(); + /** + *

+ * This method is called after getting the box by calling + * getStringBounds on the parent. Wraps the string at word + * boundaries and draws it to the specified Graphics context. + * Make sure padding is the same as specified for the + * getStringBounds call, or you may get an unexpected + * {@link gnu.jpdf.StringTooLongException}

+ * + * @param g the Graphics object + * @param fm the FontMetrics to use for sizing + * @param padding an int, the padding around the strings + * @param hAlign the int horizontal alignment + * @throws IllegalArgumentException if the args are invalid + * @throws StringTooLongException if the string won't fit this will only + * happen if the fm or padding has been changed since getStringBounds was + * called succesfully + */ + public void drawWrappedString(Graphics g, + FontMetrics fm, + int padding, + int hAlign) + throws IllegalArgumentException, StringTooLongException { + if (getStringArray() == null) { + Point p = getDrawingPoint(); + int xx = (int) p.getX(); + int yy = (int) p.getY(); + g.drawString(getFullString(), xx, yy); + } else { + int len = stringArray.length; + for (int i = 0; i < len; i++) { + BoundingBox wrappedBox = null; + wrappedBox = getStringBounds(stringArray[i], + hAlign, + BoundingBox.VERT_ALIGN_TOP, + fm, + 0); + Point pp = wrappedBox.getDrawingPoint(); + int xx = (int) pp.getX(); + if (hAlign == BoundingBox.HORIZ_ALIGN_RIGHT) { + xx -= padding; + } + if (hAlign == BoundingBox.HORIZ_ALIGN_LEFT) { + xx += padding; + } + int yy = (int) pp.getY() + padding; + g.drawString(stringArray[i], xx, yy); + subtract(wrappedBox, BoundingBox.SUBTRACT_FROM_BOTTOM); + } + } + } // end drawWrappedString - while(st.hasMoreTokens()) { - // Get the next word and add a space after it - String tempString = st.nextToken(); - tempBuffer.append(tempString); + /** + *

+ * Draws lines from the wrapped string until there is no more room and then + * stops. If there is no string or the box is too small for anything to be + * drawn, does nothing

+ * + * @param g the Graphics object to draw to + * @param fm the FontMetrics object to use for string sizing + * @param padding the int amount of padding around the string + * @param hAlign the int horizontal alignment + * + */ + public void drawWrappedStringTruncate(Graphics g, + FontMetrics fm, + int padding, + int hAlign) { - // If we haven't reached the width with our current - // line, keep adding tokens. Also, check for hard returns - if ((fm.stringWidth(tempBuffer.toString()) < lw) && - (tempBuffer.toString() - .charAt(tempBuffer.toString().length() - 1) != '\n') && - (tempBuffer.toString() - .charAt(tempBuffer.toString().length() - 1) != '\r')) { - finalBuffer.append(tempString); - continue; - } + if (getStringArray() == null) { + Point p = getDrawingPoint(); + int xx = (int) p.getX(); + int yy = (int) p.getY(); + if (getFullString() != null) { + g.drawString(getFullString(), xx, yy); + } else { + System.err.println("getStringArray and getFullString are null"); + } + } else { + int totalHeight = 0; + int len = stringArray.length; + for (int i = 0; i < len; i++) { + BoundingBox wrappedBox = null; + try { + wrappedBox = getStringBounds(stringArray[i], + hAlign, + BoundingBox.VERT_ALIGN_TOP, + fm, + 0, + false); + totalHeight += (int) wrappedBox.getHeight(); + if (getParent() != null) { + if (totalHeight > (int) (getParent().getHeight())) { + return; + } + } + } catch (StringTooLongException stle) { + stle.printStackTrace(); + return; + } + wrappedBox.drawChoppedString(g, fm, padding, hAlign); + subtract(wrappedBox, BoundingBox.SUBTRACT_FROM_BOTTOM); + } + } + } // end drawWrappedStringTruncate + + /** + *

+ * Take the first line of the string (if it is wrapped, otherwise just take + * the whole string) and chop the end of it off to make it fit in the box. + * If the box is smaller than one letter, draw nothing

+ * + * @param g the Graphics object to draw to + * @param fm the FontMetrics object to use for string sizing + * @param padding the int amount of padding around the string + * @param hAlign the int horizontal alignment + */ + public void drawChoppedString(Graphics g, + FontMetrics fm, + int padding, + int hAlign) { + + String string = ""; + if (getStringArray() != null) { + string = new String(getStringArray()[0]); + } else { + string = new String(getFullString()); + } + BoundingBox choppedBox = null; + try { + choppedBox = getStringBounds(string, + hAlign, + VERT_ALIGN_TOP, + fm, + padding); + Point p = choppedBox.getDrawingPoint(); + int x = (int) p.getX(); + int y = (int) p.getY(); + g.drawString(string, x, y); + } catch (StringTooLongException stle) { + // Doesn't fit - start cutting from the end until it does + StringBuffer buf = new StringBuffer().append(string); + if (buf.length() == 0) { + System.out.println("BoundingBox.drawChoppedString, buf len 0 ??"); + //return; + throw new RuntimeException(); + } + buf.deleteCharAt(buf.length() - 1); + while ((fm.stringWidth(buf.toString()) > (int) getWidth()) + && (buf.length() > 0)) { + buf.deleteCharAt(buf.length() - 1); + } + + try { + choppedBox = getStringBounds(buf.toString(), + hAlign, + VERT_ALIGN_TOP, + fm, + padding); + Point pp = choppedBox.getDrawingPoint(); + int xx = (int) pp.getX(); + int yy = (int) pp.getY(); + g.drawString(string, xx, yy); + } catch (StringTooLongException sstle) { + // Must be a really small box! + sstle.printStackTrace(); + } + } + } // end drawChoppedString + + /** + *

+ * Get the total height of the box needed to contain the strings in the + * specified array

+ */ + private int getWrappedHeight(String[] strings, FontMetrics fm, int padding) { + int ma = fm.getMaxAscent(); + int md = fm.getMaxDescent(); + int sh = ma + md; + int hPad = sh / LINE_SPACING_PERCENTAGE; + sh += hPad; + int total = sh * strings.length; + + return total + (padding * 2); + } // end getWrappedHeight + + /** + * + *

+ * Make a string array from a string, wrapped to fit the box

+ * + *

+ * If the line width is too short, the array is just a tokenized version of + * the string

+ * + * @param string - the String to convert to an array + * @param + */ + private String[] createStringArray(String string, + FontMetrics fm, + int padding, + int pw) { + if (string == null) { + System.err.println("Tried createStringArray with null String"); + return null; + } + if (fm == null) { + System.err.println("Tried createStringArray with null FontMetrics"); + } + + int lw = pw - (padding * 2); + + Vector returnVector = new Vector(); + // Return delimiters as tokens + StringTokenizer st = new StringTokenizer(string, " \t\n\r\f", true); + StringBuffer tempBuffer = new StringBuffer(); + StringBuffer finalBuffer = new StringBuffer(); + + while (st.hasMoreTokens()) { + // Get the next word and add a space after it + String tempString = st.nextToken(); + tempBuffer.append(tempString); + + // If we haven't reached the width with our current + // line, keep adding tokens. Also, check for hard returns + if ((fm.stringWidth(tempBuffer.toString()) < lw) + && (tempBuffer.toString() + .charAt(tempBuffer.toString().length() - 1) != '\n') + && (tempBuffer.toString() + .charAt(tempBuffer.toString().length() - 1) != '\r')) { + finalBuffer.append(tempString); + continue; + } + returnVector.addElement(finalBuffer.toString()); + finalBuffer.delete(0, finalBuffer.length()); + tempBuffer.delete(0, tempBuffer.length()); + if ((tempString.charAt(0) != '\n') + && (tempString.charAt(0) != '\r')) { + tempBuffer.append(tempString); + finalBuffer.append(tempString); + } + continue; + + } // end while returnVector.addElement(finalBuffer.toString()); - finalBuffer.delete(0, finalBuffer.length()); - tempBuffer.delete(0, tempBuffer.length()); - if ((tempString.charAt(0) != '\n') && - (tempString.charAt(0) != '\r')) { - tempBuffer.append(tempString); - finalBuffer.append(tempString); - } - continue; - - } // end while - returnVector.addElement(finalBuffer.toString()); - int len = returnVector.size(); - // Init the class member field stringArray - String[] childStrArray = new String[len]; - for (int i = 0; i < len; i++) { - String curStr = (String)returnVector.get(i); - childStrArray[i] = curStr; + int len = returnVector.size(); + // Init the class member field stringArray + String[] childStrArray = new String[len]; + for (int i = 0; i < len; i++) { + String curStr = (String) returnVector.get(i); + childStrArray[i] = curStr; + } + + return childStrArray; + + } // end createStringArray + + /** + *

+ * Removes the child box from this parent box. The child must have this + * object as its parent or the method does nothing. The BoundingBox returned + * will be cut by an area equal to the child area plus the horizontal or + * vertical strip in which it sits, depending on the 'subtractFrom' value + * passed in

+ * + * @param child a BoundingBox value + * @param subtractFrom an int, SUBTRACT_FROM_LEFT, + * SUBTRACT_FROM_RIGHT, SUBTRACT_FROM_TOP, SUBTRACT_FROM_BOTTOM + * @return a BoundingBox value + * @see #SUBTRACT_FROM_LEFT + * @see #SUBTRACT_FROM_RIGHT + * @see #SUBTRACT_FROM_TOP + * @see #SUBTRACT_FROM_BOTTOM + */ + public BoundingBox subtract(BoundingBox child, int subtractFrom) { + // First, check to see if the params are valid + if (child == null) { + throw new IllegalArgumentException("BoundingBox.subtract, " + + "BoundingBox child is null"); + } + if (!child.hasParent()) { + throw new IllegalArgumentException("BoundingBox.subtract, " + + "BoundingBox child has no parent"); + } + if (!(child.getParent() == this)) { + throw new IllegalArgumentException("BoundingBox.subtract, " + + "this is not BoundingBox child's parent"); + } + // Now that we know the child is this object's child, we continue + // and check the subtractFrom param + int len = SUBTRACTS.length; + boolean valid = false; + for (int i = 0; i < len; i++) { + if (subtractFrom == SUBTRACTS[i]) { + valid = true; + } + } + if (!valid) { + throw new IllegalArgumentException("BoundingBox.subtract, " + + "subtractFrom invalid: " + subtractFrom); + } + + // Now we know the child is valid, and if the subtractFrom + // preference was invalid, we subtract from the bottom + // The child should no longer be used, since the parent + // reference will be invalid + child.setParent(null); + + int cx = (int) child.getLocation().getX(); + int cy = (int) child.getLocation().getY(); + int cw = (int) child.getSize().getWidth(); + int ch = (int) child.getSize().getHeight(); + int px = (int) this.getLocation().getX(); + int py = (int) this.getLocation().getY(); + int pw = (int) this.getSize().getWidth(); + int ph = (int) this.getSize().getHeight(); + + switch (subtractFrom) { + case SUBTRACT_FROM_LEFT: + // This will be useful for right-justified Strings in tables + pw = cx; + this.setSize(new Dimension(pw, ph)); + return this; + + case SUBTRACT_FROM_RIGHT: + // This will be useful for left justified Strings in tables + px = px + cw + cx; + pw = pw - cw - cx; + this.setLocation(new Point(px, py)); + this.setSize(new Dimension(pw, ph)); + return this; + + case SUBTRACT_FROM_BOTTOM: + py = py + ch + cy; + ph = ph - ch - cy; + this.setLocation(new Point(px, py)); + this.setSize(new Dimension(pw, ph)); + return this; + + case SUBTRACT_FROM_TOP: + ph = cy; + this.setSize(new Dimension(pw, ph)); + return this; + + default: // Should never happen + break; + } // end switch + return this; + } // end subtract + + /** + *

+ * Gets the drawing point to use in Graphics drawing methods. After getting + * a new BoundingBox with getStringBounds(), calling this method will give + * you an absolute point, accounting for alignment and padding, etc, from + * which to start drawing the String + *

+ * + *

+ * If getStringBounds was not called (this is a parent box), the upper left + * coordinates will be returned (this.getLocation()) + *

+ * + * @return a Point + */ + public Point getDrawingPoint() { + return drawingPoint; } - return childStrArray; - - } // end createStringArray - - - - /** - *

Removes the child box from this parent box. The child must - * have this object as its parent or the method does nothing. - * The BoundingBox returned will be cut by an area equal to - * the child area plus the horizontal or vertical strip in - * which it sits, depending on the 'subtractFrom' value passed - * in

- * - * @param child a BoundingBox value - * @param subtractFrom an int, SUBTRACT_FROM_LEFT, - SUBTRACT_FROM_RIGHT, SUBTRACT_FROM_TOP, - SUBTRACT_FROM_BOTTOM - * @return a BoundingBox value - * @see #SUBTRACT_FROM_LEFT - * @see #SUBTRACT_FROM_RIGHT - * @see #SUBTRACT_FROM_TOP - * @see #SUBTRACT_FROM_BOTTOM - */ - public BoundingBox subtract(BoundingBox child, int subtractFrom) { - // First, check to see if the params are valid - if (child == null) { - throw new IllegalArgumentException("BoundingBox.subtract, " - + "BoundingBox child is null"); - } - if (!child.hasParent()) { - throw new IllegalArgumentException("BoundingBox.subtract, " - + "BoundingBox child has no parent"); - } - if (!(child.getParent() == this)) { - throw new IllegalArgumentException("BoundingBox.subtract, " - + "this is not BoundingBox child's parent"); - } - // Now that we know the child is this object's child, we continue - // and check the subtractFrom param - int len = SUBTRACTS.length; - boolean valid = false; - for (int i = 0; i < len; i++) { - if (subtractFrom == SUBTRACTS[i]) { - valid = true; - } - } - if (!valid) { - throw new IllegalArgumentException("BoundingBox.subtract, " - + "subtractFrom invalid: " + subtractFrom); - } - - // Now we know the child is valid, and if the subtractFrom - // preference was invalid, we subtract from the bottom - - // The child should no longer be used, since the parent - // reference will be invalid - child.setParent(null); - - int cx = (int) child.getLocation().getX(); - int cy = (int) child.getLocation().getY(); - int cw = (int) child.getSize().getWidth(); - int ch = (int) child.getSize().getHeight(); - int px = (int) this.getLocation().getX(); - int py = (int) this.getLocation().getY(); - int pw = (int) this.getSize().getWidth(); - int ph = (int) this.getSize().getHeight(); - - switch (subtractFrom) { - case SUBTRACT_FROM_LEFT: - // This will be useful for right-justified Strings in tables - pw = cx; - this.setSize(new Dimension(pw, ph)); - return this; - - case SUBTRACT_FROM_RIGHT: - // This will be useful for left justified Strings in tables - px = px + cw + cx; - pw = pw - cw - cx; - this.setLocation(new Point(px, py)); - this.setSize(new Dimension(pw, ph)); - return this; - - case SUBTRACT_FROM_BOTTOM: - py = py + ch + cy; - ph = ph - ch - cy; - this.setLocation(new Point(px, py)); - this.setSize(new Dimension(pw, ph)); - return this; - - case SUBTRACT_FROM_TOP: - ph = cy; - this.setSize(new Dimension(pw, ph)); - return this; - - default: // Should never happen - break; - } // end switch - return this; - } // end subtract - - - - - /** - *

- * Gets the drawing point to use in Graphics drawing methods. After getting - * a new BoundingBox with getStringBounds(), calling this method will give - * you an absolute point, accounting for alignment and padding, etc, from - * which to start drawing the String - *

- * - *

- * If getStringBounds was not called (this is a parent box), the upper left - * coordinates will be returned (this.getLocation()) - *

- * - * @return a Point - */ - public Point getDrawingPoint() { - return drawingPoint; - } - - - - - - // main method is for testing ///////////////// - - - + // main method is for testing ///////////////// /** * For testing * * @param args a String[] value */ public static void main(String[] args) { - Point upperLeft = new Point(5, 5); - Dimension bounds = new Dimension(100, 100); - BoundingBox parent = new BoundingBox(upperLeft, bounds); - String string = "Hello World!"; - Font font = new Font("SansSerif", Font.PLAIN, 12); - Frame frame = new Frame(); - frame.addNotify(); - try { - Image image = frame.createImage(100, 100); - if (image == null) { - System.err.println("image is null"); - } - Graphics graphics = image.getGraphics(); - FontMetrics fm = graphics.getFontMetrics(font); - BoundingBox child = parent - .getStringBounds(string, - BoundingBox.HORIZ_ALIGN_LEFT, - BoundingBox.VERT_ALIGN_TOP, - fm, - 5); - System.out.println("Drawing Point: " + - child.getDrawingPoint().toString()); - System.out.println("Now testing subtract() method..."); + Point upperLeft = new Point(5, 5); + Dimension bounds = new Dimension(100, 100); + BoundingBox parent = new BoundingBox(upperLeft, bounds); + String string = "Hello World!"; + Font font = new Font("SansSerif", Font.PLAIN, 12); + Frame frame = new Frame(); + frame.addNotify(); + try { + Image image = frame.createImage(100, 100); + if (image == null) { + System.err.println("image is null"); + } + Graphics graphics = image.getGraphics(); + FontMetrics fm = graphics.getFontMetrics(font); + BoundingBox child = parent + .getStringBounds(string, + BoundingBox.HORIZ_ALIGN_LEFT, + BoundingBox.VERT_ALIGN_TOP, + fm, + 5); + System.out.println("Drawing Point: " + + child.getDrawingPoint().toString()); + System.out.println("Now testing subtract() method..."); - parent = new BoundingBox(new Point(10, 10), new Dimension(300, 300)); - System.out.println("parent: " + parent.toString()); - child = new BoundingBox(new Point(90, 110), new Dimension(100, 100)); - parent.add(child); - System.out.println("child: " + child.toString()); - System.out.println(); - System.out.println("subtracting the child from the parent"); - System.out.println("SUBTRACT_FROM_TOP: "); - parent = parent.subtract(child, SUBTRACT_FROM_TOP); - System.out.println("new parent: " + parent.toString()); - System.out.println(); - System.out.println("Resetting parent"); - parent = new BoundingBox(new Point(10, 10), new Dimension(300, 300)); - parent.add(child); - System.out.println("SUBTRACT_FROM_BOTTOM"); - parent.subtract(child, SUBTRACT_FROM_BOTTOM); - System.out.println("new parent: " + parent.toString()); - System.out.println(); - System.out.println("Resetting parent"); - parent = new BoundingBox(new Point(10, 10), new Dimension(300, 300)); - parent.add(child); - System.out.println("SUBTRACT_FROM_LEFT"); - parent.subtract(child, SUBTRACT_FROM_LEFT); - System.out.println("new parent: " + parent.toString()); - System.out.println(); - System.out.println("Resetting parent"); - parent = new BoundingBox(new Point(10, 10), new Dimension(300, 300)); - parent.add(child); - System.out.println("SUBTRACT_FROM_RIGHT"); - parent.subtract(child, SUBTRACT_FROM_RIGHT); - System.out.println("new parent: " + parent.toString()); - System.out.println(); + parent = new BoundingBox(new Point(10, 10), new Dimension(300, 300)); + System.out.println("parent: " + parent.toString()); + child = new BoundingBox(new Point(90, 110), new Dimension(100, 100)); + parent.add(child); + System.out.println("child: " + child.toString()); + System.out.println(); + System.out.println("subtracting the child from the parent"); + System.out.println("SUBTRACT_FROM_TOP: "); + parent = parent.subtract(child, SUBTRACT_FROM_TOP); + System.out.println("new parent: " + parent.toString()); + System.out.println(); + System.out.println("Resetting parent"); + parent = new BoundingBox(new Point(10, 10), new Dimension(300, 300)); + parent.add(child); + System.out.println("SUBTRACT_FROM_BOTTOM"); + parent.subtract(child, SUBTRACT_FROM_BOTTOM); + System.out.println("new parent: " + parent.toString()); + System.out.println(); + System.out.println("Resetting parent"); + parent = new BoundingBox(new Point(10, 10), new Dimension(300, 300)); + parent.add(child); + System.out.println("SUBTRACT_FROM_LEFT"); + parent.subtract(child, SUBTRACT_FROM_LEFT); + System.out.println("new parent: " + parent.toString()); + System.out.println(); + System.out.println("Resetting parent"); + parent = new BoundingBox(new Point(10, 10), new Dimension(300, 300)); + parent.add(child); + System.out.println("SUBTRACT_FROM_RIGHT"); + parent.subtract(child, SUBTRACT_FROM_RIGHT); + System.out.println("new parent: " + parent.toString()); + System.out.println(); - - - System.exit(0); + System.exit(0); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } } - catch (Exception e) { - e.printStackTrace(); - System.exit(1); + + // Private methods ///////////////////////////// + /** + * Creates a new BoundingBox instance. + * + * @param p a Point value + * @param d a Dimension value + * @param drawingPoint a Point value + */ + private BoundingBox(Point p, + Dimension d, + Point drawingPoint, + Point absolute) { + super(p, d); + this.drawingPoint = drawingPoint; + this.absoluteLocation = absolute; } - } - - // Private methods ///////////////////////////// - - /** - * Creates a new BoundingBox instance. - * - * @param p a Point value - * @param d a Dimension value - * @param drawingPoint a Point value - */ - private BoundingBox(Point p, - Dimension d, - Point drawingPoint, - Point absolute) { - super(p, d); - this.drawingPoint = drawingPoint; - this.absoluteLocation = absolute; - } - - - /** - *

Checks the horizontal alignment passed into a - * method to make sure it is one of the valid values

- * - * @param hAlign an int value - * @return a boolean value - */ - private boolean checkHAlign(int hAlign) { - int len = HORIZ_ALIGNS.length; - for (int i = 0; i < len; i++) { - if (hAlign == HORIZ_ALIGNS[i]) { - return true; - } + /** + *

+ * Checks the horizontal alignment passed into a method to make sure it is + * one of the valid values

+ * + * @param hAlign an int value + * @return a boolean value + */ + private boolean checkHAlign(int hAlign) { + int len = HORIZ_ALIGNS.length; + for (int i = 0; i < len; i++) { + if (hAlign == HORIZ_ALIGNS[i]) { + return true; + } + } + return false; } - return false; - } - - - /** - *

Checks the vertical alignment passed into a - * method to make sure it is one of the valid values

- * - * @param vAlign an int value - * @return a boolean value - */ - private boolean checkVAlign(int vAlign) { - int len = VERT_ALIGNS.length; - for (int i = 0; i < len; i++) { - if (vAlign == VERT_ALIGNS[i]) { - return true; - } + /** + *

+ * Checks the vertical alignment passed into a method to make sure it is one + * of the valid values

+ * + * @param vAlign an int value + * @return a boolean value + */ + private boolean checkVAlign(int vAlign) { + int len = VERT_ALIGNS.length; + for (int i = 0; i < len; i++) { + if (vAlign == VERT_ALIGNS[i]) { + return true; + } + } + return false; } - return false; - } } // end class BoundingBox - - - diff --git a/libsrc/gnujpdf/src/gnu/jpdf/MyRect.java b/libsrc/gnujpdf/src/gnu/jpdf/MyRect.java index ae5e3f697..28e2f5e75 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/MyRect.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/MyRect.java @@ -5,6 +5,7 @@ package gnu.jpdf; * @author JPEXS */ public class MyRect { + public int xMin; public int yMin; public int xMax; diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFAnnot.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFAnnot.java index 6ad0c9076..9c9122853 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFAnnot.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFAnnot.java @@ -24,249 +24,257 @@ import java.io.OutputStream; import java.io.Serializable; /** - *

This class defines an annotation (commonly known as a Bookmark).

+ *

+ * This class defines an annotation (commonly known as a Bookmark).

* * @author Eric Z. Beard, ericzbeard@hotmail.com * @author Peter T Mount, http://www.retep.org.uk/pdf/ * @version $Revision: 1.2 $, $Date: 2007/08/26 18:56:35 $ */ -public class PDFAnnot extends PDFObject implements Serializable -{ - /* +public class PDFAnnot extends PDFObject implements Serializable { + + /* * NOTE: The original class is the work of Peter T. Mount, who released it * in the uk.org.retep.pdf package. It was modified by Eric Z. Beard as * follows: the package name was changed to gnu.pdf. It is still * licensed under the LGPL. - */ + */ - /** - * Solid border. The border is drawn as a solid line. - */ - public static final short SOLID = 0; - - /** - * The border is drawn with a dashed line. - */ - public static final short DASHED = 1; - - /** - * The border is drawn in a beveled style (faux three-dimensional) such - * that it looks as if it is pushed out of the page (opposite of INSET) - */ - public static final short BEVELED = 2; - - /** - * The border is drawn in an inset style (faux three-dimensional) such - * that it looks as if it is inset into the page (opposite of BEVELED) - */ - public static final short INSET = 3; - - /** - * The border is drawn as a line on the bottom of the annotation rectangle - */ - public static final short UNDERLINED = 4; - - /** - * The subtype of the outline, ie text, note, etc - */ - private String subtype; - - /** - * The size of the annotation - */ - private int l,b,r,t; - - /** - * The text of a text annotation - */ - private String s; - - /** - * flag used to indicate that the destination should fit the screen - */ - private static final int FULL_PAGE = -9999; - - /** - * Link to the Destination page - */ - private PDFObject dest; - - /** - * If fl!=FULL_PAGE then this is the region of the destination page shown. - * Otherwise they are ignored. - */ - private int fl,fb,fr,ft; - - /** - * the border for this annotation - */ - private PDFBorder border; - - /** - * This is used to create an annotation. - * @param s Subtype for this annotation - * @param l Left coordinate - * @param b Bottom coordinate - * @param r Right coordinate - * @param t Top coordinate - */ - protected PDFAnnot(String s,int l,int b,int r,int t) { - super("/Annot"); - subtype = s; - this.l = l; - this.b = b; - this.r = r; - this.t = t; - } - - /** - * Creates a text annotation - * @param l Left coordinate - * @param b Bottom coordinate - * @param r Right coordinate - * @param t Top coordinate - * @param s Text for this annotation - */ - public PDFAnnot(int l,int b,int r,int t,String s) { - this("/Text",l,b,r,t); - this.s = s; - } - - /** - * Creates a link annotation - * @param l Left coordinate - * @param b Bottom coordinate - * @param r Right coordinate - * @param t Top coordinate - * @param dest Destination for this link. The page will fit the display. - */ - public PDFAnnot(int l,int b,int r,int t,PDFObject dest) { - this("/Link",l,b,r,t); - this.dest = dest; - this.fl = FULL_PAGE; // this is used to indicate a full page - } - - /** - * Creates a link annotation - * @param l Left coordinate - * @param b Bottom coordinate - * @param r Right coordinate - * @param t Top coordinate - * @param dest Destination for this link - * @param fl Left coordinate - * @param fb Bottom coordinate - * @param fr Right coordinate - * @param ft Top coordinate - *

Rectangle describing what part of the page to be displayed - * (must be in User Coordinates) - */ - public PDFAnnot(int l,int b,int r,int t, - PDFObject dest, - int fl,int fb,int fr,int ft - ) { - this("/Link",l,b,r,t); - this.dest = dest; - this.fl = fl; - this.fb = fb; - this.fr = fr; - this.ft = ft; - } - - /** - * Sets the border for the annotation. By default, no border is defined. - * - *

If the style is DASHED, then this method uses PDF's default dash - * scheme {3} - * - *

Important: the annotation must have been added to the document before - * this is used. If the annotation was created using the methods in - * PDFPage, then the annotation is already in the document. - * - * @param style Border style SOLID, DASHED, BEVELED, INSET or UNDERLINED. - * @param width Width of the border - */ - public void setBorder(short style,double width) { - border = new PDFBorder(style,width); - pdfDocument.add(border); - } - - /** - * Sets the border for the annotation. Unlike the other method, this - * produces a dashed border. - * - *

Important: the annotation must have been added to the document before - * this is used. If the annotation was created using the methods in - * PDFPage, then the annotation is already in the document. - * - * @param width Width of the border - * @param dash Array of lengths, used for drawing the dashes. If this - * is null, then the default of {3} is used. - */ - public void setBorder(double width,double dash[]) { - border = new PDFBorder(width,dash); - pdfDocument.add(border); - } - - /** - * Should this be public?? - * - * @param os OutputStream to send the object to - * @exception IOException on error - */ - public void write(OutputStream os) throws IOException { - // Write the object header - writeStart(os); - - // now the objects body - os.write("/Subtype ".getBytes()); - os.write(subtype.getBytes()); - os.write("\n/Rect [".getBytes()); - os.write(Integer.toString(l).getBytes()); - os.write(" ".getBytes()); - os.write(Integer.toString(b).getBytes()); - os.write(" ".getBytes()); - os.write(Integer.toString(r).getBytes()); - os.write(" ".getBytes()); - os.write(Integer.toString(t).getBytes()); - os.write("]\n".getBytes()); - - // handle the border - if(border==null) { - os.write("/Border [0 0 0]\n".getBytes()); - //if(pdf.defaultOutlineBorder==null) - //pdf.add(pdf.defaultOutlineBorder = new border(SOLID,0.0)); - //os.write(pdf.defaultOutlineBorder.toString().getBytes()); - } else { - os.write("/BS ".getBytes()); - os.write(border.toString().getBytes()); - os.write("\n".getBytes()); + /** + * Solid border. The border is drawn as a solid line. + */ + public static final short SOLID = 0; + + /** + * The border is drawn with a dashed line. + */ + public static final short DASHED = 1; + + /** + * The border is drawn in a beveled style (faux three-dimensional) such that + * it looks as if it is pushed out of the page (opposite of INSET) + */ + public static final short BEVELED = 2; + + /** + * The border is drawn in an inset style (faux three-dimensional) such that + * it looks as if it is inset into the page (opposite of BEVELED) + */ + public static final short INSET = 3; + + /** + * The border is drawn as a line on the bottom of the annotation rectangle + */ + public static final short UNDERLINED = 4; + + /** + * The subtype of the outline, ie text, note, etc + */ + private String subtype; + + /** + * The size of the annotation + */ + private int l, b, r, t; + + /** + * The text of a text annotation + */ + private String s; + + /** + * flag used to indicate that the destination should fit the screen + */ + private static final int FULL_PAGE = -9999; + + /** + * Link to the Destination page + */ + private PDFObject dest; + + /** + * If fl!=FULL_PAGE then this is the region of the destination page shown. + * Otherwise they are ignored. + */ + private int fl, fb, fr, ft; + + /** + * the border for this annotation + */ + private PDFBorder border; + + /** + * This is used to create an annotation. + * + * @param s Subtype for this annotation + * @param l Left coordinate + * @param b Bottom coordinate + * @param r Right coordinate + * @param t Top coordinate + */ + protected PDFAnnot(String s, int l, int b, int r, int t) { + super("/Annot"); + subtype = s; + this.l = l; + this.b = b; + this.r = r; + this.t = t; } - - // Now the annotation subtypes - if(subtype.equals("/Text")) { - os.write("/Contents ".getBytes()); - os.write(PDFStringHelper.makePDFString(s).getBytes()); - os.write("\n".getBytes()); - } else if(subtype.equals("/Link")) { - os.write("/Dest [".getBytes()); - os.write(dest.toString().getBytes()); - if(fl==FULL_PAGE) - os.write(" /Fit]".getBytes()); - else { - os.write(" /FitR ".getBytes()); - os.write(Integer.toString(fl).getBytes()); - os.write(" ".getBytes()); - os.write(Integer.toString(fb).getBytes()); - os.write(" ".getBytes()); - os.write(Integer.toString(fr).getBytes()); - os.write(" ".getBytes()); - os.write(Integer.toString(ft).getBytes()); - os.write("]".getBytes()); - } - os.write("\n".getBytes()); + + /** + * Creates a text annotation + * + * @param l Left coordinate + * @param b Bottom coordinate + * @param r Right coordinate + * @param t Top coordinate + * @param s Text for this annotation + */ + public PDFAnnot(int l, int b, int r, int t, String s) { + this("/Text", l, b, r, t); + this.s = s; + } + + /** + * Creates a link annotation + * + * @param l Left coordinate + * @param b Bottom coordinate + * @param r Right coordinate + * @param t Top coordinate + * @param dest Destination for this link. The page will fit the display. + */ + public PDFAnnot(int l, int b, int r, int t, PDFObject dest) { + this("/Link", l, b, r, t); + this.dest = dest; + this.fl = FULL_PAGE; // this is used to indicate a full page + } + + /** + * Creates a link annotation + * + * @param l Left coordinate + * @param b Bottom coordinate + * @param r Right coordinate + * @param t Top coordinate + * @param dest Destination for this link + * @param fl Left coordinate + * @param fb Bottom coordinate + * @param fr Right coordinate + * @param ft Top coordinate + *

Rectangle describing what part of the page to be displayed (must + * be in User Coordinates) + */ + public PDFAnnot(int l, int b, int r, int t, + PDFObject dest, + int fl, int fb, int fr, int ft + ) { + this("/Link", l, b, r, t); + this.dest = dest; + this.fl = fl; + this.fb = fb; + this.fr = fr; + this.ft = ft; + } + + /** + * Sets the border for the annotation. By default, no border is defined. + * + *

+ * If the style is DASHED, then this method uses PDF's default dash scheme + * {3} + * + *

+ * Important: the annotation must have been added to the document before + * this is used. If the annotation was created using the methods in PDFPage, + * then the annotation is already in the document. + * + * @param style Border style SOLID, DASHED, BEVELED, INSET or UNDERLINED. + * @param width Width of the border + */ + public void setBorder(short style, double width) { + border = new PDFBorder(style, width); + pdfDocument.add(border); + } + + /** + * Sets the border for the annotation. Unlike the other method, this + * produces a dashed border. + * + *

+ * Important: the annotation must have been added to the document before + * this is used. If the annotation was created using the methods in PDFPage, + * then the annotation is already in the document. + * + * @param width Width of the border + * @param dash Array of lengths, used for drawing the dashes. If this is + * null, then the default of {3} is used. + */ + public void setBorder(double width, double dash[]) { + border = new PDFBorder(width, dash); + pdfDocument.add(border); + } + + /** + * Should this be public?? + * + * @param os OutputStream to send the object to + * @exception IOException on error + */ + public void write(OutputStream os) throws IOException { + // Write the object header + writeStart(os); + + // now the objects body + os.write("/Subtype ".getBytes()); + os.write(subtype.getBytes()); + os.write("\n/Rect [".getBytes()); + os.write(Integer.toString(l).getBytes()); + os.write(" ".getBytes()); + os.write(Integer.toString(b).getBytes()); + os.write(" ".getBytes()); + os.write(Integer.toString(r).getBytes()); + os.write(" ".getBytes()); + os.write(Integer.toString(t).getBytes()); + os.write("]\n".getBytes()); + + // handle the border + if (border == null) { + os.write("/Border [0 0 0]\n".getBytes()); + //if(pdf.defaultOutlineBorder==null) + //pdf.add(pdf.defaultOutlineBorder = new border(SOLID,0.0)); + //os.write(pdf.defaultOutlineBorder.toString().getBytes()); + } else { + os.write("/BS ".getBytes()); + os.write(border.toString().getBytes()); + os.write("\n".getBytes()); + } + + // Now the annotation subtypes + if (subtype.equals("/Text")) { + os.write("/Contents ".getBytes()); + os.write(PDFStringHelper.makePDFString(s).getBytes()); + os.write("\n".getBytes()); + } else if (subtype.equals("/Link")) { + os.write("/Dest [".getBytes()); + os.write(dest.toString().getBytes()); + if (fl == FULL_PAGE) { + os.write(" /Fit]".getBytes()); + } else { + os.write(" /FitR ".getBytes()); + os.write(Integer.toString(fl).getBytes()); + os.write(" ".getBytes()); + os.write(Integer.toString(fb).getBytes()); + os.write(" ".getBytes()); + os.write(Integer.toString(fr).getBytes()); + os.write(" ".getBytes()); + os.write(Integer.toString(ft).getBytes()); + os.write("]".getBytes()); + } + os.write("\n".getBytes()); + } + + // finish off with its footer + writeEnd(os); } - - // finish off with its footer - writeEnd(os); - } } diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFBorder.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFBorder.java index 48f73c74a..f723869ab 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFBorder.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFBorder.java @@ -23,65 +23,67 @@ import java.io.IOException; import java.io.OutputStream; /** - *

A border around an annotation

+ *

+ * A border around an annotation

* * * @author Peter T Mount, http://www.retep.org.uk/pdf/ * @author Eric Z. Beard, ericzbeard@hotmail.com * @version $Revision: 1.2 $ */ -public class PDFBorder extends PDFObject -{ +public class PDFBorder extends PDFObject { + /* * NOTE: The original class is the work of Peter T. Mount, who released it * in the uk.org.retep.pdf package. It was modified by Eric Z. Beard as * follows: the package name was changed to gnu.pdf. It is still * licensed under the LGPL. - */ + */ /** * The style of the border */ private short style; - + /** * The width of the border */ private double width; - + /** * This array allows the definition of a dotted line for the border */ private double dash[]; - + /** * Creates a border using the predefined styles in PDFAnnot. - *

Note: Do not use PDFAnnot.DASHED with this method. - * Use the other constructor. + *

+ * Note: Do not use PDFAnnot.DASHED with this method. Use the other + * constructor. * * @param style The style of the border * @param width The width of the border * @see PDFAnnot */ - public PDFBorder(short style,double width) { + public PDFBorder(short style, double width) { super("/Border"); this.style = style; this.width = width; } - + /** * Creates a border of style PDFAnnot.DASHED * * @param width The width of the border * @param dash The line pattern definition */ - public PDFBorder(double width,double dash[]) { + public PDFBorder(double width, double dash[]) { super("/Border"); this.style = PDFAnnot.DASHED; this.width = width; this.dash = dash; } - + /** * @param os OutputStream to send the object to * @exception IOException on error @@ -90,23 +92,23 @@ public class PDFBorder extends PDFObject //writeStart(os); os.write(Integer.toString(objser).getBytes()); os.write(" 0 obj\n".getBytes()); - + os.write("[/S /".getBytes()); - os.write("SDBIU".substring(style,style+1).getBytes()); + os.write("SDBIU".substring(style, style + 1).getBytes()); os.write(" /W ".getBytes()); os.write(Double.toString(width).getBytes()); - if(dash!=null) { + if (dash != null) { os.write(" /D [".getBytes()); os.write(Double.toString(dash[0]).getBytes()); - for(int i=1;iThis class implements the PDF Catalog, - * also known as the root node

+ *

+ * This class implements the PDF Catalog, also known as the root node

* * @author Peter T. Mount * @author Eric Z. Beard, ericzbeard@hotmail.com * @version $Revision: 1.2 $, $Date: 2007/08/26 18:56:35 $ */ -public class PDFCatalog extends PDFObject -{ - /** - * The pages of the document - */ - private PDFPageList pdfPageList; - - /** - * The outlines of the document - */ - private PDFOutline outlines; - - /** - * The initial page mode - */ - private int pagemode; - - /** - * This constructs a PDF Catalog object - * - * @param pdfPageList The PDFPageList object that's the root - * of the documents page tree - * @param pagemode How the document should appear when opened. - * Allowed values are USENONE, USEOUTLINES, USETHUMBS or FULLSCREEN. - */ - public PDFCatalog(PDFPageList pdfPageList,int pagemode) { - super("/Catalog"); - this.pdfPageList = pdfPageList; - this.pagemode = pagemode; - } - - /** - * This sets the root outline object - * @param outline The root outline - */ - protected void setOutline(PDFOutline outline) { - this.outlines = outline; - } - - /** - * @param os OutputStream to send the object to - * @exception IOException on error - */ - public void write(OutputStream os) throws IOException { - // Write the object header - writeStart(os); - - // now the objects body - os.write("/Version /1.7\n".getBytes()); +public class PDFCatalog extends PDFObject { - // the /Pages object - os.write("/Pages ".getBytes()); - os.write(pdfPageList.toString().getBytes()); - os.write("\n".getBytes()); - - // the Outlines object - if(outlines!=null) { - //if(outlines.getLast()>-1) { - os.write("/Outlines ".getBytes()); - os.write(outlines.toString().getBytes()); - os.write("\n".getBytes()); - //} + /** + * The pages of the document + */ + private PDFPageList pdfPageList; + + /** + * The outlines of the document + */ + private PDFOutline outlines; + + /** + * The initial page mode + */ + private int pagemode; + + /** + * This constructs a PDF Catalog object + * + * @param pdfPageList The PDFPageList object that's the root of the + * documents page tree + * @param pagemode How the document should appear when opened. Allowed + * values are USENONE, USEOUTLINES, USETHUMBS or FULLSCREEN. + */ + public PDFCatalog(PDFPageList pdfPageList, int pagemode) { + super("/Catalog"); + this.pdfPageList = pdfPageList; + this.pagemode = pagemode; + } + + /** + * This sets the root outline object + * + * @param outline The root outline + */ + protected void setOutline(PDFOutline outline) { + this.outlines = outline; + } + + /** + * @param os OutputStream to send the object to + * @exception IOException on error + */ + public void write(OutputStream os) throws IOException { + // Write the object header + writeStart(os); + + // now the objects body + os.write("/Version /1.7\n".getBytes()); + + // the /Pages object + os.write("/Pages ".getBytes()); + os.write(pdfPageList.toString().getBytes()); + os.write("\n".getBytes()); + + // the Outlines object + if (outlines != null) { + //if(outlines.getLast()>-1) { + os.write("/Outlines ".getBytes()); + os.write(outlines.toString().getBytes()); + os.write("\n".getBytes()); + //} + } + + // the /PageMode setting + os.write("/PageMode ".getBytes()); + os.write(PDFDocument.PDF_PAGE_MODES[pagemode].getBytes()); + os.write("\n".getBytes()); + + // finish off with its footer + writeEnd(os); } - - // the /PageMode setting - os.write("/PageMode ".getBytes()); - os.write(PDFDocument.PDF_PAGE_MODES[pagemode].getBytes()); - os.write("\n".getBytes()); - - // finish off with its footer - writeEnd(os); - } } // end class PDFCatalog - + diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFDocument.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFDocument.java index 472276417..33c15f032 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFDocument.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFDocument.java @@ -37,230 +37,234 @@ import java.util.logging.Level; import java.util.logging.Logger; /** - *

This class is the base of the PDF generator. A PDFDocument class is - * created for a document, and each page, object, annotation, - * etc is added to the document. - * Once complete, the document can be written to an OutputStream, and the PDF - * document's internal structures are kept in sync.

+ *

+ * This class is the base of the PDF generator. A PDFDocument class is created + * for a document, and each page, object, annotation, etc is added to the + * document. Once complete, the document can be written to an OutputStream, and + * the PDF document's internal structures are kept in sync.

* - *

Note that most programmers using this package will NEVER access - * one of these objects directly. Most everything can be done using - * PDFJob and PDFGraphics, so you don't need - * to directly instantiate a PDFDocument

+ *

+ * Note that most programmers using this package will NEVER access one of these + * objects directly. Most everything can be done using PDFJob and + * PDFGraphics, so you don't need to directly instantiate a + * PDFDocument

* - *

ezb - 20011115 - Wondering if the constructors should even be public. - * When would someone want to make one of these and manipulate it outside - * the context of a job and graphics object?

+ *

+ * ezb - 20011115 - Wondering if the constructors should even be public. When + * would someone want to make one of these and manipulate it outside the context + * of a job and graphics object?

* * @author Peter T Mount, http://www.retep.org.uk/pdf/ * @author Eric Z. Beard, ericzbeard@hotmail.com * @author Gilbert DeLeeuw, gil1@users.sourceforge.net * @version $Revision: 1.4 $, $Date: 2007/09/22 12:58:40 $ */ -public class PDFDocument implements Serializable -{ - - /* +public class PDFDocument implements Serializable { + + /* * NOTE: This class originated in uk.org.retep.pdf, by Peter T. Mount, and it * has been modified by Eric Z. Beard, ericzbeard@hotmail.com. The * package name was changed to gnu.jpdf and several inner classes were * moved out into their own files. - */ + */ + /** + * This is used to allocate objects a unique serial number in the document. + */ + protected int objser; - /** - * This is used to allocate objects a unique serial number in the document. - */ - protected int objser; - - /** - * This vector contains each indirect object within the document. - */ - protected Vector objects; - - /** - * This is the Catalog object, which is required by each PDF Document - */ - private PDFCatalog catalog; - - /** - * This is the info object. Although this is an optional object, we - * include it. - */ - private PDFInfo info; - - /** - * This is the Pages object, which is required by each PDF Document - */ - private PDFPageList pdfPageList; - - /** - * This is the Outline object, which is optional - */ - private PDFOutline outline; - - /** - * This holds a PDFObject describing the default border for annotations. - * It's only used when the document is being written. - */ - protected PDFObject defaultOutlineBorder; - - /** - *

This page mode indicates that the document - * should be opened just with the page visible. This is the default

- */ - public static final int USENONE = 0; - - /** - *

This page mode indicates that the Outlines - * should also be displayed when the document is opened.

- */ - public static final int USEOUTLINES = 1; - - /** - *

This page mode indicates that the Thumbnails should be visible when the - * document first opens.

- */ - public static final int USETHUMBS = 2; - - /** - *

- * This page mode indicates that when the document is opened, it is displayed - * in full-screen-mode. There is no menu bar, window controls nor any other - * window present.

- */ - public static final int FULLSCREEN = 3; - - /** - *

- * These map the page modes just defined to the pagemodes setting of PDF. - *

- */ - public static final String PDF_PAGE_MODES[] = { - "/UseNone", - "/UseOutlines", - "/UseThumbs", - "/FullScreen" - }; - - /** - * This is used to provide a unique name for a font - */ - private int fontid = 0; - - /** - *

This is used to provide a unique name for an image

- */ - private int imageid = 0; - - /** - * This holds the current fonts - */ - private Vector fonts; - - - /** - *

This creates a PDF document with the default pagemode

- */ - public PDFDocument() { - this(USENONE); - } - - /** - *

This creates a PDF document

- * @param pagemode an int, determines how the document will present itself to - * the viewer when it first opens. - */ - public PDFDocument(int pagemode) { - objser = 1; - objects = new Vector(); - fonts = new Vector(); - - // Now create some standard objects - add(pdfPageList = new PDFPageList()); - add(catalog = new PDFCatalog(pdfPageList,pagemode)); - add(info = new PDFInfo()); - - // Acroread on linux seems to die if there is no root outline - add(getOutline()); - } - + /** + * This vector contains each indirect object within the document. + */ + protected Vector objects; + /** + * This is the Catalog object, which is required by each PDF Document + */ + private PDFCatalog catalog; - /** - * This adds a top level object to the document. - * - *

Once added, it is allocated a unique serial number. - * - *

Note: Not all object are added directly using this method. - * Some objects which have Kids (in PDF sub-objects or children are - * called Kids) will have their own add() method, which will call this - * one internally. - * - * @param obj The PDFObject to add to the document - * @return the unique serial number for this object. - */ - public synchronized int add(PDFObject obj) - { - objects.addElement(obj); - obj.objser=objser++; // create a new serial number - obj.pdfDocument = this; // so they can find the document they belong to - - // If its a page, then add it to the pages collection - if(obj instanceof PDFPage) - pdfPageList.add((PDFPage)obj); - - return obj.objser; - } - - /** - *

This returns a specific page. It's used mainly when using a - * Serialized template file.

- * - * ?? How does a serialized template file work ??? - * - * @param page page number to return - * @return PDFPage at that position - */ - public PDFPage getPage(int page) { - return pdfPageList.getPage(page); - } - + /** + * This is the info object. Although this is an optional object, we include + * it. + */ + private PDFInfo info; - /** - * @return the root outline - */ - public PDFOutline getOutline() - { - if(outline==null) { - outline = new PDFOutline(); - catalog.setOutline(outline); + /** + * This is the Pages object, which is required by each PDF Document + */ + private PDFPageList pdfPageList; + + /** + * This is the Outline object, which is optional + */ + private PDFOutline outline; + + /** + * This holds a PDFObject describing the default border for annotations. + * It's only used when the document is being written. + */ + protected PDFObject defaultOutlineBorder; + + /** + *

+ * This page mode indicates that the document should be opened just with the + * page visible. This is the default

+ */ + public static final int USENONE = 0; + + /** + *

+ * This page mode indicates that the Outlines should also be displayed when + * the document is opened.

+ */ + public static final int USEOUTLINES = 1; + + /** + *

+ * This page mode indicates that the Thumbnails should be visible when the + * document first opens.

+ */ + public static final int USETHUMBS = 2; + + /** + *

+ * This page mode indicates that when the document is opened, it is + * displayed in full-screen-mode. There is no menu bar, window controls nor + * any other window present.

+ */ + public static final int FULLSCREEN = 3; + + /** + *

+ * These map the page modes just defined to the pagemodes setting of PDF. + *

+ */ + public static final String PDF_PAGE_MODES[] = { + "/UseNone", + "/UseOutlines", + "/UseThumbs", + "/FullScreen" + }; + + /** + * This is used to provide a unique name for a font + */ + private int fontid = 0; + + /** + *

+ * This is used to provide a unique name for an image

+ */ + private int imageid = 0; + + /** + * This holds the current fonts + */ + private Vector fonts; + + /** + *

+ * This creates a PDF document with the default pagemode

+ */ + public PDFDocument() { + this(USENONE); } - return outline; - } - - /** - * This returns a font of the specified type and font. If the font has - * not been defined, it creates a new font in the PDF document, and - * returns it. - * - * @param type PDF Font Type - usually "/Type1" - * @param font Java font name - * @param style java.awt.Font style (NORMAL, BOLD etc) - * @return PDFFont defining this font - */ - public PDFFont getFont(String type,String font,int style) { - for(PDFFont ft : fonts) { - if(ft.equals(type,font,style)) + + /** + *

+ * This creates a PDF document

+ * + * @param pagemode an int, determines how the document will present itself + * to the viewer when it first opens. + */ + public PDFDocument(int pagemode) { + objser = 1; + objects = new Vector(); + fonts = new Vector(); + + // Now create some standard objects + add(pdfPageList = new PDFPageList()); + add(catalog = new PDFCatalog(pdfPageList, pagemode)); + add(info = new PDFInfo()); + + // Acroread on linux seems to die if there is no root outline + add(getOutline()); + } + + /** + * This adds a top level object to the document. + * + *

+ * Once added, it is allocated a unique serial number. + * + *

+ * Note: Not all object are added directly using this method. Some + * objects which have Kids (in PDF sub-objects or children are called Kids) + * will have their own add() method, which will call this one internally. + * + * @param obj The PDFObject to add to the document + * @return the unique serial number for this object. + */ + public synchronized int add(PDFObject obj) { + objects.addElement(obj); + obj.objser = objser++; // create a new serial number + obj.pdfDocument = this; // so they can find the document they belong to + + // If its a page, then add it to the pages collection + if (obj instanceof PDFPage) { + pdfPageList.add((PDFPage) obj); + } + + return obj.objser; + } + + /** + *

+ * This returns a specific page. It's used mainly when using a Serialized + * template file.

+ * + * ?? How does a serialized template file work ??? + * + * @param page page number to return + * @return PDFPage at that position + */ + public PDFPage getPage(int page) { + return pdfPageList.getPage(page); + } + + /** + * @return the root outline + */ + public PDFOutline getOutline() { + if (outline == null) { + outline = new PDFOutline(); + catalog.setOutline(outline); + } + return outline; + } + + /** + * This returns a font of the specified type and font. If the font has not + * been defined, it creates a new font in the PDF document, and returns it. + * + * @param type PDF Font Type - usually "/Type1" + * @param font Java font name + * @param style java.awt.Font style (NORMAL, BOLD etc) + * @return PDFFont defining this font + */ + public PDFFont getFont(String type, String font, int style) { + for (PDFFont ft : fonts) { + if (ft.equals(type, font, style)) { + return ft; + } + } + + // the font wasn't found, so create it + fontid++; + PDFFont ft = new PDFFont("/F" + fontid, type, font, style); + add(ft); + fonts.addElement(ft); return ft; } - - // the font wasn't found, so create it - fontid++; - PDFFont ft = new PDFFont("/F"+fontid,type,font,style); - add(ft); - fonts.addElement(ft); - return ft; - } public PDFFont getEmbeddedFont(String font, int style, File file) throws FileNotFoundException, IOException { for (PDFFont ft : fonts) { @@ -301,7 +305,6 @@ public class PDFDocument implements Serializable Logger.getLogger(PDFDocument.class.getName()).log(Level.SEVERE, null, ex); } - PDFStream cidToGidMap = new PDFStream(); cidToGidMap.getOutputStream().write(par.getCidtogidmap()); cidToGidMap.setDeflate(true); @@ -378,8 +381,7 @@ public class PDFDocument implements Serializable if (first) { widths.append("" + c + " [" + w); first = false; - } - else if (c == prevC + 1) { + } else if (c == prevC + 1) { widths.append(" " + w); } else { widths.append("]"); @@ -392,67 +394,70 @@ public class PDFDocument implements Serializable } return "/W [" + widths.toString() + " ]"; } - /** - * Sets a unique name to a PDFImage - * @param img PDFImage to set the name of - * @return the name given to the image - */ - public String setImageName(PDFImage img) { - imageid++; - img.setName("/Image"+imageid); - return img.getName(); - } - - /** - *

Set the PDFInfo object, which contains author, title, - * keywords, etc

- * @param info a PDFInof object - */ - public void setPDFInfo(PDFInfo info) { - this.info = info; - } - - - /** - *

Get the PDFInfo object, which contains author, title, keywords, - * etc

- * @return the PDFInfo object for this document. - */ - public PDFInfo getPDFInfo() { - return this.info; - } - - - /** - * This writes the document to an OutputStream. - * - *

Note: You can call this as many times as you wish, as long as - * the calls are not running at the same time. - * - *

Also, objects can be added or amended between these calls. - * - *

Also, the OutputStream is not closed, but will be flushed on - * completion. It is up to the caller to close the stream. - * - * @param os OutputStream to write the document to - * @exception IOException on error - */ - public void write(OutputStream os) throws IOException - { - PDFOutput pos = new PDFOutput(os); - - // Write each object to the OutputStream. We call via the output - // as that builds the xref table - for(PDFObject o : objects) { - pos.write(o); + /** + * Sets a unique name to a PDFImage + * + * @param img PDFImage to set the name of + * @return the name given to the image + */ + public String setImageName(PDFImage img) { + imageid++; + img.setName("/Image" + imageid); + return img.getName(); } - - // Finally close the output, which writes the xref table. - pos.close(); - - // and flush the output stream to ensure everything is written. - os.flush(); - } - + + /** + *

+ * Set the PDFInfo object, which contains author, title, keywords, etc

+ * + * @param info a PDFInof object + */ + public void setPDFInfo(PDFInfo info) { + this.info = info; + } + + /** + *

+ * Get the PDFInfo object, which contains author, title, keywords, etc

+ * + * @return the PDFInfo object for this document. + */ + public PDFInfo getPDFInfo() { + return this.info; + } + + /** + * This writes the document to an OutputStream. + * + *

+ * Note: You can call this as many times as you wish, as long as the + * calls are not running at the same time. + * + *

+ * Also, objects can be added or amended between these calls. + * + *

+ * Also, the OutputStream is not closed, but will be flushed on completion. + * It is up to the caller to close the stream. + * + * @param os OutputStream to write the document to + * @exception IOException on error + */ + public void write(OutputStream os) throws IOException { + PDFOutput pos = new PDFOutput(os); + + // Write each object to the OutputStream. We call via the output + // as that builds the xref table + for (PDFObject o : objects) { + pos.write(o); + } + + // Finally close the output, which writes the xref table. + pos.close(); + + // and flush the output stream to ensure everything is written. + os.flush(); + } + } // end class PDFDocument diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFEmbeddedFont.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFEmbeddedFont.java index c2ba06b93..9b4a30102 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFEmbeddedFont.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFEmbeddedFont.java @@ -51,14 +51,14 @@ public class PDFEmbeddedFont extends PDFFont { os.write((" " + i).getBytes()); } os.write(("]\n").getBytes()); -*/ + */ //os.write("/Widths [500 583 587 796]".getBytes()); /*os.write("/FontDescriptor ".getBytes()); os.write(descriptor.getBytes()); os.write("\n".getBytes());*/ - /*os.write("/ToUnicode ".getBytes()); + /*os.write("/ToUnicode ".getBytes()); os.write(toUnicode.getBytes()); os.write("\n".getBytes());*/ // finish off with its footer diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFFont.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFFont.java index 93be6adc4..404f50b93 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFFont.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFFont.java @@ -32,219 +32,217 @@ import java.io.Serializable; * @author Gilbert DeLeeuw, gil1@users.sourceforge.net * @version $Revision: 1.3 $, $Date: 2007/08/26 19:00:11 $ */ -public class PDFFont extends PDFObject implements Serializable -{ +public class PDFFont extends PDFObject implements Serializable { - /* + /* * NOTE: The original class is the work of Peter T. Mount, who released it * in the uk.org.retep.pdf package. It was modified by Eric Z. Beard as * follows: * The package name was changed to gnu.pdf. * The formatting was changed a little bit * It is still licensed under the LGPL. - */ - - /** - * The PDF document name of the font - */ - private String name; - - /** - * The PDF type of the font, usually /Type1 - */ - private String type; - - /** - * The font's real name - */ - private String font; - - /** - * The name of the equivalent Java font - */ - private String javaFont; - - /** - * The PDF Style, ie: BOLD, ITALIC, etc - */ - private int style; - - /** - * This constructs a default PDFFont. In this case Helvetica - */ - protected PDFFont() { - this("/F1","/Type1","Helvetica",Font.PLAIN); - } - - /** - * Constructs a PDFFont. This will attempt to map the font from a known - * Java font name to that in PDF, defaulting to Helvetica if not possible. - * - * @param name The document name, ie /F1 - * @param type The pdf type, ie /Type1 - * @param font The font name, ie Helvetica - * @param style The java.awt.Font style, ie: Font.PLAIN - */ - public PDFFont(String name,String type,String font,int style) { - super("/Font"); - this.name = name; - this.type = type; - this.style = style; - - String f = font.toLowerCase(); - - // default PDF Font name + */ + /** + * The PDF document name of the font + */ + private String name; + + /** + * The PDF type of the font, usually /Type1 + */ + private String type; + + /** + * The font's real name + */ + private String font; + + /** + * The name of the equivalent Java font + */ + private String javaFont; + + /** + * The PDF Style, ie: BOLD, ITALIC, etc + */ + private int style; + + /** + * This constructs a default PDFFont. In this case Helvetica + */ + protected PDFFont() { + this("/F1", "/Type1", "Helvetica", Font.PLAIN); + } + + /** + * Constructs a PDFFont. This will attempt to map the font from a known Java + * font name to that in PDF, defaulting to Helvetica if not possible. + * + * @param name The document name, ie /F1 + * @param type The pdf type, ie /Type1 + * @param font The font name, ie Helvetica + * @param style The java.awt.Font style, ie: Font.PLAIN + */ + public PDFFont(String name, String type, String font, int style) { + super("/Font"); + this.name = name; + this.type = type; + this.style = style; + + String f = font.toLowerCase(); + + // default PDF Font name // this.font = base14[0][1]; // this.javaFont = base14[0][0]; - this.font = font; - this.javaFont = "/" + font; - - // attempt to translate the font name from Java to PDF - for(int i=0;i usedImages = new WeakHashMap(); private Color background; /** * This is true for any Graphics instance that didn't create the stream. * @see #create */ private boolean child; private Area clip; /** * This holds the current clipRectangle */ protected Rectangle clipRectangle; private Composite composite; private Graphics2D dg2 = new BufferedImage(2, 2, BufferedImage.TYPE_INT_RGB).createGraphics(); /** * This is the current font (in Java format) */ private Font font; /** * Part of the optimizer: * When true, we are drawing a path. */ private boolean inStroke; /** * Part of the optimizer: * When true, we are within a Text Block. */ private boolean inText; // true if within a Text Block - see newTextBlock() /** * The stroke line cap code; */ private int lineCap = 0; /** * The stroke line join code */ private int lineJoin = 0; /** * The stroke line width */ private float lineWidth = 1.0f; /** * Part of the optimizer: * The last known moveto/lineto x coordinate * @see #moveto * @see #lineto */ private float lx; // last known moveto/lineto coordinates /** * Part of the optimizer: * The last known moveto/lineto y coordinate * @see #moveto * @see #lineto */ private float ly; // last known moveto/lineto coordinates private float miterLimit = 10.0f; /** * Part of the optimizer: * When true, the font has changed. */ private boolean newFont; // true if the font changes - see newTextBlock() /** * This is a reference to the PDFPage we are rendering to. */ private PDFPage page; /** * This is the current pen/fill color */ private Paint paint; /** * This is the current font (in PDF format) */ private PDFFont pdffont; /** * Part of the optimizer: * This is written to the stream when the newPath() is called. np then clears * this value. */ private String pre_np; // PDF space transform private AffineTransform pTransform; /** * This is the PrintWriter used to write PDF drawing commands to the Stream */ private RawPrintWriter pw; /** * RenderingHints */ private RenderingHints rhints = new RenderingHints(null); private Stroke stroke; // Start of Graphics2D properties private AffineTransform transform; /** * Part of the optimizer: * The last x coordinate when rendering text */ private float tx; // the last coordinate for text rendering /** * Part of the optimizer: * The last y coordinate when rendering text */ private float ty; // the last coordinate for text rendering /** * @see Graphics2D#addRenderingHints(Map) */ public void addRenderingHints(Map hints) { rhints.putAll(hints); } /** * This produces an arc by breaking it down into one or more Bezier curves. * It is used internally to implement the drawArc and fillArc methods. * * @param axc X coordinate of arc centre * @param ayc Y coordinate of arc centre * @param width of bounding rectangle * @param height of bounding rectangle * @param ang1 Start angle * @param ang2 End angle * @param clockwise true to draw clockwise, false anti-clockwise */ public void arc(double axc,double ayc, double width,double height, double ang1,double ang2, boolean clockwise) { double adiff; double x0, y0; double x3r, y3r; boolean first = true; // may not need this //if( ar < 0 ) { //ang1 += fixed_180; //ang2 += fixed_180; //ar = - ar; //} double ang1r = (ang1%360.0)*degrees_to_radians; double sin0 = Math.sin(ang1r); double cos0 = Math.cos(ang1r); x0 = axc + width*cos0; y0 = ayc + height*sin0; // NB: !clockwise here as Java Space is inverted to User Space if( !clockwise ) { // Quadrant reduction while ( ang1 < ang2 ) ang2 -= 360.0; while ( (adiff = ang2 - ang1) < -90.0 ) { double w = sin0; sin0 = -cos0; cos0 = w; x3r = axc + width*cos0; y3r = ayc + height*sin0; arc_add(first, width, height, x0, y0, x3r, y3r, (x0 + width*cos0), (y0 + height*sin0) ); x0 = x3r; y0 = y3r; ang1 -= 90.0; first = false; } } else { // Quadrant reduction while ( ang2 < ang1 ) ang2 += 360.0; while ( (adiff = ang2 - ang1) > 90.0 ) { double w = cos0; cos0 = -sin0; sin0 = w; x3r = axc + width*cos0; y3r = ayc + height*sin0; arc_add(first, width, height, x0, y0, x3r, y3r, (x0 + width*cos0), (y0 + height*sin0) ); x0 = x3r; y0 = y3r; ang1 += 90.0; first = false; } } // Compute the intersection of the tangents. // We know that -fixed_90 <= adiff <= fixed_90. double trad = Math.tan(adiff * (degrees_to_radians / 2)); double ang2r = ang2 * degrees_to_radians; double xt = x0 - trad * width*sin0; double yt = y0 + trad * height*cos0; arc_add(first, width, height, x0, y0, (axc + width * Math.cos(ang2r)), (ayc + height * Math.sin(ang2r)), xt, yt); } /** * Used by the arc method to actually add an arc to the path * Important: We write directly to the stream here, because this method * operates in User space, rather than Java space. * @param first true if the first arc * @param w width * @param h height * @param x0 coordinate * @param y0 coordinate * @param x3 coordinate * @param y3 coordinate * @param xt coordinate * @param yt coordinate */ private void arc_add(boolean first, double w,double h, double x0,double y0, double x3,double y3, double xt,double yt) { double dx = xt - x0, dy = yt - y0; double dist = dx*dx + dy*dy; double w2 = w*w, h2=h*h; double r2 = w2+h2; double fw = 0.0, fh = 0.0; if(dist < (r2*1.0e8)) { // JM fw = (w2 != 0.0) ? ((4.0/3.0)/(1+Math.sqrt(1+dist/w2))) : 0.0; fh = (h2 != 0.0) ? ((4.0/3.0)/(1+Math.sqrt(1+dist/h2))) : 0.0; } // The path must have a starting point if(first) moveto(x0,y0); double x = x0+((xt-x0)*fw); double y = y0+((yt-y0)*fh); x0 = x3+((xt-x3)*fw); y0 = y3+((yt-y3)*fh); // Finally the actual curve. curveto(x,y,x0,y0,x3,y3); } /** * This simply draws a White Rectangle to clear the area * @param x coordinate * @param y coordinate * @param w width * @param h height */ public void clearRect(int x,int y,int w,int h) { closeBlock(); pw.print("q 1 1 1 RG ");// save state, set colour to White drawRect(x,y,w,h); closeBlock("B Q"); // close fill & stroke, then restore state } /** * @see Graphics2D#clip(Shape) */ public void clip(Shape s) { if (s == null) { setClip(null); return; } if (clip == null) clip = new Area(s); else clip.intersect(new Area(s)); // followPath(s, CLIP); } /** * This extra method allows PDF users to clip to a Polygon. * *

In theory you could use setClip(), except that java.awt.Graphics * only supports Rectangle with that method, so we will have an extra * method. * @param p Polygon to clip to */ public void clipPolygon(Polygon p) { closeBlock(); // finish off any existing path polygon(p.xpoints,p.ypoints,p.npoints); closeBlock("W"); // clip to current path clipRectangle = p.getBounds(); } /** * Clips to a set of coordinates * @param x coordinate * @param y coordinate * @param w width * @param h height */ public void clipRect(int x,int y,int w,int h) { setClip(x,y,w,h); } /** * All functions should call this to close any existing optimized blocks. */ void closeBlock() { closeBlock("S"); } /** *

This is used by code that use the path in any way other than Stroke * (like Fill, close path & Stroke etc). Usually this is used internally.

* * @param code PDF operators that will close the path */ void closeBlock(String code) { if(inText) { pw.println("ET Q"); // setOrientation(); // fixes Orientation matrix } if(inStroke) { pw.println(code); } inStroke=inText=false; } /** * This is unsupported - how do you do this with Vector graphics? * @param x coordinate * @param y coordinate * @param w width * @param h height * @param dx coordinate * @param dy coordinate */ public void copyArea(int x,int y,int w,int h,int dx,int dy) { // Hmm... Probably need to keep track of everything // that has been drawn so far to get the contents of an area } //============ Line operations ======================= /** *

This returns a child instance of this Graphics object. As with AWT, the * affects of using the parent instance while the child exists, is not * determined.

* *

Once complete, the child should be released with it's dispose() * method which will restore the graphics state to it's parent.

* * @return Graphics object to render onto the page */ @Override public Graphics create() { closeBlock(); PDFGraphics g = createGraphic(page,pw); // The new instance inherits a few items g.clipRectangle = new Rectangle(clipRectangle); return (Graphics) g; } // end create() /** * This method creates a new instance of the class based on the page * and a print writer. * * @param page the page to attach to * @param pw the PrintWriter to attach to. */ protected PDFGraphics createGraphic(PDFPage page, RawPrintWriter pw) { PDFGraphics g = new PDFGraphics(); g.init(page,pw); return g; } /** * This extension appends a Bezier curve to the path. The curve * extends from the current point to (x2,y2) using the current * point and (x1,y1) as the Bezier control points. *

The new current point is (x2,y2) * * @param x1 Second control point * @param y1 Second control point * @param x2 Destination point * @param y2 Destination point */ public void curveto(double x1,double y1,double x2,double y2) { newPath(); pw.println(cxy(x1,y1)+cxy(x2,y2)+"v"); lx=(float)x2; ly=(float)y2; } /** * This extension appends a Bezier curve to the path. The curve * extends from the current point to (x3,y3) using (x1,y1) and * (x2,y2) as the Bezier control points. *

The new current point is (x3,y3) * * @param x1 First control point * @param y1 First control point * @param x2 Second control point * @param y2 Second control point * @param x3 Destination point * @param y3 Destination point */ public void curveto(double x1,double y1,double x2,double y2,double x3,double y3) { newPath(); pw.println(cxy(x1,y1)+cxy(x2,y2)+cxy(x3,y3)+"c"); lx=(float)x3; ly=(float)y3; } /** * This extension appends a Bezier curve to the path. The curve * extends from the current point to (x2,y2) using the current * point and (x1,y1) as the Bezier control points. *

The new current point is (x2,y2) * * @param x1 Second control point * @param y1 Second control point * @param x2 Destination point * @param y2 Destination point */ public void curveto(int x1,int y1,int x2,int y2) { newPath(); pw.println(cxy(x1,y1)+cxy(x2,y2)+"v"); lx=x2; ly=y2; } /** * This extension appends a Bezier curve to the path. The curve * extends from the current point to (x3,y3) using (x1,y1) and * (x2,y2) as the Bezier control points. *

The new current point is (x3,y3) * * @param x1 First control point * @param y1 First control point * @param x2 Second control point * @param y2 Second control point * @param x3 Destination point * @param y3 Destination point */ public void curveto(int x1,int y1,int x2,int y2,int x3,int y3) { newPath(); pw.println(cxy(x1,y1)+cxy(x2,y2)+cxy(x3,y3)+"c"); lx=x3; ly=y3; } /** * This extension appends a Bezier curve to the path. The curve * extends from the current point to (x2,y2) using (x1,y1) and * the end point as the Bezier control points. *

The new current point is (x2,y2) * * @param x1 Second control point * @param y1 Second control point * @param x2 Destination point * @param y2 Destination point */ public void curveto2(double x1,double y1,double x2,double y2) { newPath(); pw.println(cxy(x1,y1)+cxy(x2,y2)+"y"); lx=(float)x2; ly=(float)y2; } // Arcs are horrible and complex. They are at the end of the // file, because they are the largest. This is because, unlike // Postscript, PDF doesn't have any arc operators, so we must // implement them by converting into one or more Bezier curves // (which is how Postscript does them internally). /** * This extension appends a Bezier curve to the path. The curve * extends from the current point to (x2,y2) using (x1,y1) and * the end point as the Bezier control points. *

The new current point is (x2,y2) * * @param x1 Second control point * @param y1 Second control point * @param x2 Destination point * @param y2 Destination point */ public void curveto2(int x1,int y1,int x2,int y2) { newPath(); pw.println(cxy(x1,y1)+cxy(x2,y2)+"y"); lx=x2; ly=y2; } /** * Converts the Java space dimension into pdf. * @param w width * @param h height * @return String containing the coordinates in PDF space */ private String cwh(double w,double h) { double nw=w,nh=h; // scratch // switch(mediaRot) { // case PageFormat.PORTRAIT: // Portrait //nw = w; nh = -h; // break; // // case PageFormat.LANDSCAPE: // // Landscape // nw = h; // nh = w; // break; // //// case 180: //// // Inverse Portrait //// nw = -w; //// //nh = h; //// break; // // case PageFormat.REVERSE_LANDSCAPE: // // Seascape // nw = -h; // nh = -w; // break; // } return ""+df.format(nw)+" "+df.format(nh)+" "; } /** * Converts the Java space dimension into pdf. * @param w width * @param h height * @return String containing the coordinates in PDF space */ private String cwh(int w,int h) { return cwh((double)w,(double)h); } /** * Converts the Java space coordinates into pdf. * @param x coordinate * @param y coordinate * @return String containing the coordinates in PDF space */ private String cxy(double x, double y) { return "" + df.format(x) + " " + df.format(y) + " "; } /** * Converts the Java space coordinates into pdf. * @param x coordinate * @param y coordinate * @return String containing the coordinates in PDF space */ private String cxy(int x,int y) { return cxy((double)x,(double)y); } /** *

This releases any resources used by this Graphics object. You must use * this method once finished with it. Leaving it open will leave the PDF * stream in an inconsistent state, and will produce errors.

* *

If this was created with Graphics.create() then the parent instance * can be used again. If not, then this closes the graphics operations for * this page when used with PDFJob.

* *

When using PDFPage, you can create another fresh Graphics instance, * which will draw over this one.

* */ public void dispose() { closeBlock(); if(child) { pw.println("Q"); // restore graphics context } else { pw.close(); // close the stream if were the parent } } // ********************************************* // **** Implementation of java.awt.Graphics **** // ********************************************* //============ Rectangle operations ======================= /** * @see Graphics2D#draw(Shape) */ public void draw(Shape s) { followPath(s, STROKE); } /** *

Not implemented

* *

Draws a 3-D highlighted outline of the specified rectangle. * The edges of the rectangle are highlighted so that they appear * to be beveled and lit from the upper left corner. * The colors used for the highlighting effect are determined based on * the current color. The resulting rectangle covers an area that * is width + 1 pixels wide by height + 1 pixels tall. *

* * @param x an int value * @param y an int value * @param width an int value * @param height an int value * @param raised a boolean value */ public void draw3DRect(int x, int y, int width, int height, boolean raised) { // Not implemented } /** * Draws an arc * @param x coordinate * @param y coordinate * @param w width * @param h height * @param sa Start angle * @param aa End angle */ public void drawArc(int x,int y,int w,int h,int sa,int aa) { w=w>>1; h=h>>1; x+=w; y+=h; arc((double)x,(double)y, (double)w,(double)h, (double)-sa,(double)(-sa-aa), false); } /** *

Not implemented

* * @param data a byte[] value * @param offset an int value * @param length an int value * @param x an int value * @param y an int value */ public void drawBytes(byte[] data, int offset, int length, int x, int y) { } //============ Optimizers ======================= /** * @see Graphics2D#drawGlyphVector(GlyphVector, float, float) */ public void drawGlyphVector(GlyphVector g, float x, float y) { Shape s = g.getOutline(x, y); fill(s); } /** * @see Graphics2D#drawImage(BufferedImage, BufferedImageOp, int, int) */ public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { BufferedImage result = img; if (op != null) { result = op.createCompatibleDestImage(img, img.getColorModel()); result = op.filter(img, result); } drawImage(result, x, y, null); } /** * @see Graphics2D#drawImage(Image, AffineTransform, ImageObserver) */ public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { // return drawImage(img, null, xform, null, obs); return true; } /** *

Draw's an image onto the page, with a backing colour.

* * @param img The java.awt.Image * @param x coordinate on page * @param y coordinate on page * @param bgcolor Background colour * @param obs ImageObserver * @return true if drawn */ public boolean drawImage(Image img,int x,int y,Color bgcolor, ImageObserver obs) { return drawImage(img,x,y,img.getWidth(obs),img.getHeight(obs), bgcolor,obs); } /** * Draw's an image onto the page * @param img The java.awt.Image * @param x coordinate on page * @param y coordinate on page * @param obs ImageObserver * @return true if drawn */ public boolean drawImage(Image img,int x,int y,ImageObserver obs) { return drawImage(img,x,y,img.getWidth(obs),img.getHeight(obs),obs); } /** *

Draw's an image onto the page, with a backing colour.

* * @param img The java.awt.Image * @param x coordinate on page * @param y coordinate on page * @param w Width on page * @param h height on page * @param bgcolor Background colour * @param obs ImageObserver * @return true if drawn */ public boolean drawImage(Image img,int x,int y,int w,int h, Color bgcolor,ImageObserver obs) { closeBlock(); pw.print("q "); // save state Color c = getColor(); // save current colour setColor(bgcolor); // change the colour drawRect(x,y,w,h); closeBlock("B Q"); // fill stroke, restore state paint = c; // restore original colour return drawImage(img,x,y,img.getWidth(obs),img.getHeight(obs),obs); } /** *

Draws an image onto the page.

* *

This method is implemented with ASCIIbase85 encoding and the * zip stream deflater. It results in a stream that is anywhere * from 3 to 10 times as big as the image. This obviously needs some * improvement, but it works well for small images

* * @param img The java.awt.Image * @param x coordinate on page * @param y coordinate on page * @param w Width on page * @param h height on page * @param obs ImageObserver * @return true if drawn */ public boolean drawImage(Image img,int x,int y,int w,int h, ImageObserver obs) { closeBlock(); PDFImage image; if (usedImages.containsKey(img)) { image = usedImages.get(img); } else { image = new PDFImage(img, x, y, w, h, obs); // The image needs to be registered in several places page.getPDFDocument().setImageName(image); page.getPDFDocument().add(image); usedImages.put(img, image); } page.addToProcset("/ImageC"); page.addImageResource(image.getName() + " " + image.getSerialID() + " 0 R"); // JM /*page.addResource("/XObject << " + image.getName() + " " + image.getSerialID() + " 0 R >>");*/ // q w 0 0 h x y cm % the coordinate matrix AffineTransform newTransform = new AffineTransform(w, 0, 0, h, x, y); newTransform.preConcatenate(pTransform); AffineTransform transformToSet = newTransform; pw.print("q " + transformToSet.getScaleX() + " " + transformToSet.getShearY() + " " + transformToSet.getShearX() + " " + transformToSet.getScaleY() + " " + transformToSet.getTranslateX() + " " + transformToSet.getTranslateY() + " cm \n" + image.getName() + " Do\nQ\n"); return false; } /** * Draw's an image onto the page, with scaling *

This is not yet supported. * * @param img The java.awt.Image * @param dx1 coordinate on page * @param dy1 coordinate on page * @param dx2 coordinate on page * @param dy2 coordinate on page * @param sx1 coordinate on image * @param sy1 coordinate on image * @param sx2 coordinate on image * @param sy2 coordinate on image * @param bgcolor Background colour * @param obs ImageObserver * @return true if drawn */ public boolean drawImage(Image img,int dx1,int dy1,int dx2, int dy2,int sx1,int sy1,int sx2,int sy2, Color bgcolor,ImageObserver obs) { return false; } //============ Clipping operations ======================= /** * Draw's an image onto the page, with scaling *

This is not yet supported. * * @param img The java.awt.Image * @param dx1 coordinate on page * @param dy1 coordinate on page * @param dx2 coordinate on page * @param dy2 coordinate on page * @param sx1 coordinate on image * @param sy1 coordinate on image * @param sx2 coordinate on image * @param sy2 coordinate on image * @param obs ImageObserver * @return true if drawn */ public boolean drawImage(Image img,int dx1,int dy1,int dx2, int dy2,int sx1,int sy1,int sx2,int sy2, ImageObserver obs) { // This shouldn't be too bad, just change the coordinate matrix return false; } /** * Draws a line between two coordinates. * * If the first coordinate is the same as the last one drawn * (i.e. a previous drawLine, moveto, etc) it is ignored. * @param x1 coordinate * @param y1 coordinate * @param x2 coordinate * @param y2 coordinate */ public void drawLine(int x1,int y1,int x2,int y2) { moveto(x1,y1); lineto(x2,y2); } //============ Arcs operations ============================== // These are the standard Graphics operators. They use the // arc extension operators to achieve the affect. /** *

Draws an oval

* * @param x coordinate * @param y coordinate * @param w width * @param h height */ public void drawOval(int x,int y,int w,int h) { drawArc(x, y, w, h, 0, 360); } /** * Draws a polygon, linking the first and last coordinates. * @param xp Array of x coordinates * @param yp Array of y coordinates * @param np number of points in polygon */ public void drawPolygon(int[] xp,int[] yp,int np) { polygon(xp,yp,np); closeBlock("s"); // close path and stroke } /** * Draws a polyline. The first and last coordinates are not linked. * @param xp Array of x coordinates * @param yp Array of y coordinates * @param np number of points in polyline */ public void drawPolyline(int[] xp,int[] yp,int np) { polygon(xp,yp,np); // no stroke, as we keep the optimizer in stroke state } /** * We override Graphics.drawRect as it doesn't join the 4 lines. * Also, PDF provides us with a Rectangle operator, so we will use that. * @param x coordinate * @param y coordinate * @param w width * @param h height */ public void drawRect(int x,int y,int w,int h) { newPath(); pw.print(cxy(x,y)+cwh(w,h)+"re "); // rectangle lx=x; // I don't know if this is correct, but lets see if PDF ends ly=y; // the rectangle at it's start. // stroke (optimized) } /** * @see Graphics2D#drawRenderableImage(RenderableImage, AffineTransform) */ public void drawRenderableImage(RenderableImage img, AffineTransform xform) { drawRenderedImage(img.createDefaultRendering(), xform); } /** * @see Graphics2D#drawRenderedImage(RenderedImage, AffineTransform) */ public void drawRenderedImage(RenderedImage img, AffineTransform xform) { BufferedImage image = null; if (img instanceof BufferedImage) { image = (BufferedImage)img; } else { ColorModel cm = img.getColorModel(); int width = img.getWidth(); int height = img.getHeight(); WritableRaster raster = cm.createCompatibleWritableRaster(width, height); boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); Hashtable properties = new Hashtable(); String[] keys = img.getPropertyNames(); if (keys!=null) { for (int i = 0; i < keys.length; i++) { properties.put(keys[i], img.getProperty(keys[i])); } } BufferedImage result = new BufferedImage(cm, raster, isAlphaPremultiplied, properties); img.copyData(raster); image=result; } drawImage(image, xform, null); } /** * This is not yet implemented * * @param x coordinate * @param y coordinate * @param w width * @param h height * @param aw a-width * @param ah a-height */ public void drawRoundRect(int x,int y,int w,int h,int aw,int ah) { } //============ Oval operations ======================= /** * Draws a string using a AttributedCharacterIterator. *

This is not supported yet, as I have no idea what an * AttributedCharacterIterator is. *

This method is new to the Java2 API. */ public void drawString(java.text.AttributedCharacterIterator aci, float x,float y) { } /** * Draws a string using a AttributedCharacterIterator. *

This is not supported yet, as I have no idea what an * AttributedCharacterIterator is. *

This method is new to the Java2 API. */ public void drawString(java.text.AttributedCharacterIterator aci, int x,int y) { } public void drawStringWithMode(String s, float x, float y, int mode) { newTextBlock(x, y); if (mode > -1) { pw.println("" + mode + " Tr"); } if (pdffont instanceof PDFEmbeddedFont) { pw.print("[("); pw.printRaw(PDFStringHelper.makeRawPDFString(s)); pw.println(")] TJ"); } else { pw.print(PDFStringHelper.makePDFString(s)); pw.println(" Tj"); } closeBlock(); } @Override public void drawString(String s, float x, float y) { drawStringWithMode(s, x, y, -1); } /** * This draws a string. * * @param s * @oaran s String to draw * @param x coordinate * @param y coordinate */ @Override public void drawString(String s,int x,int y) { drawString(s, (float) x, (float) y); } public void drawTransparentString(String s, float x, float y) { drawStringWithMode(s, x, y, 3); } /** * This draws a transparent string. * * @oaran s String to draw * @param x coordinate * @param y coordinate */ public void drawTransparentString(String s, int x, int y) { drawTransparentString(s, (float) x, (float) y); } /** * @see Graphics2D#fill(Shape) */ public void fill(Shape s) { followPath(s, FILL); } /** *

Not implemented

* * @param x an int value * @param y an int value * @param width an int value * @param height an int value * @param raised a boolean value */ public void fill3DRect(int x, int y, int width, int height, boolean raised) { // Not implemented } /** * Fills an arc, joining the start and end coordinates * @param x coordinate * @param y coordinate * @param w width * @param h height * @param sa Start angle * @param aa End angle */ public void fillArc(int x,int y,int w,int h,int sa,int aa) { // here we fool the optimizer. We force any open path to be closed, // then draw the arc. Finally, as the optimizer hasn't stroke'd the // path, we close and fill it, and mark the Stroke as closed. // // Note: The lineto to the centre of the object is required, because // the fill only fills the arc. Skipping this includes an extra // chord, which isn't correct. Peter May 31 2000 closeBlock(); drawArc(x,y,w,h,sa,aa); lineto(x+(w>>1),y+(h>>1)); closeBlock("b"); // closepath and fill } //============ Extension operations ============================== // These are extensions, and provide access to PDF Specific // operators. /** *

Draws a filled oval

* * @param x coordinate * @param y coordinate * @param w width * @param h height */ public void fillOval(int x,int y,int w,int h) { fillArc(x, y, w, h, 0, 360); } //============ Polygon operations ======================= /** * Fills a polygon. * @param xp Array of x coordinates * @param yp Array of y coordinates * @param np number of points in polygon */ public void fillPolygon(int[] xp,int[] yp,int np) { closeBlock(); // finish off any previous paths polygon(xp,yp,np); closeBlock("b"); // closepath, fill and stroke } //============ Image operations ======================= /** * Fills a rectangle with the current colour * * @param x coordinate * @param y coordinate * @param w width * @param h height */ public void fillRect(int x,int y,int w,int h) { // end any path & stroke. This ensures the fill is on this // rectangle, and not on any previous graphics closeBlock(); drawRect(x,y,w,h); closeBlock("B"); // rectangle, fill stroke } //============ Round Rectangle operations ======================= /** * This is not yet implemented * * @param x coordinate * @param y coordinate * @param w width * @param h height * @param aw a-width * @param ah a-height */ public void fillRoundRect(int x,int y,int w,int h,int aw,int ah) { } /////////////////////////////////////////////// // // // implementation specific methods // // private void followPath(Shape s, int drawType) { PathIterator points; if (s==null) return; if (drawType==STROKE) { if (!(stroke instanceof BasicStroke)) { s = stroke.createStrokedShape(s); followPath(s, FILL); return; } } // if (drawType==STROKE) { // setStrokeDiff(stroke, oldStroke); // oldStroke = stroke; // setStrokePaint(); // } // else if (drawType==FILL) // setFillPaint(); points = s.getPathIterator(IDENTITY); int segments = 0; float[] coords = new float[6]; while(!points.isDone()) { segments++; int segtype = points.currentSegment(coords); switch(segtype) { case PathIterator.SEG_CLOSE: pw.print("h "); break; case PathIterator.SEG_CUBICTO: curveto(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); break; case PathIterator.SEG_LINETO: lineto(coords[0], coords[1]); break; case PathIterator.SEG_MOVETO: moveto(coords[0], coords[1]); break; case PathIterator.SEG_QUADTO: curveto(coords[0], coords[1], coords[2], coords[3]); break; } points.next(); } switch (drawType) { case FILL: if (segments > 0) { if (points.getWindingRule() == PathIterator.WIND_EVEN_ODD) closeBlock("B*"); else closeBlock("B"); } break; case STROKE: if (segments > 0) closeBlock("S"); break; case CLIP: default: //drawType==CLIP if (segments == 0) drawRect(0, 0, 0, 0); if (points.getWindingRule() == PathIterator.WIND_EVEN_ODD) closeBlock("W*"); else closeBlock("W"); } } /** * @see Graphics2D#getBackground() */ public Color getBackground() { return background; } /** * Returns the Shape of the clipping region * As my JDK docs say, this may break with Java 2D. * @return Shape of the clipping region */ public Shape getClip() { return null; } /** * Returns the Rectangle that fits the current clipping region * @return the Rectangle that fits the current clipping region */ public Rectangle getClipBounds() { return clipRectangle; } //============ Color operations ======================= /** * Returns the current pen Colour * @return the current pen Colour */ public Color getColor() { return (paint instanceof Color) ? (Color) paint : Color.black; } /** * @see Graphics2D#getComposite() */ public Composite getComposite() { return composite; } /** * @see Graphics2D#getDeviceConfiguration() */ public GraphicsConfiguration getDeviceConfiguration() { return dg2.getDeviceConfiguration(); } /** * Return's the current font. * @return the current font. */ public Font getFont() { if(font==null) setFont(new Font("SansSerif",Font.PLAIN,12)); return font; } /** * Returns the FontMetrics for a font. *

This doesn't work correctly. Perhaps having some way of mapping * the base 14 fonts to our own FontMetrics implementation? * @param font The java.awt.Font to return the metrics for * @return FontMetrics for a font */ public FontMetrics getFontMetrics(Font font) { Frame dummy = new Frame(); dummy.addNotify(); Image image = dummy.createImage(100, 100); if (image == null) { System.err.println("getFontMetrics: image is null"); } Graphics graphics = image.getGraphics(); return graphics.getFontMetrics(font); } /** * @see Graphics2D#getFontRenderContext() */ public FontRenderContext getFontRenderContext() { boolean antialias = RenderingHints.VALUE_TEXT_ANTIALIAS_ON.equals(getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING)); boolean fractions = RenderingHints.VALUE_FRACTIONALMETRICS_ON.equals(getRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS)); return new FontRenderContext(new AffineTransform(), antialias, fractions); } /** * Returns the associated PDFPage for this graphic * @return the associated PDFPage for this graphic */ public PDFPage getPage() { return page; } /** * Returns the current pen Colour * @return the current pen Colour */ public Paint getPaint() { return paint; } /** * @param arg0 a key * @return the rendering hint */ public Object getRenderingHint(Key arg0) { return rhints.get(arg0); } /** * @see Graphics2D#getRenderingHints() */ public RenderingHints getRenderingHints() { return rhints; } /** * @see Graphics2D#getStroke() */ public Stroke getStroke() { return stroke; } /** * @see Graphics2D#getTransform() */ public AffineTransform getTransform() { return new AffineTransform(transform); } /** * Returns the PrintWriter handling the underlying stream * @return the PrintWriter handling the underlying stream */ public RawPrintWriter getWriter() { return pw; } /** * @see Graphics2D#hit(Rectangle, Shape, boolean) */ public boolean hit(Rectangle rect, Shape s, boolean onStroke) { if (onStroke) { s = stroke.createStrokedShape(s); } Area area = new Area(s); if (clip != null) area.intersect(clip); return area.intersects(rect.x, rect.y, rect.width, rect.height); } /** * This initialises the stream by saving the current graphics state, and * setting up the default line width (for us). * * It also sets up the instance ready for graphic operations and any * optimisations. * *

For child instances, the stream is already open, so this should keep * things happy. */ private void init() { PageFormat pf = page.getPageFormat(); // save graphics state (restored by dispose) if(child) { pw.print("q "); } // now initialise the instance //setColor(Color.black); paint = Color.black; // possible: if parent.color is not black, then force black? // must check to see what AWT does? // Original User Space Transform (identity) // Transform from Java Space to PDF Space pTransform = new AffineTransform(); pTransform.translate(0, pf.getHeight()); pTransform.scale(1d, -1d); // Combined Transform User->Java->PDF setNewTranform(new AffineTransform()); // Set the line width setStroke(DEF_STROKE); } /** * This is called by PDFPage when creating a Graphcis instance. * @param page The PDFPage to draw onto. */ protected void init(PDFPage page) { this.page = page; // We are the parent instance child = false; // Now create a stream to store the graphics in PDFStream stream = new PDFStream(); // To view detail in uncompressed format comment out the next line stream.setDeflate(true); page.getPDFDocument().add(stream); page.add(stream); pw = new RawPrintWriter(stream.getOutputStream()); // initially, we are limited to the page size clipRectangle = page.getImageableArea(); // finally initialise the stream init(); } /** * This method is used internally by create() and by the PDFJob class * @param page PDFPage to draw into * @param pw PrintWriter to use */ protected void init(PDFPage page, RawPrintWriter pw) { this.page = page; this.pw = pw; // In this case, we didn't create the stream (our parent did) // so child is true (see dispose) child = true; // finally initialise the stream init(); } /** * This adds a line segment to the current path * @param x coordinate * @param y coordinate */ public void lineto(double x,double y) { newPath(); // no optimisation here as it may introduce errors on decimal coordinates. pw.print(cxy(x,y)+"l "); lx=(float)x; ly=(float)y; } /** * This adds a line segment to the current path * @param x coordinate * @param y coordinate */ public void lineto(int x,int y) { newPath(); if(lx!=x && ly!=y) pw.print(cxy(x,y)+"l "); lx=x; ly=y; } /** * This moves the current drawing point. * @param x coordinate * @param y coordinate */ public void moveto(double x,double y) { newPath(); // no optimisation here as it may introduce errors on decimal coordinates. pw.print(cxy(x,y)+"m "); lx=(float)x; ly=(float)y; } /** * This moves the current drawing point. * @param x coordinate * @param y coordinate */ public void moveto(int x,int y) { newPath(); if(lx!=x || ly!=y) pw.print(cxy(x,y)+"m "); lx=x; ly=y; } /** * Functions that draw lines should start by calling this. It starts a * new path unless inStroke is set, in that case it uses the existing path */ void newPath() { if(inText) { closeBlock(); } if(!inStroke) { if(pre_np!=null) { pw.print(pre_np); // this is the prefix set by setOrientation() pre_np = null; } pw.print("n "); } inText=false; inStroke=true; // an unlikely coordinate to fool the moveto() optimizer lx = ly = -9999; } /** *

Functions that draw text should start by calling this. It starts a text * block (accounting for media orientation) unless we are already in a Text * block.

* *

It also handles if the font has been changed since the current text * block was started, so your function will be current.

* * @param x x coordinate in java space * @param y y coordinate in java space */ void newTextBlock(float x,float y) { // close the current path if there is one if(inStroke) { closeBlock(); } // create the text block if one is not current. If we are, the newFont // condition at the end catches font changes if(!inText) { // This ensures that there is a font available getFont(); pw.print("q BT "); tx=ty=0; AffineTransform tm = new AffineTransform(pTransform); pw.println("" + df.format(tm.getScaleX()) + " " + "" + df.format(tm.getShearY()) + " " + "" + df.format(tm.getShearX()) + " " + "" + df.format(tm.getScaleY()) + " " + "" + df.format(tm.getTranslateX()) + " " + "" + df.format(tm.getTranslateY()) + " Tm" ); // produce the text matrix for the media // switch(mediaRot) { // case PageFormat.PORTRAIT: // Portrait // //pw.println("1 0 0 1 0 0 Tm"); // break; // // case PageFormat.LANDSCAPE: // Landscape // pw.println("0 1 -1 0 0 0 Tm"); // rotate // break; // // case 180: // Inverted Portrait // pw.println("1 0 0 -1 0 0 Tm"); // break; // // case PageFormat.REVERSE_LANDSCAPE: // Seascape // pw.println("0 -1 1 0 0 0 Tm"); // rotate // break; // } // move the text cursor by an absolute amount pw.print(txy(x,y)+"Td "); } else { // move the text cursor by a relative amount pw.print(twh(x, y, tx, ty) + "Td "); //pw.print(txy(x,y)+"Td "); } // preserve the coordinates for the next time tx = x; ty = y; if(newFont || !inText) pw.print(pdffont.getName()+" "+font.getSize()+" Tf "); // later add colour changes here (if required) inStroke = newFont = false; inText = true; } /** * This is used to add a polygon to the current path. * Used by drawPolygon(), drawPolyline() and fillPolygon() etal * @param xp Array of x coordinates * @param yp Array of y coordinates * @param np number of points in polygon * @see #drawPolygon * @see #drawPolyline * @see #fillPolygon */ public void polygon(int[] xp,int[] yp,int np) { // newPath() not needed here as moveto does it ;-) moveto(xp[0],yp[0]); for(int i=1;iSets the clipping region to that of a Shape. * @param s Shape to clip to. */ public void setClip(Shape s) { Rectangle r = s.getBounds(); setClip(r.x,r.y,r.width,r.height); } /** * Sets the color for drawing * @param c Color to use */ public void setColor(Color c) { setPaint(c); } /** * @see Graphics2D#setComposite(Composite) */ public void setComposite(Composite comp) { this.composite = comp; } /** * This extension sets the line width to the default of 1mm which is what * Java uses when drawing to a PrintJob. */ public void setDefaultLineWidth() { closeBlock(); // draw any path before we change the line width pw.println("1 w"); } /** * This sets the font. * @param f java.awt.Font to set to. */ public void setFont(Font f) { // optimize: Save some space if the font is already the current one. if(font!=f) { font = f; pdffont = page.getFont("/Type1",f.getName(),f.getStyle()); // mark the font as changed newFont = true; } } public void setExistingTtfFont(Font f) { if (font != f) { font = f; pdffont = page.getFont("/TrueType", f.getName(), f.getStyle()); // mark the font as changed newFont = true; } } public void setTtfFont(Font f, File file) throws IOException { if (font != f) { font = f; pdffont = page.getEmbeddedFont(f.getName(), f.getStyle(), file); // mark the font as changed newFont = true; } } private void setLineCap(int cap) { int lineCap = 0; switch (cap) { case BasicStroke.JOIN_MITER: lineCap = 0; break; case BasicStroke.JOIN_ROUND: lineCap = 1; break; case BasicStroke.JOIN_BEVEL: lineCap = 2; break; } if (this.lineCap != lineCap) { closeBlock(); // draw any path before we change the line width this.lineCap = lineCap; pw.println(""+lineCap+" J"); } } private void setLineJoin(int join) { int lineJoin = 0; switch (join) { case BasicStroke.JOIN_MITER: lineJoin = 0; break; case BasicStroke.JOIN_ROUND: lineJoin = 1; break; case BasicStroke.JOIN_BEVEL: lineJoin = 2; break; } if (this.lineJoin != lineJoin) { closeBlock(); // draw any path before we change the line width this.lineJoin = lineJoin; pw.println(""+lineJoin+" j"); } } /** * This extension allows the width of the drawn line to be set * @param width Line width in pdf graphic units (points) */ public void setLineWidth(float width) { if (width != this.lineWidth) { closeBlock(); // draw any path before we change the line width this.lineWidth = width; pw.println(""+width+" w"); } } private void setMiterLimit(float limit) { if (limit != this.miterLimit) { closeBlock(); // draw any path before we change the line width this.miterLimit = limit; pw.println(""+limit+" M"); } } /** * Sets the paint for drawing * @param paint Paint to use */ public void setPaint(Paint paint) { this.paint = paint; if (paint instanceof Color) { Color c = (Color) paint; double r = ((double) c.getRed()) / 255.0; double g = ((double) c.getGreen()) / 255.0; double b = ((double) c.getBlue()) / 255.0; closeBlock(); // This ensures any paths are drawn in the previous // colours pw.println("" + r + " " + g + " " + b + " rg " + r + " " + g + " " + b + " RG"); } } /** * Not implemented, as this is not supported in the PDF specification. */ public void setPaintMode() { } /** * Sets a rendering hint * @param arg0 * @param arg1 */ public void setRenderingHint(Key arg0, Object arg1) { if (arg1 != null) { rhints.put(arg0, arg1); } else { rhints.remove(arg0); } } // Add Graphics2D methods. /** * @see Graphics2D#setRenderingHints(Map) */ public void setRenderingHints(Map hints) { rhints.clear(); rhints.putAll(hints); } /** * @see Graphics2D#setStroke(Stroke) */ public void setStroke(Stroke s) { this.stroke = s; if (stroke instanceof BasicStroke) { BasicStroke bs = (BasicStroke) stroke; setLineCap(bs.getEndCap()); setLineJoin(bs.getLineJoin()); setLineWidth(bs.getLineWidth()); setMiterLimit(bs.getMiterLimit()); // TODO: Line dash pattern } } /** * @see Graphics2D#setTransform(AffineTransform) */ public void setTransform(AffineTransform t) { setNewTranform(new AffineTransform(t)); } /** * Not implemented, as this is not supported in the PDF specification. * @param c1 Color to xor with */ public void setXORMode(Color c1) { } //============ Text operations ======================= /** * @see Graphics2D#shear(double, double) */ public void shear(double shx, double shy) { AffineTransform newTransform = new AffineTransform(transform); newTransform.shear(shx, shy); setNewTranform(newTransform); } /** * @see Graphics2D#transform(AffineTransform) */ public void transform(AffineTransform tx) { AffineTransform newTransform = new AffineTransform(transform); newTransform.concatenate(tx); setNewTranform(newTransform); } /** * @see Graphics2D#translate(double, double) */ public void translate(double tx, double ty) { AffineTransform newTransform = new AffineTransform(transform); newTransform.translate(tx, ty); setNewTranform(newTransform); } /** * @see Graphics#translate(int, int) */ public void translate(int x, int y) { translate((double)x, (double)y); } /** * Converts the Java space coordinates into pdf text space. * @param x coordinate * @param y coordinate * @param tx coordinate * @param ty coordinate * @return String containing the coordinates in PDF text space */ private String twh(float x,float y,float tx,float ty) { float nx=x, ny=y; float ntx=tx, nty=ty; nx = (float) (x - tx); ny = (float) (y - ty); return ""+df.format(nx)+" "+df.format(ny)+" "; } /** * Converts the Java space coordinates into pdf text space. * @param x coordinate * @param y coordinate * @return String containing the coordinates in PDF text space */ private String txy(float x, float y) { Point2D ptSrc = new Point2D.Float(x, y); Point2D ptDst = new Point2D.Float(); pTransform.transform(ptSrc, ptDst); return "" + df.format(ptDst.getX()) + " " + df.format(ptDst.getY()) + " "; } private void setNewTranform(AffineTransform t) { closeBlock(); AffineTransform newTransform = new AffineTransform(t); AffineTransform transformToSet = new AffineTransform(newTransform); if (transform != null) { AffineTransform realTransformWithPTransform = new AffineTransform(transform); realTransformWithPTransform.preConcatenate(pTransform); AffineTransform inverted = new AffineTransform(realTransformWithPTransform); try { inverted.invert(); } catch (NoninvertibleTransformException ex) { Logger.getLogger(PDFGraphics.class.getName()).log(Level.SEVERE, null, ex); } AffineTransform newTransformWithPTransform = new AffineTransform(newTransform); newTransformWithPTransform.preConcatenate(pTransform); transformToSet = newTransformWithPTransform; transformToSet.preConcatenate(inverted); } else { transformToSet.preConcatenate(pTransform); } transform = newTransform; pw.println("" + df.format(transformToSet.getScaleX()) + " " + "" + df.format(transformToSet.getShearY()) + " " + "" + df.format(transformToSet.getShearX()) + " " + "" + df.format(transformToSet.getScaleY()) + " " + "" + df.format(transformToSet.getTranslateX()) + " " + "" + df.format(transformToSet.getTranslateY()) + " cm" ); } private void saveState() { pw.println("q"); } private void restoreState() { pw.println("Q"); } } // end class PDFGraphics \ No newline at end of file +/* * $Id: PDFGraphics.java,v 1.6 2007/09/22 12:58:40 gil1 Exp $ * * $Date: 2007/09/22 12:58:40 $ * * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package gnu.jpdf; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Composite; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.Image; import java.awt.Paint; import java.awt.Polygon; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.Stroke; import java.awt.RenderingHints.Key; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.ColorModel; import java.awt.image.ImageObserver; import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; import java.awt.image.renderable.RenderableImage; import java.awt.print.PageFormat; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.io.Serializable; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Hashtable; import java.util.Locale; import java.util.Map; import java.util.WeakHashMap; import java.util.logging.Level; import java.util.logging.Logger; /** * This class is our implementation of AWT's Graphics class. It provides a Java * standard way of rendering into a PDF Document's Page. * * @author Peter T Mount, http://www.retep.org.uk/pdf/ * @author Eric Z. Beard, ericzbeard@hotmail.com * @author Gilbert DeLeeuw, gil1@users.sourceforge.net * @version $Revision: 1.6 $, $Date: 2007/09/22 12:58:40 $ * @see gnu.jpdf.PDFGraphics */ public class PDFGraphics extends Graphics2D implements Serializable { /** * One degree in radians */ private static final double degrees_to_radians = Math.PI / 180.0; private static final int FILL = 1; private static final int STROKE = 2; private static final int CLIP = 3; private static final AffineTransform IDENTITY = new AffineTransform(); private static final Stroke DEF_STROKE = new BasicStroke(); /* * NOTE: The original class is the work of Peter T. Mount, who released it * in the uk.org.retep.pdf package. It was modified by Eric Z. Beard as * follows: * The package name was changed to gnu.pdf. * The formatting was changed a little bit. * This used to subclass an abstract class in a different package with * the same name (confusing). Now it's one concrete class. * drawImage() was implemented * It is still licensed under the LGPL. */ // Implementation notes: // // Pages 333-335 of the PDF Reference Manual // // Unless absolutely required, use the moveto, lineto and rectangle // operators to perform those actions. // They contain some extra optimizations // which will reduce the output size by up to half in some cases. // // About fill operators: For correct operation, any fill operation should // start with closeBlock(), which will ensure any previous path is completed, // otherwise you may find the fill will include previous items private static final DecimalFormat df = new DecimalFormat("#.###", new DecimalFormatSymbols(Locale.ENGLISH)); //JPEXS: cache for already used images private static Map usedImages = new WeakHashMap(); private Color background; /** * This is true for any Graphics instance that didn't create the stream. * * @see #create */ private boolean child; private Area clip; /** * This holds the current clipRectangle */ protected Rectangle clipRectangle; private Composite composite; private Graphics2D dg2 = new BufferedImage(2, 2, BufferedImage.TYPE_INT_RGB).createGraphics(); /** * This is the current font (in Java format) */ private Font font; /** * Part of the optimizer: When true, we are drawing a path. */ private boolean inStroke; /** * Part of the optimizer: When true, we are within a Text Block. */ private boolean inText; // true if within a Text Block - see newTextBlock() /** * The stroke line cap code; */ private int lineCap = 0; /** * The stroke line join code */ private int lineJoin = 0; /** * The stroke line width */ private float lineWidth = 1.0f; /** * Part of the optimizer: The last known moveto/lineto x coordinate * * @see #moveto * @see #lineto */ private float lx; // last known moveto/lineto coordinates /** * Part of the optimizer: The last known moveto/lineto y coordinate * * @see #moveto * @see #lineto */ private float ly; // last known moveto/lineto coordinates private float miterLimit = 10.0f; /** * Part of the optimizer: When true, the font has changed. */ private boolean newFont; // true if the font changes - see newTextBlock() /** * This is a reference to the PDFPage we are rendering to. */ private PDFPage page; /** * This is the current pen/fill color */ private Paint paint; /** * This is the current font (in PDF format) */ private PDFFont pdffont; /** * Part of the optimizer: This is written to the stream when the newPath() * is called. np then clears this value. */ private String pre_np; // PDF space transform private AffineTransform pTransform; /** * This is the PrintWriter used to write PDF drawing commands to the Stream */ private RawPrintWriter pw; /** * RenderingHints */ private RenderingHints rhints = new RenderingHints(null); private Stroke stroke; // Start of Graphics2D properties private AffineTransform transform; /** * Part of the optimizer: The last x coordinate when rendering text */ private float tx; // the last coordinate for text rendering /** * Part of the optimizer: The last y coordinate when rendering text */ private float ty; // the last coordinate for text rendering /** * @see Graphics2D#addRenderingHints(Map) */ public void addRenderingHints(Map hints) { rhints.putAll(hints); } /** * This produces an arc by breaking it down into one or more Bezier curves. * It is used internally to implement the drawArc and fillArc methods. * * @param axc X coordinate of arc centre * @param ayc Y coordinate of arc centre * @param width of bounding rectangle * @param height of bounding rectangle * @param ang1 Start angle * @param ang2 End angle * @param clockwise true to draw clockwise, false anti-clockwise */ public void arc(double axc, double ayc, double width, double height, double ang1, double ang2, boolean clockwise) { double adiff; double x0, y0; double x3r, y3r; boolean first = true; // may not need this //if( ar < 0 ) { //ang1 += fixed_180; //ang2 += fixed_180; //ar = - ar; //} double ang1r = (ang1 % 360.0) * degrees_to_radians; double sin0 = Math.sin(ang1r); double cos0 = Math.cos(ang1r); x0 = axc + width * cos0; y0 = ayc + height * sin0; // NB: !clockwise here as Java Space is inverted to User Space if (!clockwise) { // Quadrant reduction while (ang1 < ang2) { ang2 -= 360.0; } while ((adiff = ang2 - ang1) < -90.0) { double w = sin0; sin0 = -cos0; cos0 = w; x3r = axc + width * cos0; y3r = ayc + height * sin0; arc_add(first, width, height, x0, y0, x3r, y3r, (x0 + width * cos0), (y0 + height * sin0) ); x0 = x3r; y0 = y3r; ang1 -= 90.0; first = false; } } else { // Quadrant reduction while (ang2 < ang1) { ang2 += 360.0; } while ((adiff = ang2 - ang1) > 90.0) { double w = cos0; cos0 = -sin0; sin0 = w; x3r = axc + width * cos0; y3r = ayc + height * sin0; arc_add(first, width, height, x0, y0, x3r, y3r, (x0 + width * cos0), (y0 + height * sin0) ); x0 = x3r; y0 = y3r; ang1 += 90.0; first = false; } } // Compute the intersection of the tangents. // We know that -fixed_90 <= adiff <= fixed_90. double trad = Math.tan(adiff * (degrees_to_radians / 2)); double ang2r = ang2 * degrees_to_radians; double xt = x0 - trad * width * sin0; double yt = y0 + trad * height * cos0; arc_add(first, width, height, x0, y0, (axc + width * Math.cos(ang2r)), (ayc + height * Math.sin(ang2r)), xt, yt); } /** * Used by the arc method to actually add an arc to the path Important: We * write directly to the stream here, because this method operates in User * space, rather than Java space. * * @param first true if the first arc * @param w width * @param h height * @param x0 coordinate * @param y0 coordinate * @param x3 coordinate * @param y3 coordinate * @param xt coordinate * @param yt coordinate */ private void arc_add(boolean first, double w, double h, double x0, double y0, double x3, double y3, double xt, double yt) { double dx = xt - x0, dy = yt - y0; double dist = dx * dx + dy * dy; double w2 = w * w, h2 = h * h; double r2 = w2 + h2; double fw = 0.0, fh = 0.0; if (dist < (r2 * 1.0e8)) { // JM fw = (w2 != 0.0) ? ((4.0 / 3.0) / (1 + Math.sqrt(1 + dist / w2))) : 0.0; fh = (h2 != 0.0) ? ((4.0 / 3.0) / (1 + Math.sqrt(1 + dist / h2))) : 0.0; } // The path must have a starting point if (first) { moveto(x0, y0); } double x = x0 + ((xt - x0) * fw); double y = y0 + ((yt - y0) * fh); x0 = x3 + ((xt - x3) * fw); y0 = y3 + ((yt - y3) * fh); // Finally the actual curve. curveto(x, y, x0, y0, x3, y3); } /** * This simply draws a White Rectangle to clear the area * * @param x coordinate * @param y coordinate * @param w width * @param h height */ public void clearRect(int x, int y, int w, int h) { closeBlock(); pw.print("q 1 1 1 RG ");// save state, set colour to White drawRect(x, y, w, h); closeBlock("B Q"); // close fill & stroke, then restore state } /** * @see Graphics2D#clip(Shape) */ public void clip(Shape s) { if (s == null) { setClip(null); return; } if (clip == null) { clip = new Area(s); } else { clip.intersect(new Area(s)); } // followPath(s, CLIP); } /** * This extra method allows PDF users to clip to a Polygon. * *

* In theory you could use setClip(), except that java.awt.Graphics only * supports Rectangle with that method, so we will have an extra method. * * @param p Polygon to clip to */ public void clipPolygon(Polygon p) { closeBlock(); // finish off any existing path polygon(p.xpoints, p.ypoints, p.npoints); closeBlock("W"); // clip to current path clipRectangle = p.getBounds(); } /** * Clips to a set of coordinates * * @param x coordinate * @param y coordinate * @param w width * @param h height */ public void clipRect(int x, int y, int w, int h) { setClip(x, y, w, h); } /** * All functions should call this to close any existing optimized blocks. */ void closeBlock() { closeBlock("S"); } /** *

* This is used by code that use the path in any way other than Stroke (like * Fill, close path & Stroke etc). Usually this is used internally.

* * @param code PDF operators that will close the path */ void closeBlock(String code) { if (inText) { pw.println("ET Q"); // setOrientation(); // fixes Orientation matrix } if (inStroke) { pw.println(code); } inStroke = inText = false; } /** * This is unsupported - how do you do this with Vector graphics? * * @param x coordinate * @param y coordinate * @param w width * @param h height * @param dx coordinate * @param dy coordinate */ public void copyArea(int x, int y, int w, int h, int dx, int dy) { // Hmm... Probably need to keep track of everything // that has been drawn so far to get the contents of an area } //============ Line operations ======================= /** *

* This returns a child instance of this Graphics object. As with AWT, the * affects of using the parent instance while the child exists, is not * determined.

* *

* Once complete, the child should be released with it's dispose() method * which will restore the graphics state to it's parent.

* * @return Graphics object to render onto the page */ @Override public Graphics create() { closeBlock(); PDFGraphics g = createGraphic(page, pw); // The new instance inherits a few items g.clipRectangle = new Rectangle(clipRectangle); return (Graphics) g; } // end create() /** * This method creates a new instance of the class based on the page and a * print writer. * * @param page the page to attach to * @param pw the PrintWriter to attach to. */ protected PDFGraphics createGraphic(PDFPage page, RawPrintWriter pw) { PDFGraphics g = new PDFGraphics(); g.init(page, pw); return g; } /** * This extension appends a Bezier curve to the path. The curve extends from * the current point to (x2,y2) using the current point and (x1,y1) as the * Bezier control points. *

* The new current point is (x2,y2) * * @param x1 Second control point * @param y1 Second control point * @param x2 Destination point * @param y2 Destination point */ public void curveto(double x1, double y1, double x2, double y2) { newPath(); pw.println(cxy(x1, y1) + cxy(x2, y2) + "v"); lx = (float) x2; ly = (float) y2; } /** * This extension appends a Bezier curve to the path. The curve extends from * the current point to (x3,y3) using (x1,y1) and (x2,y2) as the Bezier * control points. *

* The new current point is (x3,y3) * * @param x1 First control point * @param y1 First control point * @param x2 Second control point * @param y2 Second control point * @param x3 Destination point * @param y3 Destination point */ public void curveto(double x1, double y1, double x2, double y2, double x3, double y3) { newPath(); pw.println(cxy(x1, y1) + cxy(x2, y2) + cxy(x3, y3) + "c"); lx = (float) x3; ly = (float) y3; } /** * This extension appends a Bezier curve to the path. The curve extends from * the current point to (x2,y2) using the current point and (x1,y1) as the * Bezier control points. *

* The new current point is (x2,y2) * * @param x1 Second control point * @param y1 Second control point * @param x2 Destination point * @param y2 Destination point */ public void curveto(int x1, int y1, int x2, int y2) { newPath(); pw.println(cxy(x1, y1) + cxy(x2, y2) + "v"); lx = x2; ly = y2; } /** * This extension appends a Bezier curve to the path. The curve extends from * the current point to (x3,y3) using (x1,y1) and (x2,y2) as the Bezier * control points. *

* The new current point is (x3,y3) * * @param x1 First control point * @param y1 First control point * @param x2 Second control point * @param y2 Second control point * @param x3 Destination point * @param y3 Destination point */ public void curveto(int x1, int y1, int x2, int y2, int x3, int y3) { newPath(); pw.println(cxy(x1, y1) + cxy(x2, y2) + cxy(x3, y3) + "c"); lx = x3; ly = y3; } /** * This extension appends a Bezier curve to the path. The curve extends from * the current point to (x2,y2) using (x1,y1) and the end point as the * Bezier control points. *

* The new current point is (x2,y2) * * @param x1 Second control point * @param y1 Second control point * @param x2 Destination point * @param y2 Destination point */ public void curveto2(double x1, double y1, double x2, double y2) { newPath(); pw.println(cxy(x1, y1) + cxy(x2, y2) + "y"); lx = (float) x2; ly = (float) y2; } // Arcs are horrible and complex. They are at the end of the // file, because they are the largest. This is because, unlike // Postscript, PDF doesn't have any arc operators, so we must // implement them by converting into one or more Bezier curves // (which is how Postscript does them internally). /** * This extension appends a Bezier curve to the path. The curve extends from * the current point to (x2,y2) using (x1,y1) and the end point as the * Bezier control points. *

* The new current point is (x2,y2) * * @param x1 Second control point * @param y1 Second control point * @param x2 Destination point * @param y2 Destination point */ public void curveto2(int x1, int y1, int x2, int y2) { newPath(); pw.println(cxy(x1, y1) + cxy(x2, y2) + "y"); lx = x2; ly = y2; } /** * Converts the Java space dimension into pdf. * * @param w width * @param h height * @return String containing the coordinates in PDF space */ private String cwh(double w, double h) { double nw = w, nh = h; // scratch // switch(mediaRot) { // case PageFormat.PORTRAIT: // Portrait //nw = w; nh = -h; // break; // // case PageFormat.LANDSCAPE: // // Landscape // nw = h; // nh = w; // break; // //// case 180: //// // Inverse Portrait //// nw = -w; //// //nh = h; //// break; // // case PageFormat.REVERSE_LANDSCAPE: // // Seascape // nw = -h; // nh = -w; // break; // } return "" + df.format(nw) + " " + df.format(nh) + " "; } /** * Converts the Java space dimension into pdf. * * @param w width * @param h height * @return String containing the coordinates in PDF space */ private String cwh(int w, int h) { return cwh((double) w, (double) h); } /** * Converts the Java space coordinates into pdf. * * @param x coordinate * @param y coordinate * @return String containing the coordinates in PDF space */ private String cxy(double x, double y) { return "" + df.format(x) + " " + df.format(y) + " "; } /** * Converts the Java space coordinates into pdf. * * @param x coordinate * @param y coordinate * @return String containing the coordinates in PDF space */ private String cxy(int x, int y) { return cxy((double) x, (double) y); } /** *

* This releases any resources used by this Graphics object. You must use * this method once finished with it. Leaving it open will leave the PDF * stream in an inconsistent state, and will produce errors.

* *

* If this was created with Graphics.create() then the parent instance can * be used again. If not, then this closes the graphics operations for this * page when used with PDFJob.

* *

* When using PDFPage, you can create another fresh Graphics instance, which * will draw over this one.

* */ public void dispose() { closeBlock(); if (child) { pw.println("Q"); // restore graphics context } else { pw.close(); // close the stream if were the parent } } // ********************************************* // **** Implementation of java.awt.Graphics **** // ********************************************* //============ Rectangle operations ======================= /** * @see Graphics2D#draw(Shape) */ public void draw(Shape s) { followPath(s, STROKE); } /** *

* Not implemented

* *

* Draws a 3-D highlighted outline of the specified rectangle. The edges of * the rectangle are highlighted so that they appear to be beveled and lit * from the upper left corner. The colors used for the highlighting effect * are determined based on the current color. The resulting rectangle covers * an area that is width + 1 pixels wide by height + 1 pixels tall. *

* * @param x an int value * @param y an int value * @param width an int value * @param height an int value * @param raised a boolean value */ public void draw3DRect(int x, int y, int width, int height, boolean raised) { // Not implemented } /** * Draws an arc * * @param x coordinate * @param y coordinate * @param w width * @param h height * @param sa Start angle * @param aa End angle */ public void drawArc(int x, int y, int w, int h, int sa, int aa) { w = w >> 1; h = h >> 1; x += w; y += h; arc((double) x, (double) y, (double) w, (double) h, (double) -sa, (double) (-sa - aa), false); } /** *

* Not implemented

* * @param data a byte[] value * @param offset an int value * @param length an int value * @param x an int value * @param y an int value */ public void drawBytes(byte[] data, int offset, int length, int x, int y) { } //============ Optimizers ======================= /** * @see Graphics2D#drawGlyphVector(GlyphVector, float, float) */ public void drawGlyphVector(GlyphVector g, float x, float y) { Shape s = g.getOutline(x, y); fill(s); } /** * @see Graphics2D#drawImage(BufferedImage, BufferedImageOp, int, int) */ public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { BufferedImage result = img; if (op != null) { result = op.createCompatibleDestImage(img, img.getColorModel()); result = op.filter(img, result); } drawImage(result, x, y, null); } /** * @see Graphics2D#drawImage(Image, AffineTransform, ImageObserver) */ public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { // return drawImage(img, null, xform, null, obs); return true; } /** *

* Draw's an image onto the page, with a backing colour.

* * @param img The java.awt.Image * @param x coordinate on page * @param y coordinate on page * @param bgcolor Background colour * @param obs ImageObserver * @return true if drawn */ public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver obs) { return drawImage(img, x, y, img.getWidth(obs), img.getHeight(obs), bgcolor, obs); } /** * Draw's an image onto the page * * @param img The java.awt.Image * @param x coordinate on page * @param y coordinate on page * @param obs ImageObserver * @return true if drawn */ public boolean drawImage(Image img, int x, int y, ImageObserver obs) { return drawImage(img, x, y, img.getWidth(obs), img.getHeight(obs), obs); } /** *

* Draw's an image onto the page, with a backing colour.

* * @param img The java.awt.Image * @param x coordinate on page * @param y coordinate on page * @param w Width on page * @param h height on page * @param bgcolor Background colour * @param obs ImageObserver * @return true if drawn */ public boolean drawImage(Image img, int x, int y, int w, int h, Color bgcolor, ImageObserver obs) { closeBlock(); pw.print("q "); // save state Color c = getColor(); // save current colour setColor(bgcolor); // change the colour drawRect(x, y, w, h); closeBlock("B Q"); // fill stroke, restore state paint = c; // restore original colour return drawImage(img, x, y, img.getWidth(obs), img.getHeight(obs), obs); } /** *

* Draws an image onto the page.

* *

* This method is implemented with ASCIIbase85 encoding and the zip stream * deflater. It results in a stream that is anywhere from 3 to 10 times as * big as the image. This obviously needs some improvement, but it works * well for small images

* * @param img The java.awt.Image * @param x coordinate on page * @param y coordinate on page * @param w Width on page * @param h height on page * @param obs ImageObserver * @return true if drawn */ public boolean drawImage(Image img, int x, int y, int w, int h, ImageObserver obs) { closeBlock(); PDFImage image; if (usedImages.containsKey(img)) { image = usedImages.get(img); } else { image = new PDFImage(img, x, y, w, h, obs); // The image needs to be registered in several places page.getPDFDocument().setImageName(image); page.getPDFDocument().add(image); usedImages.put(img, image); } page.addToProcset("/ImageC"); page.addImageResource(image.getName() + " " + image.getSerialID() + " 0 R"); // JM /*page.addResource("/XObject << " + image.getName() + " " + image.getSerialID() + " 0 R >>");*/ // q w 0 0 h x y cm % the coordinate matrix AffineTransform newTransform = new AffineTransform(w, 0, 0, h, x, y); newTransform.preConcatenate(pTransform); AffineTransform transformToSet = newTransform; pw.print("q " + transformToSet.getScaleX() + " " + transformToSet.getShearY() + " " + transformToSet.getShearX() + " " + transformToSet.getScaleY() + " " + transformToSet.getTranslateX() + " " + transformToSet.getTranslateY() + " cm \n" + image.getName() + " Do\nQ\n"); return false; } /** * Draw's an image onto the page, with scaling *

* This is not yet supported. * * @param img The java.awt.Image * @param dx1 coordinate on page * @param dy1 coordinate on page * @param dx2 coordinate on page * @param dy2 coordinate on page * @param sx1 coordinate on image * @param sy1 coordinate on image * @param sx2 coordinate on image * @param sy2 coordinate on image * @param bgcolor Background colour * @param obs ImageObserver * @return true if drawn */ public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver obs) { return false; } //============ Clipping operations ======================= /** * Draw's an image onto the page, with scaling *

* This is not yet supported. * * @param img The java.awt.Image * @param dx1 coordinate on page * @param dy1 coordinate on page * @param dx2 coordinate on page * @param dy2 coordinate on page * @param sx1 coordinate on image * @param sy1 coordinate on image * @param sx2 coordinate on image * @param sy2 coordinate on image * @param obs ImageObserver * @return true if drawn */ public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver obs) { // This shouldn't be too bad, just change the coordinate matrix return false; } /** * Draws a line between two coordinates. * * If the first coordinate is the same as the last one drawn (i.e. a * previous drawLine, moveto, etc) it is ignored. * * @param x1 coordinate * @param y1 coordinate * @param x2 coordinate * @param y2 coordinate */ public void drawLine(int x1, int y1, int x2, int y2) { moveto(x1, y1); lineto(x2, y2); } //============ Arcs operations ============================== // These are the standard Graphics operators. They use the // arc extension operators to achieve the affect. /** *

* Draws an oval

* * @param x coordinate * @param y coordinate * @param w width * @param h height */ public void drawOval(int x, int y, int w, int h) { drawArc(x, y, w, h, 0, 360); } /** * Draws a polygon, linking the first and last coordinates. * * @param xp Array of x coordinates * @param yp Array of y coordinates * @param np number of points in polygon */ public void drawPolygon(int[] xp, int[] yp, int np) { polygon(xp, yp, np); closeBlock("s"); // close path and stroke } /** * Draws a polyline. The first and last coordinates are not linked. * * @param xp Array of x coordinates * @param yp Array of y coordinates * @param np number of points in polyline */ public void drawPolyline(int[] xp, int[] yp, int np) { polygon(xp, yp, np); // no stroke, as we keep the optimizer in stroke state } /** * We override Graphics.drawRect as it doesn't join the 4 lines. Also, PDF * provides us with a Rectangle operator, so we will use that. * * @param x coordinate * @param y coordinate * @param w width * @param h height */ public void drawRect(int x, int y, int w, int h) { newPath(); pw.print(cxy(x, y) + cwh(w, h) + "re "); // rectangle lx = x; // I don't know if this is correct, but lets see if PDF ends ly = y; // the rectangle at it's start. // stroke (optimized) } /** * @see Graphics2D#drawRenderableImage(RenderableImage, AffineTransform) */ public void drawRenderableImage(RenderableImage img, AffineTransform xform) { drawRenderedImage(img.createDefaultRendering(), xform); } /** * @see Graphics2D#drawRenderedImage(RenderedImage, AffineTransform) */ public void drawRenderedImage(RenderedImage img, AffineTransform xform) { BufferedImage image = null; if (img instanceof BufferedImage) { image = (BufferedImage) img; } else { ColorModel cm = img.getColorModel(); int width = img.getWidth(); int height = img.getHeight(); WritableRaster raster = cm.createCompatibleWritableRaster(width, height); boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); Hashtable properties = new Hashtable(); String[] keys = img.getPropertyNames(); if (keys != null) { for (int i = 0; i < keys.length; i++) { properties.put(keys[i], img.getProperty(keys[i])); } } BufferedImage result = new BufferedImage(cm, raster, isAlphaPremultiplied, properties); img.copyData(raster); image = result; } drawImage(image, xform, null); } /** * This is not yet implemented * * @param x coordinate * @param y coordinate * @param w width * @param h height * @param aw a-width * @param ah a-height */ public void drawRoundRect(int x, int y, int w, int h, int aw, int ah) { } //============ Oval operations ======================= /** * Draws a string using a AttributedCharacterIterator. *

* This is not supported yet, as I have no idea what an * AttributedCharacterIterator is. *

* This method is new to the Java2 API. */ public void drawString(java.text.AttributedCharacterIterator aci, float x, float y) { } /** * Draws a string using a AttributedCharacterIterator. *

* This is not supported yet, as I have no idea what an * AttributedCharacterIterator is. *

* This method is new to the Java2 API. */ public void drawString(java.text.AttributedCharacterIterator aci, int x, int y) { } public void drawStringWithMode(String s, float x, float y, int mode) { newTextBlock(x, y); if (mode > -1) { pw.println("" + mode + " Tr"); } if (pdffont instanceof PDFEmbeddedFont) { pw.print("[("); pw.printRaw(PDFStringHelper.makeRawPDFString(s)); pw.println(")] TJ"); } else { pw.print(PDFStringHelper.makePDFString(s)); pw.println(" Tj"); } closeBlock(); } @Override public void drawString(String s, float x, float y) { drawStringWithMode(s, x, y, -1); } /** * This draws a string. * * @param s * @oaran s String to draw * @param x coordinate * @param y coordinate */ @Override public void drawString(String s, int x, int y) { drawString(s, (float) x, (float) y); } public void drawTransparentString(String s, float x, float y) { drawStringWithMode(s, x, y, 3); } /** * This draws a transparent string. * * @oaran s String to draw * @param x coordinate * @param y coordinate */ public void drawTransparentString(String s, int x, int y) { drawTransparentString(s, (float) x, (float) y); } /** * @see Graphics2D#fill(Shape) */ public void fill(Shape s) { followPath(s, FILL); } /** *

* Not implemented

* * @param x an int value * @param y an int value * @param width an int value * @param height an int value * @param raised a boolean value */ public void fill3DRect(int x, int y, int width, int height, boolean raised) { // Not implemented } /** * Fills an arc, joining the start and end coordinates * * @param x coordinate * @param y coordinate * @param w width * @param h height * @param sa Start angle * @param aa End angle */ public void fillArc(int x, int y, int w, int h, int sa, int aa) { // here we fool the optimizer. We force any open path to be closed, // then draw the arc. Finally, as the optimizer hasn't stroke'd the // path, we close and fill it, and mark the Stroke as closed. // // Note: The lineto to the centre of the object is required, because // the fill only fills the arc. Skipping this includes an extra // chord, which isn't correct. Peter May 31 2000 closeBlock(); drawArc(x, y, w, h, sa, aa); lineto(x + (w >> 1), y + (h >> 1)); closeBlock("b"); // closepath and fill } //============ Extension operations ============================== // These are extensions, and provide access to PDF Specific // operators. /** *

* Draws a filled oval

* * @param x coordinate * @param y coordinate * @param w width * @param h height */ public void fillOval(int x, int y, int w, int h) { fillArc(x, y, w, h, 0, 360); } //============ Polygon operations ======================= /** * Fills a polygon. * * @param xp Array of x coordinates * @param yp Array of y coordinates * @param np number of points in polygon */ public void fillPolygon(int[] xp, int[] yp, int np) { closeBlock(); // finish off any previous paths polygon(xp, yp, np); closeBlock("b"); // closepath, fill and stroke } //============ Image operations ======================= /** * Fills a rectangle with the current colour * * @param x coordinate * @param y coordinate * @param w width * @param h height */ public void fillRect(int x, int y, int w, int h) { // end any path & stroke. This ensures the fill is on this // rectangle, and not on any previous graphics closeBlock(); drawRect(x, y, w, h); closeBlock("B"); // rectangle, fill stroke } //============ Round Rectangle operations ======================= /** * This is not yet implemented * * @param x coordinate * @param y coordinate * @param w width * @param h height * @param aw a-width * @param ah a-height */ public void fillRoundRect(int x, int y, int w, int h, int aw, int ah) { } /////////////////////////////////////////////// // // // implementation specific methods // // private void followPath(Shape s, int drawType) { PathIterator points; if (s == null) { return; } if (drawType == STROKE) { if (!(stroke instanceof BasicStroke)) { s = stroke.createStrokedShape(s); followPath(s, FILL); return; } } // if (drawType==STROKE) { // setStrokeDiff(stroke, oldStroke); // oldStroke = stroke; // setStrokePaint(); // } // else if (drawType==FILL) // setFillPaint(); points = s.getPathIterator(IDENTITY); int segments = 0; float[] coords = new float[6]; while (!points.isDone()) { segments++; int segtype = points.currentSegment(coords); switch (segtype) { case PathIterator.SEG_CLOSE: pw.print("h "); break; case PathIterator.SEG_CUBICTO: curveto(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); break; case PathIterator.SEG_LINETO: lineto(coords[0], coords[1]); break; case PathIterator.SEG_MOVETO: moveto(coords[0], coords[1]); break; case PathIterator.SEG_QUADTO: curveto(coords[0], coords[1], coords[2], coords[3]); break; } points.next(); } switch (drawType) { case FILL: if (segments > 0) { if (points.getWindingRule() == PathIterator.WIND_EVEN_ODD) { closeBlock("B*"); } else { closeBlock("B"); } } break; case STROKE: if (segments > 0) { closeBlock("S"); } break; case CLIP: default: //drawType==CLIP if (segments == 0) { drawRect(0, 0, 0, 0); } if (points.getWindingRule() == PathIterator.WIND_EVEN_ODD) { closeBlock("W*"); } else { closeBlock("W"); } } } /** * @see Graphics2D#getBackground() */ public Color getBackground() { return background; } /** * Returns the Shape of the clipping region As my JDK docs say, this may * break with Java 2D. * * @return Shape of the clipping region */ public Shape getClip() { return null; } /** * Returns the Rectangle that fits the current clipping region * * @return the Rectangle that fits the current clipping region */ public Rectangle getClipBounds() { return clipRectangle; } //============ Color operations ======================= /** * Returns the current pen Colour * * @return the current pen Colour */ public Color getColor() { return (paint instanceof Color) ? (Color) paint : Color.black; } /** * @see Graphics2D#getComposite() */ public Composite getComposite() { return composite; } /** * @see Graphics2D#getDeviceConfiguration() */ public GraphicsConfiguration getDeviceConfiguration() { return dg2.getDeviceConfiguration(); } /** * Return's the current font. * * @return the current font. */ public Font getFont() { if (font == null) { setFont(new Font("SansSerif", Font.PLAIN, 12)); } return font; } /** * Returns the FontMetrics for a font. *

* This doesn't work correctly. Perhaps having some way of mapping the base * 14 fonts to our own FontMetrics implementation? * * @param font The java.awt.Font to return the metrics for * @return FontMetrics for a font */ public FontMetrics getFontMetrics(Font font) { Frame dummy = new Frame(); dummy.addNotify(); Image image = dummy.createImage(100, 100); if (image == null) { System.err.println("getFontMetrics: image is null"); } Graphics graphics = image.getGraphics(); return graphics.getFontMetrics(font); } /** * @see Graphics2D#getFontRenderContext() */ public FontRenderContext getFontRenderContext() { boolean antialias = RenderingHints.VALUE_TEXT_ANTIALIAS_ON.equals(getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING)); boolean fractions = RenderingHints.VALUE_FRACTIONALMETRICS_ON.equals(getRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS)); return new FontRenderContext(new AffineTransform(), antialias, fractions); } /** * Returns the associated PDFPage for this graphic * * @return the associated PDFPage for this graphic */ public PDFPage getPage() { return page; } /** * Returns the current pen Colour * * @return the current pen Colour */ public Paint getPaint() { return paint; } /** * @param arg0 a key * @return the rendering hint */ public Object getRenderingHint(Key arg0) { return rhints.get(arg0); } /** * @see Graphics2D#getRenderingHints() */ public RenderingHints getRenderingHints() { return rhints; } /** * @see Graphics2D#getStroke() */ public Stroke getStroke() { return stroke; } /** * @see Graphics2D#getTransform() */ public AffineTransform getTransform() { return new AffineTransform(transform); } /** * Returns the PrintWriter handling the underlying stream * * @return the PrintWriter handling the underlying stream */ public RawPrintWriter getWriter() { return pw; } /** * @see Graphics2D#hit(Rectangle, Shape, boolean) */ public boolean hit(Rectangle rect, Shape s, boolean onStroke) { if (onStroke) { s = stroke.createStrokedShape(s); } Area area = new Area(s); if (clip != null) { area.intersect(clip); } return area.intersects(rect.x, rect.y, rect.width, rect.height); } /** * This initialises the stream by saving the current graphics state, and * setting up the default line width (for us). * * It also sets up the instance ready for graphic operations and any * optimisations. * *

* For child instances, the stream is already open, so this should keep * things happy. */ private void init() { PageFormat pf = page.getPageFormat(); // save graphics state (restored by dispose) if (child) { pw.print("q "); } // now initialise the instance //setColor(Color.black); paint = Color.black; // possible: if parent.color is not black, then force black? // must check to see what AWT does? // Original User Space Transform (identity) // Transform from Java Space to PDF Space pTransform = new AffineTransform(); pTransform.translate(0, pf.getHeight()); pTransform.scale(1d, -1d); // Combined Transform User->Java->PDF setNewTranform(new AffineTransform()); // Set the line width setStroke(DEF_STROKE); } /** * This is called by PDFPage when creating a Graphcis instance. * * @param page The PDFPage to draw onto. */ protected void init(PDFPage page) { this.page = page; // We are the parent instance child = false; // Now create a stream to store the graphics in PDFStream stream = new PDFStream(); // To view detail in uncompressed format comment out the next line stream.setDeflate(true); page.getPDFDocument().add(stream); page.add(stream); pw = new RawPrintWriter(stream.getOutputStream()); // initially, we are limited to the page size clipRectangle = page.getImageableArea(); // finally initialise the stream init(); } /** * This method is used internally by create() and by the PDFJob class * * @param page PDFPage to draw into * @param pw PrintWriter to use */ protected void init(PDFPage page, RawPrintWriter pw) { this.page = page; this.pw = pw; // In this case, we didn't create the stream (our parent did) // so child is true (see dispose) child = true; // finally initialise the stream init(); } /** * This adds a line segment to the current path * * @param x coordinate * @param y coordinate */ public void lineto(double x, double y) { newPath(); // no optimisation here as it may introduce errors on decimal coordinates. pw.print(cxy(x, y) + "l "); lx = (float) x; ly = (float) y; } /** * This adds a line segment to the current path * * @param x coordinate * @param y coordinate */ public void lineto(int x, int y) { newPath(); if (lx != x && ly != y) { pw.print(cxy(x, y) + "l "); } lx = x; ly = y; } /** * This moves the current drawing point. * * @param x coordinate * @param y coordinate */ public void moveto(double x, double y) { newPath(); // no optimisation here as it may introduce errors on decimal coordinates. pw.print(cxy(x, y) + "m "); lx = (float) x; ly = (float) y; } /** * This moves the current drawing point. * * @param x coordinate * @param y coordinate */ public void moveto(int x, int y) { newPath(); if (lx != x || ly != y) { pw.print(cxy(x, y) + "m "); } lx = x; ly = y; } /** * Functions that draw lines should start by calling this. It starts a new * path unless inStroke is set, in that case it uses the existing path */ void newPath() { if (inText) { closeBlock(); } if (!inStroke) { if (pre_np != null) { pw.print(pre_np); // this is the prefix set by setOrientation() pre_np = null; } pw.print("n "); } inText = false; inStroke = true; // an unlikely coordinate to fool the moveto() optimizer lx = ly = -9999; } /** *

* Functions that draw text should start by calling this. It starts a text * block (accounting for media orientation) unless we are already in a Text * block.

* *

* It also handles if the font has been changed since the current text block * was started, so your function will be current.

* * @param x x coordinate in java space * @param y y coordinate in java space */ void newTextBlock(float x, float y) { // close the current path if there is one if (inStroke) { closeBlock(); } // create the text block if one is not current. If we are, the newFont // condition at the end catches font changes if (!inText) { // This ensures that there is a font available getFont(); pw.print("q BT "); tx = ty = 0; AffineTransform tm = new AffineTransform(pTransform); pw.println("" + df.format(tm.getScaleX()) + " " + "" + df.format(tm.getShearY()) + " " + "" + df.format(tm.getShearX()) + " " + "" + df.format(tm.getScaleY()) + " " + "" + df.format(tm.getTranslateX()) + " " + "" + df.format(tm.getTranslateY()) + " Tm" ); // produce the text matrix for the media // switch(mediaRot) { // case PageFormat.PORTRAIT: // Portrait // //pw.println("1 0 0 1 0 0 Tm"); // break; // // case PageFormat.LANDSCAPE: // Landscape // pw.println("0 1 -1 0 0 0 Tm"); // rotate // break; // // case 180: // Inverted Portrait // pw.println("1 0 0 -1 0 0 Tm"); // break; // // case PageFormat.REVERSE_LANDSCAPE: // Seascape // pw.println("0 -1 1 0 0 0 Tm"); // rotate // break; // } // move the text cursor by an absolute amount pw.print(txy(x, y) + "Td "); } else { // move the text cursor by a relative amount pw.print(twh(x, y, tx, ty) + "Td "); //pw.print(txy(x,y)+"Td "); } // preserve the coordinates for the next time tx = x; ty = y; if (newFont || !inText) { pw.print(pdffont.getName() + " " + font.getSize() + " Tf "); } // later add colour changes here (if required) inStroke = newFont = false; inText = true; } /** * This is used to add a polygon to the current path. Used by drawPolygon(), * drawPolyline() and fillPolygon() etal * * @param xp Array of x coordinates * @param yp Array of y coordinates * @param np number of points in polygon * @see #drawPolygon * @see #drawPolyline * @see #fillPolygon */ public void polygon(int[] xp, int[] yp, int np) { // newPath() not needed here as moveto does it ;-) moveto(xp[0], yp[0]); for (int i = 1; i < np; i++) { lineto(xp[i], yp[i]); } } /** * @see Graphics2D#rotate(double) */ public void rotate(double theta) { AffineTransform newTransform = new AffineTransform(transform); newTransform.rotate(theta); setNewTranform(newTransform); } /** * @see Graphics2D#rotate(double, double, double) */ public void rotate(double theta, double x, double y) { AffineTransform newTransform = new AffineTransform(transform); newTransform.rotate(theta, x, y); setNewTranform(newTransform); } /** * @see Graphics2D#scale(double, double) */ public void scale(double sx, double sy) { AffineTransform newTransform = new AffineTransform(transform); newTransform.scale(sx, sy); setNewTranform(newTransform); } /** * @see Graphics2D#setBackground(Color) */ public void setBackground(Color color) { background = color; } /** * Clips to a set of coordinates * * @param x coordinate * @param y coordinate * @param w width * @param h height */ public void setClip(int x, int y, int w, int h) { clipRectangle = new Rectangle(x, y, w, h); closeBlock(); // finish off any existing paths drawRect(x, y, w, h); closeBlock("W n"); // clip to current path } /** * As my JDK docs say, this may break with Java 2D. *

* Sets the clipping region to that of a Shape. * * @param s Shape to clip to. */ public void setClip(Shape s) { Rectangle r = s.getBounds(); setClip(r.x, r.y, r.width, r.height); } /** * Sets the color for drawing * * @param c Color to use */ public void setColor(Color c) { setPaint(c); } /** * @see Graphics2D#setComposite(Composite) */ public void setComposite(Composite comp) { this.composite = comp; } /** * This extension sets the line width to the default of 1mm which is what * Java uses when drawing to a PrintJob. */ public void setDefaultLineWidth() { closeBlock(); // draw any path before we change the line width pw.println("1 w"); } /** * This sets the font. * * @param f java.awt.Font to set to. */ public void setFont(Font f) { // optimize: Save some space if the font is already the current one. if (font != f) { font = f; pdffont = page.getFont("/Type1", f.getName(), f.getStyle()); // mark the font as changed newFont = true; } } public void setExistingTtfFont(Font f) { if (font != f) { font = f; pdffont = page.getFont("/TrueType", f.getName(), f.getStyle()); // mark the font as changed newFont = true; } } public void setTtfFont(Font f, File file) throws IOException { if (font != f) { font = f; pdffont = page.getEmbeddedFont(f.getName(), f.getStyle(), file); // mark the font as changed newFont = true; } } private void setLineCap(int cap) { int lineCap = 0; switch (cap) { case BasicStroke.JOIN_MITER: lineCap = 0; break; case BasicStroke.JOIN_ROUND: lineCap = 1; break; case BasicStroke.JOIN_BEVEL: lineCap = 2; break; } if (this.lineCap != lineCap) { closeBlock(); // draw any path before we change the line width this.lineCap = lineCap; pw.println("" + lineCap + " J"); } } private void setLineJoin(int join) { int lineJoin = 0; switch (join) { case BasicStroke.JOIN_MITER: lineJoin = 0; break; case BasicStroke.JOIN_ROUND: lineJoin = 1; break; case BasicStroke.JOIN_BEVEL: lineJoin = 2; break; } if (this.lineJoin != lineJoin) { closeBlock(); // draw any path before we change the line width this.lineJoin = lineJoin; pw.println("" + lineJoin + " j"); } } /** * This extension allows the width of the drawn line to be set * * @param width Line width in pdf graphic units (points) */ public void setLineWidth(float width) { if (width != this.lineWidth) { closeBlock(); // draw any path before we change the line width this.lineWidth = width; pw.println("" + width + " w"); } } private void setMiterLimit(float limit) { if (limit != this.miterLimit) { closeBlock(); // draw any path before we change the line width this.miterLimit = limit; pw.println("" + limit + " M"); } } /** * Sets the paint for drawing * * @param paint Paint to use */ public void setPaint(Paint paint) { this.paint = paint; if (paint instanceof Color) { Color c = (Color) paint; double r = ((double) c.getRed()) / 255.0; double g = ((double) c.getGreen()) / 255.0; double b = ((double) c.getBlue()) / 255.0; closeBlock(); // This ensures any paths are drawn in the previous // colours pw.println("" + r + " " + g + " " + b + " rg " + r + " " + g + " " + b + " RG"); } } /** * Not implemented, as this is not supported in the PDF specification. */ public void setPaintMode() { } /** * Sets a rendering hint * * @param arg0 * @param arg1 */ public void setRenderingHint(Key arg0, Object arg1) { if (arg1 != null) { rhints.put(arg0, arg1); } else { rhints.remove(arg0); } } // Add Graphics2D methods. /** * @see Graphics2D#setRenderingHints(Map) */ public void setRenderingHints(Map hints) { rhints.clear(); rhints.putAll(hints); } /** * @see Graphics2D#setStroke(Stroke) */ public void setStroke(Stroke s) { this.stroke = s; if (stroke instanceof BasicStroke) { BasicStroke bs = (BasicStroke) stroke; setLineCap(bs.getEndCap()); setLineJoin(bs.getLineJoin()); setLineWidth(bs.getLineWidth()); setMiterLimit(bs.getMiterLimit()); // TODO: Line dash pattern } } /** * @see Graphics2D#setTransform(AffineTransform) */ public void setTransform(AffineTransform t) { setNewTranform(new AffineTransform(t)); } /** * Not implemented, as this is not supported in the PDF specification. * * @param c1 Color to xor with */ public void setXORMode(Color c1) { } //============ Text operations ======================= /** * @see Graphics2D#shear(double, double) */ public void shear(double shx, double shy) { AffineTransform newTransform = new AffineTransform(transform); newTransform.shear(shx, shy); setNewTranform(newTransform); } /** * @see Graphics2D#transform(AffineTransform) */ public void transform(AffineTransform tx) { AffineTransform newTransform = new AffineTransform(transform); newTransform.concatenate(tx); setNewTranform(newTransform); } /** * @see Graphics2D#translate(double, double) */ public void translate(double tx, double ty) { AffineTransform newTransform = new AffineTransform(transform); newTransform.translate(tx, ty); setNewTranform(newTransform); } /** * @see Graphics#translate(int, int) */ public void translate(int x, int y) { translate((double) x, (double) y); } /** * Converts the Java space coordinates into pdf text space. * * @param x coordinate * @param y coordinate * @param tx coordinate * @param ty coordinate * @return String containing the coordinates in PDF text space */ private String twh(float x, float y, float tx, float ty) { float nx = x, ny = y; float ntx = tx, nty = ty; nx = (float) (x - tx); ny = (float) (y - ty); return "" + df.format(nx) + " " + df.format(ny) + " "; } /** * Converts the Java space coordinates into pdf text space. * * @param x coordinate * @param y coordinate * @return String containing the coordinates in PDF text space */ private String txy(float x, float y) { Point2D ptSrc = new Point2D.Float(x, y); Point2D ptDst = new Point2D.Float(); pTransform.transform(ptSrc, ptDst); return "" + df.format(ptDst.getX()) + " " + df.format(ptDst.getY()) + " "; } private void setNewTranform(AffineTransform t) { closeBlock(); AffineTransform newTransform = new AffineTransform(t); AffineTransform transformToSet = new AffineTransform(newTransform); if (transform != null) { AffineTransform realTransformWithPTransform = new AffineTransform(transform); realTransformWithPTransform.preConcatenate(pTransform); AffineTransform inverted = new AffineTransform(realTransformWithPTransform); try { inverted.invert(); } catch (NoninvertibleTransformException ex) { Logger.getLogger(PDFGraphics.class.getName()).log(Level.SEVERE, null, ex); } AffineTransform newTransformWithPTransform = new AffineTransform(newTransform); newTransformWithPTransform.preConcatenate(pTransform); transformToSet = newTransformWithPTransform; transformToSet.preConcatenate(inverted); } else { transformToSet.preConcatenate(pTransform); } transform = newTransform; pw.println("" + df.format(transformToSet.getScaleX()) + " " + "" + df.format(transformToSet.getShearY()) + " " + "" + df.format(transformToSet.getShearX()) + " " + "" + df.format(transformToSet.getScaleY()) + " " + "" + df.format(transformToSet.getTranslateX()) + " " + "" + df.format(transformToSet.getTranslateY()) + " cm" ); } private void saveState() { pw.println("q"); } private void restoreState() { pw.println("Q"); } } // end class PDFGraphics \ No newline at end of file diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFImage.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFImage.java index 79ac9ebf1..4888df7d3 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFImage.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFImage.java @@ -26,18 +26,19 @@ import java.util.*; import java.util.zip.*; /** - *

This implements the Image XObject. Calling one of the - * drawImage methods of PDFGraphics will - * put all the necessary code into the pdf file, and the image will - * be encoded in ascii base 85, then deflated in zip format.

+ *

+ * This implements the Image XObject. Calling one of the drawImage + * methods of PDFGraphics will put all the necessary code into the + * pdf file, and the image will be encoded in ascii base 85, then deflated in + * zip format.

* * @author Eric Z. Beard (original version by Peter Mount) * @author Matthew Hreljac, mhreljac@hotmail.com * @version $Revision: 1.2 $, $Date: 2007/08/26 18:56:35 $ */ -public class PDFImage extends PDFStream implements ImageObserver, Serializable -{ - /* +public class PDFImage extends PDFStream implements ImageObserver, Serializable { + + /* * NOTE: The original class is the work of Peter T. Mount, who released it * in the uk.org.retep.pdf package. It was modified by Eric Z. Beard as * follows: @@ -47,206 +48,211 @@ public class PDFImage extends PDFStream implements ImageObserver, Serializable * class was mostly rewritten * It is still licensed under the LGPL. * Got some help with base85 methods from Mathew Hreljac - */ + */ + // Dimensions of the object. + private int objwidth; + private int objheight; - // Dimensions of the object. - private int objwidth; - private int objheight; + // Dimensions of the image. + private int width; + private int height; + private Image img; + private String name; - // Dimensions of the image. - private int width; - private int height; - private Image img; - private String name; - - - /** - * Creates a new PDFImage instance. - * - */ - public PDFImage() - { - super("/XObject"); - } - - /** - * Creates a new PDFImage instance. - * - * @param img an Image value - */ - public PDFImage(Image img) { - this(); - setImage(img, 0, 0, img.getWidth(this), img.getHeight(this), this); - } - - /** - * Creates a new PDFImage instance. - * - * @param img an Image value - * @param x an int value - * @param y an int value - * @param w an int value - * @param h an int value - * @param obs an ImageObserver value - */ - public PDFImage(Image img,int x,int y,int w,int h,ImageObserver obs) { - this(); - objwidth = w; - objheight = h; - setImage(img, x, y, img.getWidth(this), img.getHeight(this), obs); - } - - - /** - * Get the value of width. - * @return value of width. - */ - public int getWidth() { - return width; - } - - /** - * Set the value of width. - * @param v Value to assign to width. - */ - public void setWidth(int v) { - this.width = v; - } - - /** - * Get the value of height. - * @return value of height. - */ - public int getHeight() { - return height; - } - - /** - * Set the value of height. - * @param v Value to assign to height. - */ - public void setHeight(int v) { - this.height = v; - } - - - /** - * Set the name - * - * @param n a String value - */ - public void setName(String n) { - name = n; - } - - /** - * Get the name - * - * @return a String value - */ - public String getName() { - return name; - } - - /** - * Set the image - * - * @param img an Image value - * @param x an int value - * @param y an int value - * @param w an int value - * @param h an int value - * @param obs an ImageObserver value - */ - public void setImage(Image img,int x,int y,int w,int h,ImageObserver obs) { - this.img = img; - width = w; - height = h; - } - - - - /** - *

Adobe's base 85 does not follow the format used by ipv6 - * addresses. It simply starts with 33 and goes straight up without - * skipping any characters

- * - *

Parts of this method contributed by Mathew Hreljac

- * - * @param stringToEncode a String value - * @return a String value - */ - private String base85Encoding(String stringToEncode) - throws NumberFormatException { - if ((stringToEncode == null) || (stringToEncode.length() == 0)) { - //System.out.println("PDFImage.base85Encoding() null or blank String"); - return ""; + /** + * Creates a new PDFImage instance. + * + */ + public PDFImage() { + super("/XObject"); } - if ((stringToEncode.length() > 8) || - ((stringToEncode.length() % 2) != 0)) { - System.out.println("PDFImage.base85Encoding, Incorrect tuple length: " + - stringToEncode.length()); - return ""; + + /** + * Creates a new PDFImage instance. + * + * @param img an Image value + */ + public PDFImage(Image img) { + this(); + setImage(img, 0, 0, img.getWidth(this), img.getHeight(this), this); } - //System.out.println("str: " + stringToEncode); - // String buffer to use to return the String encoding - StringBuffer sb = new StringBuffer(); - // Deal with a partial tuple (less than 8 hex digits) - // From Adobe's docs: - // "Given n (1, 2 or 3) bytes of binary data, the encoding first - // appends 4 - n zero bytes to make a complete 4-tuple. This 4-tuple - // is encoded in the usual way, but without applying the special - // z-case. Finally, only the first n+1 characters of the resulting - // 5-tuple are written out. Those characters are immediately followed - // by the EOD marker, ~>" - - int numHexDigits = stringToEncode.length() / 2; - int numAppendBytes = 4 - numHexDigits; - for (int i = 0; i < numAppendBytes; i++) { - stringToEncode += "00"; + /** + * Creates a new PDFImage instance. + * + * @param img an Image value + * @param x an int value + * @param y an int value + * @param w an int value + * @param h an int value + * @param obs an ImageObserver value + */ + public PDFImage(Image img, int x, int y, int w, int h, ImageObserver obs) { + this(); + objwidth = w; + objheight = h; + setImage(img, x, y, img.getWidth(this), img.getHeight(this), obs); } - Vector digitVector = new Vector(); - long number = Long.parseLong(stringToEncode, 16); - int remainder = 0; - while (number >= 85) { - remainder = (int) (number % 85); - number = number / 85; - digitVector.add( 0, new Integer( remainder ) ); + /** + * Get the value of width. + * + * @return value of width. + */ + public int getWidth() { + return width; } - digitVector.add( 0, new Integer( (int)number ) ); - for ( int i = 0; i < digitVector.size(); i++) { - char c = (char) (((Integer)digitVector.elementAt(i)).intValue() + 33); - sb.append(c); + /** + * Set the value of width. + * + * @param v Value to assign to width. + */ + public void setWidth(int v) { + this.width = v; } - String tuple = sb.toString(); - int len = tuple.length(); - switch (len) { - case 1: tuple = "!!!!" + tuple; break; - case 2: tuple = "!!!" + tuple; break; - case 3: tuple = "!!" + tuple; break; - case 4: tuple = "!" + tuple; break; - default: break; - } // end switch - //System.out.println("enc tuple: " + tuple); - return (tuple); - } // end base85encoding + /** + * Get the value of height. + * + * @return value of height. + */ + public int getHeight() { + return height; + } + /** + * Set the value of height. + * + * @param v Value to assign to height. + */ + public void setHeight(int v) { + this.height = v; + } + /** + * Set the name + * + * @param n a String value + */ + public void setName(String n) { + name = n; + } - /** - * Writes the image to the stream - * - * @param os an OutputStream value - * @exception IOException if an error occurs - */ - public void writeStream(OutputStream os) throws IOException { - // This is a non-deflated stream - /* + /** + * Get the name + * + * @return a String value + */ + public String getName() { + return name; + } + + /** + * Set the image + * + * @param img an Image value + * @param x an int value + * @param y an int value + * @param w an int value + * @param h an int value + * @param obs an ImageObserver value + */ + public void setImage(Image img, int x, int y, int w, int h, ImageObserver obs) { + this.img = img; + width = w; + height = h; + } + + /** + *

+ * Adobe's base 85 does not follow the format used by ipv6 addresses. It + * simply starts with 33 and goes straight up without skipping any + * characters

+ * + *

+ * Parts of this method contributed by Mathew Hreljac

+ * + * @param stringToEncode a String value + * @return a String value + */ + private String base85Encoding(String stringToEncode) + throws NumberFormatException { + if ((stringToEncode == null) || (stringToEncode.length() == 0)) { + //System.out.println("PDFImage.base85Encoding() null or blank String"); + return ""; + } + if ((stringToEncode.length() > 8) + || ((stringToEncode.length() % 2) != 0)) { + System.out.println("PDFImage.base85Encoding, Incorrect tuple length: " + + stringToEncode.length()); + return ""; + } + //System.out.println("str: " + stringToEncode); + // String buffer to use to return the String encoding + StringBuffer sb = new StringBuffer(); + + // Deal with a partial tuple (less than 8 hex digits) + // From Adobe's docs: + // "Given n (1, 2 or 3) bytes of binary data, the encoding first + // appends 4 - n zero bytes to make a complete 4-tuple. This 4-tuple + // is encoded in the usual way, but without applying the special + // z-case. Finally, only the first n+1 characters of the resulting + // 5-tuple are written out. Those characters are immediately followed + // by the EOD marker, ~>" + int numHexDigits = stringToEncode.length() / 2; + int numAppendBytes = 4 - numHexDigits; + for (int i = 0; i < numAppendBytes; i++) { + stringToEncode += "00"; + } + Vector digitVector = new Vector(); + long number = Long.parseLong(stringToEncode, 16); + int remainder = 0; + + while (number >= 85) { + remainder = (int) (number % 85); + number = number / 85; + digitVector.add(0, new Integer(remainder)); + } + digitVector.add(0, new Integer((int) number)); + + for (int i = 0; i < digitVector.size(); i++) { + char c = (char) (((Integer) digitVector.elementAt(i)).intValue() + 33); + sb.append(c); + } + String tuple = sb.toString(); + int len = tuple.length(); + switch (len) { + case 1: + tuple = "!!!!" + tuple; + break; + case 2: + tuple = "!!!" + tuple; + break; + case 3: + tuple = "!!" + tuple; + break; + case 4: + tuple = "!" + tuple; + break; + default: + break; + } // end switch + //System.out.println("enc tuple: " + tuple); + + return (tuple); + } // end base85encoding + + /** + * Writes the image to the stream + * + * @param os an OutputStream value + * @exception IOException if an error occurs + */ + public void writeStream(OutputStream os) throws IOException { + // This is a non-deflated stream + /* os.write("/Length ".getBytes()); // Accout for stream\n ... >\nendstream os.write(Integer.toString(buf.size() + 18).getBytes()); @@ -254,156 +260,150 @@ public class PDFImage extends PDFStream implements ImageObserver, Serializable os.write("\n>>\nstream\n".getBytes()); buf.writeTo(os); os.write(">\nendstream\nendobj\n\n".getBytes()); - */ - ByteArrayOutputStream b = new ByteArrayOutputStream(); - DeflaterOutputStream dos = new DeflaterOutputStream(b); - buf.writeTo(dos); - dos.finish(); - dos.close(); + */ + ByteArrayOutputStream b = new ByteArrayOutputStream(); + DeflaterOutputStream dos = new DeflaterOutputStream(b); + buf.writeTo(dos); + dos.finish(); + dos.close(); - // FlatDecode is compatible with the java.util.zip.Deflater class - //os.write("/Filter [/FlateDecode /ASCIIHexDecode]\n".getBytes()); - os.write("/Filter [/FlateDecode /ASCII85Decode]\n".getBytes()); - os.write("/Length ".getBytes()); - os.write(Integer.toString(b.size()).getBytes()); - os.write("\n>>\nstream\n".getBytes()); - b.writeTo(os); - os.write("\nendstream\nendobj\n".getBytes()); + // FlatDecode is compatible with the java.util.zip.Deflater class + //os.write("/Filter [/FlateDecode /ASCIIHexDecode]\n".getBytes()); + os.write("/Filter [/FlateDecode /ASCII85Decode]\n".getBytes()); + os.write("/Length ".getBytes()); + os.write(Integer.toString(b.size()).getBytes()); + os.write("\n>>\nstream\n".getBytes()); + b.writeTo(os); + os.write("\nendstream\nendobj\n".getBytes()); - } // end writeStream + } // end writeStream + /** + *

+ * Compression needs to be improved here

+ * + * @param os OutputStream to send the object to + * @exception IOException on error + */ + public void write(OutputStream os) throws IOException { + writeStart(os); - /** - *

Compression needs to be improved here

- * - * @param os OutputStream to send the object to - * @exception IOException on error - */ - public void write(OutputStream os) throws IOException - { - writeStart(os); + // write the extra details + os.write("/Subtype /Image\n/Name ".getBytes()); + os.write(name.getBytes()); + os.write("\n/Width ".getBytes()); + os.write(Integer.toString(width).getBytes()); + os.write("\n/Height ".getBytes()); + os.write(Integer.toString(height).getBytes()); + os.write("\n/BitsPerComponent 8\n/ColorSpace /DeviceRGB\n".getBytes()); - // write the extra details - os.write("/Subtype /Image\n/Name ".getBytes()); - os.write(name.getBytes()); - os.write("\n/Width ".getBytes()); - os.write(Integer.toString(width).getBytes()); - os.write("\n/Height ".getBytes()); - os.write(Integer.toString(height).getBytes()); - os.write("\n/BitsPerComponent 8\n/ColorSpace /DeviceRGB\n".getBytes()); + // write the pixels to the stream + //System.err.println("Processing image "+width+"x"+height+" pixels"); + ByteArrayOutputStream bos = getStream(); - // write the pixels to the stream - //System.err.println("Processing image "+width+"x"+height+" pixels"); - ByteArrayOutputStream bos = getStream(); - - int w = width; - int h = height; - int x = 0; - int y = 0; - int[] pixels = new int[w * h]; - PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixels, 0, w); - try { - pg.grabPixels(); - } catch (InterruptedException e) { - System.err.println("interrupted waiting for pixels!"); - return; - } - if ((pg.getStatus() & ImageObserver.ABORT) != 0) { - System.err.println("image fetch aborted or errored"); - return; - } - StringBuffer out = new StringBuffer(); - for (int j = 0; j < h; j++) { - for (int i = 0; i < w; i++) { - //System.out.print("p[" + j * w + i+ "]=" + pixels[j * w + i] + "."); - out.append(handlePixel(x+i, y+j, pixels[j * w + i])); - if (out.toString().length() >= 8) { - String tuple = out.substring(0, 8); - out.delete(0, 8); - // Convert !!!!! to 'z' - String encTuple = base85Encoding(tuple); - if (encTuple.equals("!!!!!")) { - encTuple = "z"; - } - bos.write(encTuple.getBytes()); + int w = width; + int h = height; + int x = 0; + int y = 0; + int[] pixels = new int[w * h]; + PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixels, 0, w); + try { + pg.grabPixels(); + } catch (InterruptedException e) { + System.err.println("interrupted waiting for pixels!"); + return; } - } + if ((pg.getStatus() & ImageObserver.ABORT) != 0) { + System.err.println("image fetch aborted or errored"); + return; + } + StringBuffer out = new StringBuffer(); + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i++) { + //System.out.print("p[" + j * w + i+ "]=" + pixels[j * w + i] + "."); + out.append(handlePixel(x + i, y + j, pixels[j * w + i])); + if (out.toString().length() >= 8) { + String tuple = out.substring(0, 8); + out.delete(0, 8); + // Convert !!!!! to 'z' + String encTuple = base85Encoding(tuple); + if (encTuple.equals("!!!!!")) { + encTuple = "z"; + } + bos.write(encTuple.getBytes()); + } + } + } + // This should be the only partial tuple case, + + String lastTuple = base85Encoding(out.toString()); + //System.out.println("lastTuple: " + lastTuple); + bos.write(lastTuple.getBytes()); + bos.write("~".getBytes()); + + //System.out.println("Processing done"); + // this will write the actual stream + setDeflate(false); + + writeStream(os); + + // Note: we do not call writeEnd() on streams! } - // This should be the only partial tuple case, - String lastTuple = base85Encoding(out.toString()); - //System.out.println("lastTuple: " + lastTuple); - bos.write(lastTuple.getBytes()); - bos.write("~".getBytes()); + /** + *

+ * Converts a pixel to a hex string

+ * + * @param x an int value + * @param y an int value + * @param p an int value + * @return a String value + */ + public static String handlePixel(int x, int y, int p) { + int alpha = (p >> 24) & 0xff; + int red = (p >> 16) & 0xff; + int green = (p >> 8) & 0xff; + int blue = (p) & 0xff; + String redHex = Integer.toHexString(red); + String greenHex = Integer.toHexString(green); + String blueHex = Integer.toHexString(blue); + if (redHex.length() == 1) { + redHex = "0" + redHex; + } + if (greenHex.length() == 1) { + greenHex = "0" + greenHex; + } + if (blueHex.length() == 1) { + blueHex = "0" + blueHex; + } + return redHex + greenHex + blueHex; + } // end handlePixel + /** + * Describe imageUpdate method here. + * + * @param img an Image value + * @param infoflags an int value + * @param x an int value + * @param y an int value + * @param w an int value + * @param h an int value + * @return a boolean value + */ + public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) { + System.err.println("img=" + img + "\ninfoflags=" + infoflags + + "\nx=" + x + " y=" + y + " w=" + w + " h=" + h); + //if(img == this.img) { + if (infoflags == ImageObserver.WIDTH) { + width = w; + } + if (infoflags == ImageObserver.HEIGHT) { + height = h; + } - //System.out.println("Processing done"); - - // this will write the actual stream - setDeflate(false); - - writeStream(os); - - // Note: we do not call writeEnd() on streams! - } - - - - /** - *

Converts a pixel to a hex string

- * - * @param x an int value - * @param y an int value - * @param p an int value - * @return a String value - */ - public static String handlePixel(int x, int y, int p) { - int alpha = (p >> 24) & 0xff; - int red = (p >> 16) & 0xff; - int green = (p >> 8) & 0xff; - int blue = (p ) & 0xff; - String redHex = Integer.toHexString(red); - String greenHex = Integer.toHexString(green); - String blueHex = Integer.toHexString(blue); - if (redHex.length() == 1) { - redHex = "0" + redHex; + //return true; + //} + return false; } - if (greenHex.length() == 1) { - greenHex = "0" + greenHex; - } - if (blueHex.length() == 1) { - blueHex = "0" + blueHex; - } - return redHex + greenHex + blueHex; - } // end handlePixel - - - - - - /** - * Describe imageUpdate method here. - * - * @param img an Image value - * @param infoflags an int value - * @param x an int value - * @param y an int value - * @param w an int value - * @param h an int value - * @return a boolean value - */ - public boolean imageUpdate(Image img,int infoflags,int x,int y,int w,int h) { - System.err.println("img="+img+"\ninfoflags="+infoflags+ - "\nx="+x+" y="+y+" w="+w+" h="+h); - //if(img == this.img) { - if(infoflags==ImageObserver.WIDTH) - width = w; - if(infoflags==ImageObserver.HEIGHT) - height = h; - - //return true; - //} - return false; - } } // end class PDFImage diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFInfo.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFInfo.java index 45b554b44..2f80b6a9d 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFInfo.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFInfo.java @@ -24,170 +24,176 @@ package gnu.jpdf; import java.io.*; /** - *

This class stores details of the author, the PDF generator etc. - * The values are accessible via the PDFDocument class.

+ *

+ * This class stores details of the author, the PDF generator etc. The values + * are accessible via the PDFDocument class.

* * @author Peter T. Mount * @author Eric Z. Beard, ericzbeard@hotmail.com * @version $Revision: 1.2 $, $Date: 2007/08/26 18:56:35 $ - + * */ -public class PDFInfo extends PDFObject -{ - private String author; - private String creator; - private String title; - private String subject; - private String keywords; +public class PDFInfo extends PDFObject { - /** - * This constructs a minimal info object - */ - public PDFInfo() { - super(null); - } - - /** - * @param title Title of this document - */ - public PDFInfo(String title) { - this(); - this.title = title; - } + private String author; + private String creator; + private String title; + private String subject; + private String keywords; + /** + * This constructs a minimal info object + */ + public PDFInfo() { + super(null); + } - - /** - * Get the value of author. - * @return value of author. - */ - public String getAuthor() { - return author; - } - - /** - * Set the value of author. - * @param v Value to assign to author. - */ - public void setAuthor(String v) { - this.author = v; - } - - + /** + * @param title Title of this document + */ + public PDFInfo(String title) { + this(); + this.title = title; + } - /** - * PDF has two values, a Creator and a Producer. The creator field is - * available for calling code. The producer is fixed by this library. - * Get the value of creator. - * @return value of creator. - */ - public String getCreator() { - return creator; - } - - /** - * Set the value of creator. - * @param v Value to assign to creator. - */ - public void setCreator(String v) { - this.creator = v; - } - - /** - * Get the value of title. - * @return value of title. - */ - public String getTitle() { - return title; - } - - /** - * Set the value of title. - * @param v Value to assign to title. - */ - public void setTitle(String v) { - this.title = v; - } - - /** - * Get the value of subject. - * @return value of subject. - */ - public String getSubject() { - return subject; - } - - /** - * Set the value of subject. - * @param v Value to assign to subject. - */ - public void setSubject(String v) { - this.subject = v; - } - - /** - * Get the value of keywords. - * @return value of keywords. - */ - public String getKeywords() { - return keywords; - } - - /** - * Set the value of keywords. - * @param v Value to assign to keywords. - */ - public void setKeywords(String v) { - this.keywords = v; - } - - /** - * @param os OutputStream to send the object to - * @exception IOException on error - */ - public void write(OutputStream os) throws IOException { - // Write the object header - writeStart(os); - - // now the objects body - - if(author!=null) { - os.write("/Author (".getBytes()); - os.write(PDFStringHelper.makePDFString(author).getBytes()); - os.write(")\n".getBytes()); + /** + * Get the value of author. + * + * @return value of author. + */ + public String getAuthor() { + return author; } - - if(creator!=null) { - os.write("/Creator (".getBytes()); - os.write(PDFStringHelper.makePDFString(creator).getBytes()); - os.write(")\n".getBytes()); + + /** + * Set the value of author. + * + * @param v Value to assign to author. + */ + public void setAuthor(String v) { + this.author = v; } - - os.write("/Producer ".getBytes()); - os.write(PDFStringHelper.makePDFString("gnujpdf - gnujpdf.sourceforge.net") - .getBytes()); - os.write("\n".getBytes()); - - if(title!=null) { - os.write("/Title ".getBytes()); - os.write(PDFStringHelper.makePDFString(title).getBytes()); - os.write("\n".getBytes()); + + /** + * PDF has two values, a Creator and a Producer. The creator field is + * available for calling code. The producer is fixed by this library. Get + * the value of creator. + * + * @return value of creator. + */ + public String getCreator() { + return creator; } - - if(subject!=null) { - os.write("/Subject (".getBytes()); - os.write(PDFStringHelper.makePDFString(subject).getBytes()); - os.write(")\n".getBytes()); + + /** + * Set the value of creator. + * + * @param v Value to assign to creator. + */ + public void setCreator(String v) { + this.creator = v; } - - if(keywords!=null) { - os.write("/Keywords (".getBytes()); - os.write(PDFStringHelper.makePDFString(keywords).getBytes()); - os.write(")\n".getBytes()); + + /** + * Get the value of title. + * + * @return value of title. + */ + public String getTitle() { + return title; } - - // finish off with its footer - writeEnd(os); - } // end write - + + /** + * Set the value of title. + * + * @param v Value to assign to title. + */ + public void setTitle(String v) { + this.title = v; + } + + /** + * Get the value of subject. + * + * @return value of subject. + */ + public String getSubject() { + return subject; + } + + /** + * Set the value of subject. + * + * @param v Value to assign to subject. + */ + public void setSubject(String v) { + this.subject = v; + } + + /** + * Get the value of keywords. + * + * @return value of keywords. + */ + public String getKeywords() { + return keywords; + } + + /** + * Set the value of keywords. + * + * @param v Value to assign to keywords. + */ + public void setKeywords(String v) { + this.keywords = v; + } + + /** + * @param os OutputStream to send the object to + * @exception IOException on error + */ + public void write(OutputStream os) throws IOException { + // Write the object header + writeStart(os); + + // now the objects body + if (author != null) { + os.write("/Author (".getBytes()); + os.write(PDFStringHelper.makePDFString(author).getBytes()); + os.write(")\n".getBytes()); + } + + if (creator != null) { + os.write("/Creator (".getBytes()); + os.write(PDFStringHelper.makePDFString(creator).getBytes()); + os.write(")\n".getBytes()); + } + + os.write("/Producer ".getBytes()); + os.write(PDFStringHelper.makePDFString("gnujpdf - gnujpdf.sourceforge.net") + .getBytes()); + os.write("\n".getBytes()); + + if (title != null) { + os.write("/Title ".getBytes()); + os.write(PDFStringHelper.makePDFString(title).getBytes()); + os.write("\n".getBytes()); + } + + if (subject != null) { + os.write("/Subject (".getBytes()); + os.write(PDFStringHelper.makePDFString(subject).getBytes()); + os.write(")\n".getBytes()); + } + + if (keywords != null) { + os.write("/Keywords (".getBytes()); + os.write(PDFStringHelper.makePDFString(keywords).getBytes()); + os.write(")\n".getBytes()); + } + + // finish off with its footer + writeEnd(os); + } // end write + } // end class PDFInfo diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFJob.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFJob.java index 1696429e7..2f2803771 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFJob.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFJob.java @@ -30,23 +30,24 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.io.Serializable; - /** - *

This class extends awt's PrintJob, to provide a simple method of writing - * PDF documents.

+ *

+ * This class extends awt's PrintJob, to provide a simple method of writing PDF + * documents.

* - *

You can use this with any code that uses Java's printing mechanism. It - * does include a few extra methods to provide access to some of PDF's features - * like annotations, or outlines.

+ *

+ * You can use this with any code that uses Java's printing mechanism. It does + * include a few extra methods to provide access to some of PDF's features like + * annotations, or outlines.

* * * @author Peter T Mount, http://www.retep.org.uk/pdf/ * @author Eric Z. Beard, ericzbeard@hotmail.com * @version $Revision: 1.3 $, $Date: 2007/08/26 18:56:35 $ */ -public class PDFJob extends PrintJob implements Serializable -{ - /* +public class PDFJob extends PrintJob implements Serializable { + + /* * NOTE: The original class is the work of Peter T. Mount, who released it * in the uk.org.retep.pdf package. It was modified by Eric Z. Beard as * follows: @@ -58,348 +59,346 @@ public class PDFJob extends PrintJob implements Serializable * Instances of PDFJob come directly from constructors, not * static methods in PDFDocument (which used to be PDF) * It is still licensed under the LGPL. - */ - - - /** - * This is the OutputStream the PDF file will be written to when complete - * Note: This is transient, as it's not valid after being Serialized. - */ - protected transient OutputStream os; - - /** - * This is the PDF file being constructed - */ - protected PDFDocument pdfDocument; - - /** - * This is the current page being constructed by the last getGraphics() - * call - */ - protected PDFPage page; - - /** - * This is the page number of the current page - */ - protected int pagenum; - - - // Constructors - - /** - *

This constructs the job. This method must be used when creating a - * template pdf file, ie one that is Serialised by one application, and - * then restored by another.

- * - *

ezb 20011115 - Haven't done anything with templates yet, don't know - * how/if they are implemented

- */ - public PDFJob() { - this(null); - } - - /** - *

This constructs the job. This is the primary constructor that - * will be used for creating pdf documents with this package. The - * specified output stream is a handle to the .pdf file you wish to - * create.

- * - * @param os - OutputStream to use for the pdf output - */ - public PDFJob(OutputStream os) { - this(os, "PDF Doc"); - } - - /** - *

This constructs the job. This is the primary constructor that - * will be used for creating pdf documents with this package. The - * specified output stream is a handle to the .pdf file you wish to - * create.

- * - *

Use this constructor if you want to give the pdf document a name - * other than the default of "PDF Doc"

- * - * @param os - OutputStream to use for the pdf output - * @param title a String value - */ - public PDFJob(OutputStream os, String title) { - this.os = os; - this.pdfDocument = new PDFDocument(); - pagenum = 0; - pdfDocument.getPDFInfo().setTitle(title); - } - - - /** - *

This returns a graphics object that can be used to draw on a page. - * In PDF, this will be a new page within the document.

- * - * @param orient - the int Orientation of the new page, - * as defined in PDFPage - * @return Graphics object to draw. - * @see PageFormat#PORTRAIT - * @see PageFormat#LANDSCAPE - * @see PageFormat#REVERSE_LANDSCAPE - */ - public Graphics getGraphics(int orient) { - // create a new page - page = new PDFPage(orient); - pdfDocument.add(page); - pagenum++; - - // Now create a Graphics object to draw onto the page - return new graphic(page,this); - } - - - /** - *

This returns a graphics object that can be used to draw on a page. - * In PDF, this will be a new page within the document.

- * - * @param pageFormat PageFormat describing the page size - * @return Graphics object to draw. - */ - public Graphics getGraphics(PageFormat pageFormat) { - // create a new page - page = new PDFPage(pageFormat); - pdfDocument.add(page); - pagenum++; - - // Now create a Graphics object to draw onto the page - return new graphic(page,this); - } - - - - - /** - *

This writes the PDF document to the OutputStream, finishing the - * document.

- */ - public void end() { - try { - pdfDocument.write(os); - } catch(IOException ioe) { - // Ideally we should throw this. However, PrintJob doesn't throw - // anything, so we will print the Stack Trace instead. - ioe.printStackTrace(); - } finally { - try { - if (os != null) { - os.close(); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - // This should mark us as dead - os = null; - pdfDocument = null; - } - - - - /** - *

This returns a graphics object that can be used to draw on a page. - * In PDF, this will be a new page within the document.

- * - *

This new page will by default be oriented as a portrait

- * - * @return a Graphics object to draw to. - */ - public Graphics getGraphics() { - return getGraphics(PageFormat.PORTRAIT); - } - - - - /** - *

Returns the page dimension

- * - * @return a Dimension instance, the size of the page - */ - public Dimension getPageDimension() { - if (page == null) { - System.err.println("PDFJob.getPageDimension(), page is null"); - } - return page.getDimension(); - } - - - /** - *

How about a setPageDimension(Rectangle media) ??

- */ - - - /** - * This returns the page resolution. - * - *

This is the PDF (and Postscript) device resolution of 72 dpi - * (equivalent to 1 point).

- * - * @return an int, the resolution in pixels per inch - */ - public int getPageResolution() { - return 72; - } - - - - - /** - *

In AWT's PrintJob, this would return true if the user requested that the - * file is printed in reverse order. For PDF's this is not applicable, so - * it will always return false.

- * - * @return false - */ - public boolean lastPageFirst() { - return false; - } - - //======== END OF PrintJob extension ========== - - - - /** - * Returns the PDFDocument object for this document. - * Useful for gaining access to - * the internals of PDFDocument. - * @return the PDF object - */ - public PDFDocument getPDFDocument() { - return pdfDocument; - } - - /** - *

Returns the current PDFPage being worked on. Useful for working on - * Annotations (like links), etc.

- * - * @return the PDFPage currently being constructed - */ - public PDFPage getCurrentPage() { - return page; - } - - /** - *

Returns the current page number. - * Useful if you need to include one in the document

- * - * @return the int current page number - */ - public int getCurrentPageNumber() { - return pagenum; - } - - - - /** - *

This method attaches an outline to the current page being generated. - * When selected, the outline displays the top of the page.

- * - * @param title a String, the title of the Outline - * @return a PDFOutline object that was created, - * for adding sub-outline's if required. - */ - public PDFOutline addOutline(String title) { - return page.addOutline(title); - } - - /** - *

This method attaches an outline to the current page being generated. - * When selected, the outline displays the specified region.

- * - * @param title Outline title to attach - * @param x Left coordinate of region - * @param y Top coordinate of region - * @param w width of region - * @param h height of region - * @return the PDFOutline object created, - * for adding sub-outline's if required. - */ - public PDFOutline addOutline(String title,int x,int y,int w,int h) { - return page.addOutline(title,x,y,w,h); - } - - /** - * Convenience method: Adds a text note to the document. - * @param note Text of the note - * @param x Coordinate of note - * @param y Coordinate of note - * @param w Width of the note - * @param h Height of the note - * @return Returns the annotation, so other settings can be changed. - */ - public PDFAnnot addNote(String note,int x,int y,int w,int h) { - return page.addNote(note,x,y,w,h); - } - - - /** - *

This inner class extends PDFGraphics for the PrintJob.

- * - *

Like with java.awt, Graphics instances created with PrintJob implement - * the PrintGraphics interface. Here we implement that method, and overide - * PDFGraphics.create() method, so all instances have this interface.

- */ - class graphic extends PDFGraphics implements PrintGraphics { - /** - * The PDFJob we are linked with */ - private PDFJob job; - + /** - * @param page to attach to - * @param job PDFJob containing this graphic + * This is the OutputStream the PDF file will be written to when complete + * Note: This is transient, as it's not valid after being Serialized. */ - graphic(PDFPage page,PDFJob job) { - super(); - this.init(page); - this.job = job; - } - + protected transient OutputStream os; + /** - * This is used by our version of create() + * This is the PDF file being constructed */ - graphic(PDFPage page, PDFJob job, RawPrintWriter pw) { - super(); - this.init(page,pw); - this.job = job; - } - + protected PDFDocument pdfDocument; + /** - * This returns a child instance of this Graphics object. As with AWT, - * the affects of using the parent instance while the child exists, - * is not determined. + * This is the current page being constructed by the last getGraphics() call + */ + protected PDFPage page; + + /** + * This is the page number of the current page + */ + protected int pagenum; + + // Constructors + /** + *

+ * This constructs the job. This method must be used when creating a + * template pdf file, ie one that is Serialised by one application, and then + * restored by another.

* - *

This method is used to make a new Graphics object without - * going to a new page

- * - *

Once complete, the child should be released with it's dispose() - * method which will restore the graphics state to it's parent. - * - * @return Graphics object + *

+ * ezb 20011115 - Haven't done anything with templates yet, don't know + * how/if they are implemented

*/ - public Graphics create() { - closeBlock(); - graphic g = new graphic(getPage(),job,getWriter()); - - // The new instance inherits a few items - g.clipRectangle = new Rectangle(clipRectangle); - - return (Graphics) g; + public PDFJob() { + this(null); } - + /** - * This is the PrintGraphics interface - * @return PrintJob for this object + *

+ * This constructs the job. This is the primary constructor that will be + * used for creating pdf documents with this package. The specified output + * stream is a handle to the .pdf file you wish to create.

+ * + * @param os - OutputStream to use for the pdf output */ - public PrintJob getPrintJob() { - return (PrintJob)job; + public PDFJob(OutputStream os) { + this(os, "PDF Doc"); } - - } // end inner class graphic - + + /** + *

+ * This constructs the job. This is the primary constructor that will be + * used for creating pdf documents with this package. The specified output + * stream is a handle to the .pdf file you wish to create.

+ * + *

+ * Use this constructor if you want to give the pdf document a name other + * than the default of "PDF Doc"

+ * + * @param os - OutputStream to use for the pdf output + * @param title a String value + */ + public PDFJob(OutputStream os, String title) { + this.os = os; + this.pdfDocument = new PDFDocument(); + pagenum = 0; + pdfDocument.getPDFInfo().setTitle(title); + } + + /** + *

+ * This returns a graphics object that can be used to draw on a page. In + * PDF, this will be a new page within the document.

+ * + * @param orient - the int Orientation of the new page, as + * defined in PDFPage + * @return Graphics object to draw. + * @see PageFormat#PORTRAIT + * @see PageFormat#LANDSCAPE + * @see PageFormat#REVERSE_LANDSCAPE + */ + public Graphics getGraphics(int orient) { + // create a new page + page = new PDFPage(orient); + pdfDocument.add(page); + pagenum++; + + // Now create a Graphics object to draw onto the page + return new graphic(page, this); + } + + /** + *

+ * This returns a graphics object that can be used to draw on a page. In + * PDF, this will be a new page within the document.

+ * + * @param pageFormat PageFormat describing the page size + * @return Graphics object to draw. + */ + public Graphics getGraphics(PageFormat pageFormat) { + // create a new page + page = new PDFPage(pageFormat); + pdfDocument.add(page); + pagenum++; + + // Now create a Graphics object to draw onto the page + return new graphic(page, this); + } + + /** + *

+ * This writes the PDF document to the OutputStream, finishing the + * document.

+ */ + public void end() { + try { + pdfDocument.write(os); + } catch (IOException ioe) { + // Ideally we should throw this. However, PrintJob doesn't throw + // anything, so we will print the Stack Trace instead. + ioe.printStackTrace(); + } finally { + try { + if (os != null) { + os.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + // This should mark us as dead + os = null; + pdfDocument = null; + } + + /** + *

+ * This returns a graphics object that can be used to draw on a page. In + * PDF, this will be a new page within the document.

+ * + *

+ * This new page will by default be oriented as a portrait

+ * + * @return a Graphics object to draw to. + */ + public Graphics getGraphics() { + return getGraphics(PageFormat.PORTRAIT); + } + + /** + *

+ * Returns the page dimension

+ * + * @return a Dimension instance, the size of the page + */ + public Dimension getPageDimension() { + if (page == null) { + System.err.println("PDFJob.getPageDimension(), page is null"); + } + return page.getDimension(); + } + + /** + *

+ * How about a setPageDimension(Rectangle media) ??

+ */ + /** + * This returns the page resolution. + * + *

+ * This is the PDF (and Postscript) device resolution of 72 dpi (equivalent + * to 1 point).

+ * + * @return an int, the resolution in pixels per inch + */ + public int getPageResolution() { + return 72; + } + + /** + *

+ * In AWT's PrintJob, this would return true if the user requested that the + * file is printed in reverse order. For PDF's this is not applicable, so it + * will always return false.

+ * + * @return false + */ + public boolean lastPageFirst() { + return false; + } + + //======== END OF PrintJob extension ========== + /** + * Returns the PDFDocument object for this document. Useful for gaining + * access to the internals of PDFDocument. + * + * @return the PDF object + */ + public PDFDocument getPDFDocument() { + return pdfDocument; + } + + /** + *

+ * Returns the current PDFPage being worked on. Useful for working on + * Annotations (like links), etc.

+ * + * @return the PDFPage currently being constructed + */ + public PDFPage getCurrentPage() { + return page; + } + + /** + *

+ * Returns the current page number. Useful if you need to include one in the + * document

+ * + * @return the int current page number + */ + public int getCurrentPageNumber() { + return pagenum; + } + + /** + *

+ * This method attaches an outline to the current page being generated. When + * selected, the outline displays the top of the page.

+ * + * @param title a String, the title of the Outline + * @return a PDFOutline object that was created, for adding + * sub-outline's if required. + */ + public PDFOutline addOutline(String title) { + return page.addOutline(title); + } + + /** + *

+ * This method attaches an outline to the current page being generated. When + * selected, the outline displays the specified region.

+ * + * @param title Outline title to attach + * @param x Left coordinate of region + * @param y Top coordinate of region + * @param w width of region + * @param h height of region + * @return the PDFOutline object created, for adding + * sub-outline's if required. + */ + public PDFOutline addOutline(String title, int x, int y, int w, int h) { + return page.addOutline(title, x, y, w, h); + } + + /** + * Convenience method: Adds a text note to the document. + * + * @param note Text of the note + * @param x Coordinate of note + * @param y Coordinate of note + * @param w Width of the note + * @param h Height of the note + * @return Returns the annotation, so other settings can be changed. + */ + public PDFAnnot addNote(String note, int x, int y, int w, int h) { + return page.addNote(note, x, y, w, h); + } + + /** + *

+ * This inner class extends PDFGraphics for the PrintJob.

+ * + *

+ * Like with java.awt, Graphics instances created with PrintJob implement + * the PrintGraphics interface. Here we implement that method, and overide + * PDFGraphics.create() method, so all instances have this interface.

+ */ + class graphic extends PDFGraphics implements PrintGraphics { + + /** + * The PDFJob we are linked with + */ + private PDFJob job; + + /** + * @param page to attach to + * @param job PDFJob containing this graphic + */ + graphic(PDFPage page, PDFJob job) { + super(); + this.init(page); + this.job = job; + } + + /** + * This is used by our version of create() + */ + graphic(PDFPage page, PDFJob job, RawPrintWriter pw) { + super(); + this.init(page, pw); + this.job = job; + } + + /** + * This returns a child instance of this Graphics object. As with AWT, + * the affects of using the parent instance while the child exists, is + * not determined. + * + *

+ * This method is used to make a new Graphics object without going to a + * new page

+ * + *

+ * Once complete, the child should be released with it's dispose() + * method which will restore the graphics state to it's parent. + * + * @return Graphics object + */ + public Graphics create() { + closeBlock(); + graphic g = new graphic(getPage(), job, getWriter()); + + // The new instance inherits a few items + g.clipRectangle = new Rectangle(clipRectangle); + + return (Graphics) g; + } + + /** + * This is the PrintGraphics interface + * + * @return PrintJob for this object + */ + public PrintJob getPrintJob() { + return (PrintJob) job; + } + + } // end inner class graphic + } // end class PDFJob diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFObject.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFObject.java index ce771ed2a..11c835e20 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFObject.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFObject.java @@ -30,148 +30,145 @@ import java.util.*; * @author Eric Z. Beard, ericzbeard@hotmail.com * @version $Revision: 1.3 $, $Date: 2007/09/22 12:48:16 $ */ -public abstract class PDFObject implements Serializable -{ +public abstract class PDFObject implements Serializable { - /* + /* * NOTE: The original class is the work of Peter T. Mount, who released it * in the uk.org.retep.pdf package. It was modified by Eric Z. Beard as * follows: * The package name was changed to gnu.pdf. * The formatting was changed a little bit. * It is still licensed under the LGPL. - */ + */ + /** + * This is the object's PDF Type + */ + private String type; - /** - * This is the object's PDF Type - */ - private String type; - - /** - * This is the unique serial number for this object. - */ - protected int objser; - - /** - * This allows any PDF object to refer to the document being constructed. - */ - protected PDFDocument pdfDocument; - - - /** - * This is usually called by extensors to this class, and sets the - * PDF Object Type - * @param type the PDF Object Type - */ - public PDFObject(String type) - { - this.type = type; - } - - /** - * Returns the PDF Type of this object - * @return The PDF Type of this object - */ - public String getType() - { - return type; - } - - /** - * Returns the unique serial number of this object. - * @return Unique serial number of this object. - */ - public final int getSerialID() - { - return objser; - } - - /** - * Returns the PDF document this object belongs to. - * @return PDF containing this object - */ - public final PDFDocument getPDFDocument() - { - return pdfDocument; - } - - /** - *

Writes the object to the output stream. - * This method must be overidden.

- * - *

Note: It should not write any other objects, even if they are - * it's Kids, as they will be written by the calling routine.

- * - * @param os OutputStream to send the object to - * @exception IOException on error - */ - public abstract void write(OutputStream os) throws IOException; - - /** - * The write method should call this before writing anything to the - * OutputStream. This will send the standard header for each object. - * - *

Note: There are a few rare cases where this method is not called. - * - * @param os OutputStream to write to - * @exception IOException on error - */ - public final void writeStart(OutputStream os) throws IOException - { - os.write(Integer.toString(objser).getBytes()); - os.write(" 0 obj\n<<\n".getBytes()); - if(type!=null) { - os.write("/Type ".getBytes()); - os.write(type.getBytes()); - os.write("\n".getBytes()); + /** + * This is the unique serial number for this object. + */ + protected int objser; + + /** + * This allows any PDF object to refer to the document being constructed. + */ + protected PDFDocument pdfDocument; + + /** + * This is usually called by extensors to this class, and sets the PDF + * Object Type + * + * @param type the PDF Object Type + */ + public PDFObject(String type) { + this.type = type; } - } - - - - /** - * The write method should call this after writing anything to the - * OutputStream. This will send the standard footer for each object. - * - *

Note: There are a few rare cases where this method is not called. - * - * @param os OutputStream to write to - * @exception IOException on error - */ - public final void writeEnd(OutputStream os) throws IOException - { - os.write(">>\nendobj\n".getBytes()); - } - - /** - * Returns the unique serial number in PDF format - * @return the serial number in PDF format - */ - public String toString() - { - return ""+objser+" 0 R"; - } - - /** - * This utility method returns a String containing an array definition - * based on a Vector containing PDFObjects - * @param v Vector containing PDFObjects - * @return String containing a PDF array - */ - public static String toArray(Vector v) - { - if(v.size()==0) - return ""; - - StringBuffer b = new StringBuffer(); - String bs = "["; - for(PDFObject x : v) { - b.append(bs); - b.append(x.toString()); - bs = " "; + /** + * Returns the PDF Type of this object + * + * @return The PDF Type of this object + */ + public String getType() { + return type; + } + + /** + * Returns the unique serial number of this object. + * + * @return Unique serial number of this object. + */ + public final int getSerialID() { + return objser; + } + + /** + * Returns the PDF document this object belongs to. + * + * @return PDF containing this object + */ + public final PDFDocument getPDFDocument() { + return pdfDocument; + } + + /** + *

+ * Writes the object to the output stream. This method must be + * overidden.

+ * + *

+ * Note: It should not write any other objects, even if they are it's + * Kids, as they will be written by the calling routine.

+ * + * @param os OutputStream to send the object to + * @exception IOException on error + */ + public abstract void write(OutputStream os) throws IOException; + + /** + * The write method should call this before writing anything to the + * OutputStream. This will send the standard header for each object. + * + *

+ * Note: There are a few rare cases where this method is not called. + * + * @param os OutputStream to write to + * @exception IOException on error + */ + public final void writeStart(OutputStream os) throws IOException { + os.write(Integer.toString(objser).getBytes()); + os.write(" 0 obj\n<<\n".getBytes()); + if (type != null) { + os.write("/Type ".getBytes()); + os.write(type.getBytes()); + os.write("\n".getBytes()); + } + } + + /** + * The write method should call this after writing anything to the + * OutputStream. This will send the standard footer for each object. + * + *

+ * Note: There are a few rare cases where this method is not called. + * + * @param os OutputStream to write to + * @exception IOException on error + */ + public final void writeEnd(OutputStream os) throws IOException { + os.write(">>\nendobj\n".getBytes()); + } + + /** + * Returns the unique serial number in PDF format + * + * @return the serial number in PDF format + */ + public String toString() { + return "" + objser + " 0 R"; + } + + /** + * This utility method returns a String containing an array definition based + * on a Vector containing PDFObjects + * + * @param v Vector containing PDFObjects + * @return String containing a PDF array + */ + public static String toArray(Vector v) { + if (v.size() == 0) { + return ""; + } + + StringBuffer b = new StringBuffer(); + String bs = "["; + for (PDFObject x : v) { + b.append(bs); + b.append(x.toString()); + bs = " "; + } + b.append("]"); + return b.toString(); } - b.append("]"); - return b.toString(); - } } diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFOutline.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFOutline.java index e3546ad82..cb8034d73 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFOutline.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFOutline.java @@ -29,70 +29,67 @@ import java.util.*; * @author Eric Z. Beard, ericzbeard@hotmail.com * @version $Revision: 1.3 $, $Date: 2007/09/22 12:58:40 $ */ -public class PDFOutline extends PDFObject implements Serializable -{ +public class PDFOutline extends PDFObject implements Serializable { - /* + /* * NOTE: The original class is the work of Peter T. Mount, who released it * in the uk.org.retep.pdf package. It was modified by Eric Z. Beard as * follows: * The package name was changed to gnu.pdf. * The formatting was changed a little bit. * It is still licensed under the LGPL. - */ - + */ /** * This holds any outlines below us */ private Vector outlines; - + /** * For subentries, this points to it's parent outline */ protected PDFOutline parent; - + /** * This is this outlines Title */ private String title; - + /** * The destination page */ PDFPage dest; - + /** * The region on the destination page */ - int l,b,r,t; - + int l, b, r, t; + /** * How the destination is handled */ boolean destMode; - + /** * When jumping to the destination, display the whole page */ static final boolean FITPAGE = false; - + /** * When jumping to the destination, display the specified region */ static final boolean FITRECT = true; - + /** * Constructs a PDF Outline object. This method is used internally only. */ - protected PDFOutline() - { + protected PDFOutline() { super("/Outlines"); outlines = new Vector(); title = null; dest = null; destMode = FITPAGE; } - + /** * Constructs a PDF Outline object. When selected, the whole page is * displayed. @@ -100,16 +97,15 @@ public class PDFOutline extends PDFObject implements Serializable * @param title Title of the outline * @param dest The destination page */ - public PDFOutline(String title,PDFPage dest) - { + public PDFOutline(String title, PDFPage dest) { this(); this.title = title; this.dest = dest; } - + /** - * Constructs a PDF Outline object. When selected, the specified region - * is displayed. + * Constructs a PDF Outline object. When selected, the specified region is + * displayed. * * @param title Title of the outline * @param dest The destination page @@ -118,47 +114,46 @@ public class PDFOutline extends PDFObject implements Serializable * @param r right coordinate * @param t top coordinate */ - public PDFOutline(String title,PDFPage dest,int l,int b,int r,int t) - { - this(title,dest); + public PDFOutline(String title, PDFPage dest, int l, int b, int r, int t) { + this(title, dest); this.destMode = FITRECT; this.l = l; this.b = b; this.r = r; this.t = t; } - + /** - * This method creates an outline, and attaches it to this one. - * When the outline is selected, the entire page is displayed. + * This method creates an outline, and attaches it to this one. When the + * outline is selected, the entire page is displayed. * - *

This allows you to have an outline for say a Chapter, - * then under the chapter, one for each section. You are not really - * limited on how deep you go, but it's best not to go below say 6 levels, - * for the reader's sake. + *

+ * This allows you to have an outline for say a Chapter, then under the + * chapter, one for each section. You are not really limited on how deep you + * go, but it's best not to go below say 6 levels, for the reader's sake. * * @param title Title of the outline * @param dest The destination page - * @return PDFOutline object created, for creating sub-outlines + * @return PDFOutline object created, for creating sub-outlines */ - public PDFOutline add(String title,PDFPage dest) { - PDFOutline outline = new PDFOutline(title,dest); + public PDFOutline add(String title, PDFPage dest) { + PDFOutline outline = new PDFOutline(title, dest); pdfDocument.add(outline); // add to the pdf first! add(outline); return outline; } - + /** - * This method creates an outline, and attaches it to this one. - * When the outline is selected, the supplied region is displayed. + * This method creates an outline, and attaches it to this one. When the + * outline is selected, the supplied region is displayed. * - *

Note: the coordiates are in Java space. They are converted to User - * space. + *

+ * Note: the coordiates are in Java space. They are converted to User space. * - *

This allows you to have an outline for say a Chapter, - * then under the chapter, one for each section. You are not really - * limited on how deep you go, but it's best not to go below say 6 levels, - * for the reader's sake. + *

+ * This allows you to have an outline for say a Chapter, then under the + * chapter, one for each section. You are not really limited on how deep you + * go, but it's best not to go below say 6 levels, for the reader's sake. * * @param title Title of the outline * @param dest The destination page @@ -168,53 +163,51 @@ public class PDFOutline extends PDFObject implements Serializable * @param h height of region in Java space * @return PDFOutline object created, for creating sub-outlines */ - public PDFOutline add(String title,PDFPage dest, - int x,int y,int w,int h) { - int xy1[] = dest.cxy(x,y+h); - int xy2[] = dest.cxy(x+w,y); - PDFOutline outline = new PDFOutline(title,dest, - xy1[0],xy1[1], - xy2[0],xy2[1]); + public PDFOutline add(String title, PDFPage dest, + int x, int y, int w, int h) { + int xy1[] = dest.cxy(x, y + h); + int xy2[] = dest.cxy(x + w, y); + PDFOutline outline = new PDFOutline(title, dest, + xy1[0], xy1[1], + xy2[0], xy2[1]); pdfDocument.add(outline); // add to the pdf first! add(outline); return outline; } - + /** * This adds an already existing outline to this one. * - *

Note: the outline must have been added to the PDF document before - * calling this method. Normally the other add methods are used. + *

+ * Note: the outline must have been added to the PDF document before calling + * this method. Normally the other add methods are used. * * @param outline PDFOutline to add */ - public void add(PDFOutline outline) - { + public void add(PDFOutline outline) { outlines.addElement(outline); - + // Tell the outline of ourselves outline.parent = this; } - + /** * @param os OutputStream to send the object to * @exception IOException on error */ - public void write(OutputStream os) throws IOException - { + public void write(OutputStream os) throws IOException { // Write the object header writeStart(os); - + // now the objects body - // These are for kids only - if(parent!=null) { + if (parent != null) { os.write("/Title ".getBytes()); os.write(PDFStringHelper.makePDFString(title).getBytes()); os.write("\n/Dest [".getBytes()); os.write(dest.toString().getBytes()); - - if(destMode==FITPAGE) { + + if (destMode == FITPAGE) { //os.write(" null null null]\n/Parent ".getBytes()); os.write(" /Fit]\n/Parent ".getBytes()); } else { @@ -231,9 +224,9 @@ public class PDFOutline extends PDFObject implements Serializable os.write(parent.toString().getBytes()); os.write("\n".getBytes()); } - + // the number of outlines in this document - if(parent==null) { + if (parent == null) { // were the top level node, so all are open by default if (outlines.size() > 0) { os.write("/Count ".getBytes()); @@ -244,99 +237,97 @@ public class PDFOutline extends PDFObject implements Serializable // were a decendent, so by default we are closed. Find out how many // entries are below us int c = descendants(); - if(c>0) { + if (c > 0) { os.write("/Count ".getBytes()); os.write(Integer.toString(-c).getBytes()); os.write("\n".getBytes()); } } - + // These only valid if we have children - if(outlines.size()>0) { + if (outlines.size() > 0) { // the number of the first outline in list os.write("/First ".getBytes()); os.write(outlines.elementAt(0).toString().getBytes()); os.write("\n".getBytes()); - + // the number of the last outline in list os.write("/Last ".getBytes()); - os.write(outlines.elementAt(outlines.size()-1).toString().getBytes()); + os.write(outlines.elementAt(outlines.size() - 1).toString().getBytes()); os.write("\n".getBytes()); } - - if(parent!=null) { + + if (parent != null) { int index = parent.getIndex(this); - if(index>0) { + if (index > 0) { // Now if were not the first, then we have a /Prev node os.write("/Prev ".getBytes()); - os.write(parent.getNode(index-1).toString().getBytes()); + os.write(parent.getNode(index - 1).toString().getBytes()); os.write("\n".getBytes()); } - if(index elements() - { + public Enumeration elements() { return outlines.elements(); } - + /** * Returns the total number of descendants below this one. + * * @return the number of descendants below this one */ - protected int descendants() - { + protected int descendants() { int c = outlines.size(); // initially the number of kids - + // now call each one for their descendants - for(PDFOutline o : outlines) { + for (PDFOutline o : outlines) { c += o.descendants(); } - + return c; } } // end class PDFOutline diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFOutput.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFOutput.java index e0ebd2986..5ae79e217 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFOutput.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFOutput.java @@ -25,194 +25,198 @@ import java.io.*; import java.util.*; /** - * This class is used to write a PDF document. It acts as a wrapper - * to a real OutputStream, but is necessary for certain internal PDF - * structures to be built correctly. + * This class is used to write a PDF document. It acts as a wrapper to a real + * OutputStream, but is necessary for certain internal PDF structures to be + * built correctly. * * @author Peter T. Mount * @author Eric Z. Beard, ericzbeard@hotmail.com * @version $Revision: 1.3 $, $Date: 2007/09/22 12:48:16 $ */ -public class PDFOutput -{ - /** - * This is the actual OutputStream used to write to. - */ - protected OutputStream os; - - /** - * This is the OutputStream used to write each object to. - * - *

We use a separate stream, because we need to keep track of how - * many bytes have been written for each object for the xref table to - * work correctly. - */ - protected ByteArrayOutputStream baos; - - /** - * This is the current position within the stream - */ - protected int offset; - - /** - * This vector contains offsets of each object - */ - protected Vector offsets; - - /** - * This is used to track the /Root object (catalog) - */ - protected PDFObject rootID; - - /** - * This is used to track the /Info object (info) - */ - protected PDFObject infoID; - - /** - * This creates a PDF OutputStream - * - * @param os The output stream to write the PDF file to. - * @throws IOException if there is an I/O error. - */ - public PDFOutput(OutputStream os) throws IOException - { - this.os = os; - offset = 0; - offsets = new Vector(); - baos = new ByteArrayOutputStream(); - - // Now write the PDF header - // - // Note: As the encoding is fixed here, we use getBytes(). - // - baos.write("%PDF-1.2\n".getBytes()); - - // This second comment is advised in the PDF Reference manual - // page 61 - baos.write("%\342\343\317\323\n".getBytes()); - - offset = baos.size(); - baos.writeTo(os); - } - - /** - * This method writes a PDFObject to the stream. - * - * @param ob PDFObject Obeject to write - * @exception IOException on error - */ - protected void write(PDFObject ob) throws IOException - { - // Check the object to see if it's one that is needed in the trailer - // object - if(ob instanceof PDFCatalog) rootID=ob; - if(ob instanceof PDFInfo) infoID=ob; - - offsets.addElement(new PDFXref(ob.getSerialID(),offset)); - baos.reset(); - ob.write(baos); - offset+=baos.size(); - baos.writeTo(os); - } - - /** - * This closes the Stream, writing the xref table - */ - protected void close() throws IOException - { - // Make sure everything is written - os.flush(); - - // we use baos to speed things up a little. - // Also, offset is preserved, and marks the begining of this block. - // This is required by PDF at the end of the PDF file. - baos.reset(); - baos.write("xref\n".getBytes()); - - // Now a single subsection for object 0 - //baos.write("0 1\n0000000000 65535 f \n".getBytes()); - - // Now scan through the offsets list. The should be in sequence, - // but just in case: - int firstid = 0; // First id in block - int lastid = -1; // The last id used - Vector block = new Vector(); // xrefs in this block - - // We need block 0 to exist - block.addElement(new PDFXref(0,0,65535)); - - for(PDFXref x : offsets) { - - if(firstid==-1) firstid=x.id; - - // check to see if block is in range (-1 means empty) - if(lastid>-1 && x.id != (lastid+1)) { - // no, so write this block, and reset - writeblock(firstid,block); - block.removeAllElements(); - firstid=-1; - } - - // now add to block - block.addElement(x); - lastid = x.id; +public class PDFOutput { + + /** + * This is the actual OutputStream used to write to. + */ + protected OutputStream os; + + /** + * This is the OutputStream used to write each object to. + * + *

+ * We use a separate stream, because we need to keep track of how many bytes + * have been written for each object for the xref table to work correctly. + */ + protected ByteArrayOutputStream baos; + + /** + * This is the current position within the stream + */ + protected int offset; + + /** + * This vector contains offsets of each object + */ + protected Vector offsets; + + /** + * This is used to track the /Root object (catalog) + */ + protected PDFObject rootID; + + /** + * This is used to track the /Info object (info) + */ + protected PDFObject infoID; + + /** + * This creates a PDF OutputStream + * + * @param os The output stream to write the PDF file to. + * @throws IOException if there is an I/O error. + */ + public PDFOutput(OutputStream os) throws IOException { + this.os = os; + offset = 0; + offsets = new Vector(); + baos = new ByteArrayOutputStream(); + + // Now write the PDF header + // + // Note: As the encoding is fixed here, we use getBytes(). + // + baos.write("%PDF-1.2\n".getBytes()); + + // This second comment is advised in the PDF Reference manual + // page 61 + baos.write("%\342\343\317\323\n".getBytes()); + + offset = baos.size(); + baos.writeTo(os); } - - // now write the last block - if(firstid>-1) - writeblock(firstid,block); - - // now the trailer object - baos.write("trailer\n<<\n".getBytes()); - - // the number of entries (REQUIRED) - baos.write("/Size ".getBytes()); - baos.write(Integer.toString(offsets.size()+1).getBytes()); - baos.write("\n".getBytes()); - - // the /Root catalog indirect reference (REQUIRED) - if(rootID != null) { - baos.write("/Root ".getBytes()); - baos.write(rootID.toString().getBytes()); - baos.write("\n".getBytes()); - } else - throw new IOException("Root object is not present in document"); - - // the /Info reference (OPTIONAL) - if(infoID != null) { - baos.write("/Info ".getBytes()); - baos.write(infoID.toString().getBytes()); - baos.write("\n".getBytes()); + + /** + * This method writes a PDFObject to the stream. + * + * @param ob PDFObject Obeject to write + * @exception IOException on error + */ + protected void write(PDFObject ob) throws IOException { + // Check the object to see if it's one that is needed in the trailer + // object + if (ob instanceof PDFCatalog) { + rootID = ob; + } + if (ob instanceof PDFInfo) { + infoID = ob; + } + + offsets.addElement(new PDFXref(ob.getSerialID(), offset)); + baos.reset(); + ob.write(baos); + offset += baos.size(); + baos.writeTo(os); } - - // end the trailer object - baos.write(">>\nstartxref\n".getBytes()); - baos.write(Integer.toString(offset).getBytes()); - baos.write("\n%%EOF\n".getBytes()); - - // now flush the stream - baos.writeTo(os); - os.flush(); - } - - /** - * Writes a block of references to the PDF file - * @param firstid ID of the first reference in this block - * @param block Vector containing the references in this block - * @exception IOException on write error - */ - protected void writeblock(int firstid,Vector block) throws IOException - { - baos.write(Integer.toString(firstid).getBytes()); - baos.write(" ".getBytes()); - baos.write(Integer.toString(block.size()).getBytes()); - baos.write("\n".getBytes()); - //baos.write("\n0000000000 65535 f\n".getBytes()); - - for(PDFXref x : block) { - baos.write(x.toString().getBytes()); - baos.write("\n".getBytes()); + + /** + * This closes the Stream, writing the xref table + */ + protected void close() throws IOException { + // Make sure everything is written + os.flush(); + + // we use baos to speed things up a little. + // Also, offset is preserved, and marks the begining of this block. + // This is required by PDF at the end of the PDF file. + baos.reset(); + baos.write("xref\n".getBytes()); + + // Now a single subsection for object 0 + //baos.write("0 1\n0000000000 65535 f \n".getBytes()); + // Now scan through the offsets list. The should be in sequence, + // but just in case: + int firstid = 0; // First id in block + int lastid = -1; // The last id used + Vector block = new Vector(); // xrefs in this block + + // We need block 0 to exist + block.addElement(new PDFXref(0, 0, 65535)); + + for (PDFXref x : offsets) { + + if (firstid == -1) { + firstid = x.id; + } + + // check to see if block is in range (-1 means empty) + if (lastid > -1 && x.id != (lastid + 1)) { + // no, so write this block, and reset + writeblock(firstid, block); + block.removeAllElements(); + firstid = -1; + } + + // now add to block + block.addElement(x); + lastid = x.id; + } + + // now write the last block + if (firstid > -1) { + writeblock(firstid, block); + } + + // now the trailer object + baos.write("trailer\n<<\n".getBytes()); + + // the number of entries (REQUIRED) + baos.write("/Size ".getBytes()); + baos.write(Integer.toString(offsets.size() + 1).getBytes()); + baos.write("\n".getBytes()); + + // the /Root catalog indirect reference (REQUIRED) + if (rootID != null) { + baos.write("/Root ".getBytes()); + baos.write(rootID.toString().getBytes()); + baos.write("\n".getBytes()); + } else { + throw new IOException("Root object is not present in document"); + } + + // the /Info reference (OPTIONAL) + if (infoID != null) { + baos.write("/Info ".getBytes()); + baos.write(infoID.toString().getBytes()); + baos.write("\n".getBytes()); + } + + // end the trailer object + baos.write(">>\nstartxref\n".getBytes()); + baos.write(Integer.toString(offset).getBytes()); + baos.write("\n%%EOF\n".getBytes()); + + // now flush the stream + baos.writeTo(os); + os.flush(); + } + + /** + * Writes a block of references to the PDF file + * + * @param firstid ID of the first reference in this block + * @param block Vector containing the references in this block + * @exception IOException on write error + */ + protected void writeblock(int firstid, Vector block) throws IOException { + baos.write(Integer.toString(firstid).getBytes()); + baos.write(" ".getBytes()); + baos.write(Integer.toString(block.size()).getBytes()); + baos.write("\n".getBytes()); + //baos.write("\n0000000000 65535 f\n".getBytes()); + + for (PDFXref x : block) { + baos.write(x.toString().getBytes()); + baos.write("\n".getBytes()); + } } - } } // end class PDFOutput diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFPage.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFPage.java index ed218502e..02792d69a 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFPage.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFPage.java @@ -29,8 +29,9 @@ import java.io.Serializable; import java.util.Vector; /** - *

This class defines a single page within a document. It is linked to a - * single PDFGraphics object

+ *

+ * This class defines a single page within a document. It is linked to a single + * PDFGraphics object

* * @author Peter T Mount * @author Eric Z. Beard, ericzbeard@hotmail.com @@ -39,20 +40,20 @@ import java.util.Vector; * * */ -public class PDFPage extends PDFObject implements Serializable -{ - /* +public class PDFPage extends PDFObject implements Serializable { + + /* * NOTE: The original class is the work of Peter T. Mount, who released it * in the uk.org.retep.pdf package. It was modified by Eric Z. Beard as * follows: * The package name was changed to gnu.pdf. * The formatting was changed a little bit. * It is still licensed under the LGPL. - */ + */ /** - * Default page format (Letter size with 1 inch margins and - * Portrait orientation) + * Default page format (Letter size with 1 inch margins and Portrait + * orientation) */ private static final PageFormat DEF_FORMAT = new PageFormat(); @@ -60,10 +61,10 @@ public class PDFPage extends PDFObject implements Serializable * This is this page format, ie the size of the page, margins, and rotation */ protected PageFormat pageFormat; - + /** - * This is the pages object id that this page belongs to. - * It is set by the pages object when it is added to it. + * This is the pages object id that this page belongs to. It is set by the + * pages object when it is added to it. */ protected PDFObject pdfPageList; @@ -73,8 +74,8 @@ public class PDFPage extends PDFObject implements Serializable protected Vector contents; /** - * Object ID that contains a thumbnail sketch of the page. - * -1 indicates no thumbnail. + * Object ID that contains a thumbnail sketch of the page. -1 indicates no + * thumbnail. */ protected PDFObject thumbnail; @@ -100,79 +101,79 @@ public class PDFPage extends PDFObject implements Serializable * The xobjects or other images in the pdf */ // protected Vector xobjects; - /** - * These handle the procset for this page. - * Refer to page 140 of the PDF Reference manual - * NB: Text is handled when the fonts Vector is null, and a font is created - * refer to getFont() to see where it's defined + * These handle the procset for this page. Refer to page 140 of the PDF + * Reference manual NB: Text is handled when the fonts Vector is null, and a + * font is created refer to getFont() to see where it's defined */ - protected boolean hasImageB,hasImageC,hasImageI; + protected boolean hasImageB, hasImageC, hasImageI; protected procset procset; /** * This constructs a Page object, which will hold any contents for this * page. * - *

Once created, it is added to the document via the PDF.add() method. - * (For Advanced use, via the PDFPages.add() method). + *

+ * Once created, it is added to the document via the PDF.add() method. (For + * Advanced use, via the PDFPages.add() method). * - *

This defaults to a4 media. + *

+ * This defaults to a4 media. */ - public PDFPage() - { + public PDFPage() { super("/Page"); - pageFormat = DEF_FORMAT; - contents = new Vector(); - thumbnail = null; - annotations = new Vector(); - resources = new Vector(); - // JM - imageResources = new Vector(); - fonts = new Vector(); - procset = null; + pageFormat = DEF_FORMAT; + contents = new Vector(); + thumbnail = null; + annotations = new Vector(); + resources = new Vector(); + // JM + imageResources = new Vector(); + fonts = new Vector(); + procset = null; } /** * Constructs a page using A4 media, but using the supplied orientation. + * * @param orientation Orientation: 0, 90 or 270 * @see PageFormat#PORTRAIT * @see PageFormat#LANDSCAPE * @see PageFormat#REVERSE_LANDSCAPE */ - public PDFPage(int orientation) - { + public PDFPage(int orientation) { this(); setOrientation(orientation); } /** * Constructs a page using the supplied media size and orientation. + * * @param pageFormat PageFormat describing the page size */ - public PDFPage(PageFormat pageFormat) - { + public PDFPage(PageFormat pageFormat) { this(); this.pageFormat = pageFormat; } /** * Adds to procset. + * * @param proc the String to be added. */ public void addToProcset(String proc) { - if (procset == null) { - addProcset(); - } - procset.add(proc); + if (procset == null) { + addProcset(); + } + procset.add(proc); } /** - * This returns a PDFGraphics object, which can then be used to render - * on to this page. If a previous PDFGraphics object was used, this object - * is appended to the page, and will be drawn over the top of any previous + * This returns a PDFGraphics object, which can then be used to render on to + * this page. If a previous PDFGraphics object was used, this object is + * appended to the page, and will be drawn over the top of any previous * objects. - * + * * @return a new PDFGraphics object to be used to draw this page. */ public PDFGraphics getGraphics() { @@ -180,7 +181,7 @@ public class PDFPage extends PDFObject implements Serializable PDFGraphics g = new PDFGraphics(); g.init(this); return g; - } catch(Exception ex) { + } catch (Exception ex) { ex.printStackTrace(); } @@ -189,31 +190,32 @@ public class PDFPage extends PDFObject implements Serializable /** * Returns a PDFFont, creating it if not yet used. + * * @param type Font type, usually /Type1 * @param font Font name * @param style java.awt.Font style, ie Font.NORMAL * @return a PDFFont object. */ - public PDFFont getFont(String type,String font,int style) { + public PDFFont getFont(String type, String font, int style) { // Search the fonts on this page, and return one that matches this // font. // This keeps the number of font definitions down to one per font/style - for(PDFFont ft : fonts) { - if(ft.equals(type,font,style)) + for (PDFFont ft : fonts) { + if (ft.equals(type, font, style)) { return ft; + } } // Ok, the font isn't in the page, so create one. - // We need a procset if we are using fonts, so create it (if not // already created, and add to our resources - if(fonts.size()==0) { + if (fonts.size() == 0) { addProcset(); procset.add("/Text"); } // finally create and return the font - PDFFont f = pdfDocument.getFont(type,font,style); + PDFFont f = pdfDocument.getFont(type, font, style); fonts.addElement(f); return f; } @@ -244,6 +246,7 @@ public class PDFPage extends PDFObject implements Serializable /** * Returns the page's PageFormat. + * * @return PageFormat describing the page size in device units (72dpi) */ public PageFormat getPageFormat() { @@ -252,45 +255,48 @@ public class PDFPage extends PDFObject implements Serializable /** * Gets the dimensions of the page. + * * @return a Dimension object containing the width and height of the page. */ public Dimension getDimension() { - return new Dimension((int) pageFormat.getWidth(), (int) pageFormat - .getHeight()); - } + return new Dimension((int) pageFormat.getWidth(), (int) pageFormat + .getHeight()); + } /** * Gets the imageable area of the page. + * * @return a Rectangle containing the bounds of the imageable area. */ - public Rectangle getImageableArea() { - return new Rectangle((int) pageFormat.getImageableX(), (int) pageFormat - .getImageableY(), - (int) (pageFormat.getImageableX() + pageFormat - .getImageableWidth()), (int) (pageFormat - .getImageableY() + pageFormat.getImageableHeight())); - } + public Rectangle getImageableArea() { + return new Rectangle((int) pageFormat.getImageableX(), (int) pageFormat + .getImageableY(), + (int) (pageFormat.getImageableX() + pageFormat + .getImageableWidth()), (int) (pageFormat + .getImageableY() + pageFormat.getImageableHeight())); + } /** * Sets the page's orientation. * - *

Normally, this should be done when the page is created, to avoid + *

+ * Normally, this should be done when the page is created, to avoid * problems. * - * @param orientation a PageFormat orientation constant: + * @param orientation a PageFormat orientation constant: * PageFormat.PORTRAIT, PageFormat.LANDSACPE or PageFromat.REVERSE_LANDSACPE */ public void setOrientation(int orientation) { - pageFormat.setOrientation(orientation); - } + pageFormat.setOrientation(orientation); + } /** - * Returns the pages orientation: - * PageFormat.PORTRAIT, PageFormat.LANDSACPE or PageFromat.REVERSE_LANDSACPE - * - * @see java.awt.print.PageFormat - * @return current orientation of the page - */ + * Returns the pages orientation: PageFormat.PORTRAIT, PageFormat.LANDSACPE + * or PageFromat.REVERSE_LANDSACPE + * + * @see java.awt.print.PageFormat + * @return current orientation of the page + */ public int getOrientation() { return pageFormat.getOrientation(); } @@ -298,7 +304,8 @@ public class PDFPage extends PDFObject implements Serializable /** * This adds an object that describes some content to this page. * - *

Note: Objects that describe contents must be added using this + *

+ * Note: Objects that describe contents must be added using this * method _AFTER_ the PDF.add() method has been called. * * @param ob PDFObject describing some contents @@ -310,8 +317,9 @@ public class PDFPage extends PDFObject implements Serializable /** * This adds an Annotation to the page. * - *

As with other objects, the annotation must be added to the pdf - * document using PDF.add() before adding to the page. + *

+ * As with other objects, the annotation must be added to the pdf document + * using PDF.add() before adding to the page. * * @param ob Annotation to add. */ @@ -321,6 +329,7 @@ public class PDFPage extends PDFObject implements Serializable /** * This method adds a text note to the document. + * * @param note Text of the note * @param x Coordinate of note * @param y Coordinate of note @@ -328,12 +337,12 @@ public class PDFPage extends PDFObject implements Serializable * @param h Height of the note * @return Returns the annotation, so other settings can be changed. */ - public PDFAnnot addNote(String note,int x,int y,int w,int h) { - int xy1[] = cxy(x,y+h); - int xy2[] = cxy(x+w,y); - PDFAnnot ob = new PDFAnnot(xy1[0],xy1[1], - xy2[0],xy2[1], - note); + public PDFAnnot addNote(String note, int x, int y, int w, int h) { + int xy1[] = cxy(x, y + h); + int xy2[] = cxy(x + w, y); + PDFAnnot ob = new PDFAnnot(xy1[0], xy1[1], + xy2[0], xy2[1], + note); pdfDocument.add(ob); annotations.addElement(ob); return ob; @@ -341,6 +350,7 @@ public class PDFPage extends PDFObject implements Serializable /** * Adds a hyperlink to the document. + * * @param x Coordinate of active area * @param y Coordinate of active area * @param w Width of the active area @@ -349,13 +359,13 @@ public class PDFPage extends PDFObject implements Serializable * displayed, the zoom factor will be changed to fit the display. * @return Returns the annotation, so other settings can be changed. */ - public PDFAnnot addLink(int x,int y,int w,int h,PDFObject dest) { - int xy1[] = cxy(x,y+h); - int xy2[] = cxy(x+w,y); - PDFAnnot ob = new PDFAnnot(xy1[0],xy1[1], - xy2[0],xy2[1], - dest - ); + public PDFAnnot addLink(int x, int y, int w, int h, PDFObject dest) { + int xy1[] = cxy(x, y + h); + int xy2[] = cxy(x + w, y); + PDFAnnot ob = new PDFAnnot(xy1[0], xy1[1], + xy2[0], xy2[1], + dest + ); pdfDocument.add(ob); annotations.addElement(ob); return ob; @@ -363,6 +373,7 @@ public class PDFPage extends PDFObject implements Serializable /** * Adds a hyperlink to the document. + * * @param x Coordinate of active area * @param y Coordinate of active area * @param w Width of the active area @@ -374,39 +385,42 @@ public class PDFPage extends PDFObject implements Serializable * @param vh Height of the view area * @return Returns the annotation, so other settings can be changed. */ - public PDFAnnot addLink(int x,int y,int w,int h, - PDFObject dest, - int vx,int vy,int vw,int vh) { - int xy1[] = cxy(x,y+h); - int xy2[] = cxy(x+w,y); - int xy3[] = cxy(vx,vy+vh); - int xy4[] = cxy(vx+vw,vy); - PDFAnnot ob = new PDFAnnot(xy1[0],xy1[1], - xy2[0],xy2[1], - dest, - xy3[0],xy3[1], - xy4[0],xy4[1] - ); + public PDFAnnot addLink(int x, int y, int w, int h, + PDFObject dest, + int vx, int vy, int vw, int vh) { + int xy1[] = cxy(x, y + h); + int xy2[] = cxy(x + w, y); + int xy3[] = cxy(vx, vy + vh); + int xy4[] = cxy(vx + vw, vy); + PDFAnnot ob = new PDFAnnot(xy1[0], xy1[1], + xy2[0], xy2[1], + dest, + xy3[0], xy3[1], + xy4[0], xy4[1] + ); pdfDocument.add(ob); annotations.addElement(ob); return ob; } - /** Contains the text strings for the xobjects. */ - private Vector xobjects = new Vector(); - /** - * This adds an XObject resource to the page. - * The string should be of the format - * /Name ObjectNumber RevisionNumber R as in /Image1 13 0 R . + * Contains the text strings for the xobjects. + */ + private Vector xobjects = new Vector(); + + /** + * This adds an XObject resource to the page. The string should be of the + * format /Name ObjectNumber RevisionNumber R as in /Image1 13 0 R . + * * @param inxobject the XObject resource to be added. */ - public void addXObject(String inxobject){ + public void addXObject(String inxobject) { xobjects.addElement(inxobject); } /** * This adds a resource to the page. + * * @param resource String defining the resource */ public void addResource(String resource) { @@ -416,6 +430,7 @@ public class PDFPage extends PDFObject implements Serializable // JM /** * This adds an image resource to the page. + * * @param resource the XObject resource to be added. */ public void addImageResource(String resource) { @@ -424,34 +439,37 @@ public class PDFPage extends PDFObject implements Serializable /** * This adds an object that describes a thumbnail for this page. - *

Note: The object must already exist in the PDF, as only the - * object ID is stored. + *

+ * Note: The object must already exist in the PDF, as only the object + * ID is stored. + * * @param thumbnail PDFObject containing the thumbnail */ - public void setThumbnail(PDFObject thumbnail) - { + public void setThumbnail(PDFObject thumbnail) { this.thumbnail = thumbnail; } /** * This method attaches an outline to the current page being generated. When * selected, the outline displays the top of the page. + * * @param title Outline title to attach * @return PDFOutline object created, for addSubOutline if required. */ public PDFOutline addOutline(String title) { - PDFOutline outline = new PDFOutline(title,this); + PDFOutline outline = new PDFOutline(title, this); pdfDocument.add(outline); pdfDocument.getOutline().add(outline); return outline; } /** - * This method attaches an outline to the current page being generated. - * When selected, the outline displays the top of the page. + * This method attaches an outline to the current page being generated. When + * selected, the outline displays the top of the page. * - *

Note: If the outline is not in the top level (ie below another - * outline) then it must not be passed to this method. + *

+ * Note: If the outline is not in the top level (ie below another outline) + * then it must not be passed to this method. * * @param title Outline title to attach * @param x Left coordinate of region @@ -460,12 +478,12 @@ public class PDFPage extends PDFObject implements Serializable * @param h Height coordinate of region * @return PDFOutline object created, for addSubOutline if required. */ - public PDFOutline addOutline(String title,int x,int y,int w,int h) { - int xy1[] = cxy(x,y+h); - int xy2[] = cxy(x+w,y); - PDFOutline outline = new PDFOutline(title,this, - xy1[0],xy1[1], - xy2[0],xy2[1]); + public PDFOutline addOutline(String title, int x, int y, int w, int h) { + int xy1[] = cxy(x, y + h); + int xy2[] = cxy(x + w, y); + PDFOutline outline = new PDFOutline(title, this, + xy1[0], xy1[1], + xy2[0], xy2[1]); pdfDocument.add(outline); pdfDocument.getOutline().add(outline); return outline; @@ -475,13 +493,11 @@ public class PDFPage extends PDFObject implements Serializable * @param os OutputStream to send the object to * @exception IOException on error */ - public void write(OutputStream os) throws IOException - { + public void write(OutputStream os) throws IOException { // Write the object header writeStart(os); // now the objects body - // the /Parent pages object os.write("/Parent ".getBytes()); os.write(pdfPageList.toString().getBytes()); @@ -493,9 +509,9 @@ public class PDFPage extends PDFObject implements Serializable os.write(" ".getBytes()); os.write(Integer.toString(0).getBytes()); os.write(" ".getBytes()); - os.write(Integer.toString((int)pageFormat.getWidth()).getBytes()); + os.write(Integer.toString((int) pageFormat.getWidth()).getBytes()); os.write(" ".getBytes()); - os.write(Integer.toString((int)pageFormat.getHeight()).getBytes()); + os.write(Integer.toString((int) pageFormat.getHeight()).getBytes()); os.write("]\n".getBytes()); // Rotation (if not zero) @@ -504,14 +520,13 @@ public class PDFPage extends PDFObject implements Serializable // os.write(Integer.toString(rotate).getBytes()); // os.write("\n".getBytes()); // } - // Now the resources os.write("/Resources << ".getBytes()); // fonts - if(fonts.size()>0) { - //os.write("/Font << ".getBytes()); + if (fonts.size() > 0) { + //os.write("/Font << ".getBytes()); os.write("\n/Font << ".getBytes()); - for(PDFFont font : fonts) { + for (PDFFont font : fonts) { os.write(font.getName().getBytes()); os.write(" ".getBytes()); os.write(font.toString().getBytes()); @@ -520,41 +535,41 @@ public class PDFPage extends PDFObject implements Serializable os.write(">> ".getBytes()); } // Now the XObjects - if (xobjects.size() > 0){ + if (xobjects.size() > 0) { os.write("\n/XObject << ".getBytes()); - for(String str : xobjects) { + for (String str : xobjects) { os.write(str.getBytes()); os.write(" ".getBytes()); } os.write(">> ".getBytes()); } // Any other resources - for(String str : resources) { + for (String str : resources) { os.write(str.getBytes()); os.write(" ".getBytes()); } - // JM - if(imageResources.size() > 0) { - os.write("/XObject << ".getBytes()); - for(String str : imageResources) { - os.write(str.getBytes()); - os.write(" ".getBytes()); - } - os.write(" >> ".getBytes()); - } + // JM + if (imageResources.size() > 0) { + os.write("/XObject << ".getBytes()); + for (String str : imageResources) { + os.write(str.getBytes()); + os.write(" ".getBytes()); + } + os.write(" >> ".getBytes()); + } os.write(">>\n".getBytes()); // The thumbnail - if(thumbnail!=null) { + if (thumbnail != null) { os.write("/Thumb ".getBytes()); os.write(thumbnail.toString().getBytes()); os.write("\n".getBytes()); } // the /Contents pages object - if(contents.size()>0) { - if(contents.size()==1) { - PDFObject ob = (PDFObject)contents.elementAt(0); + if (contents.size() > 0) { + if (contents.size() == 1) { + PDFObject ob = (PDFObject) contents.elementAt(0); os.write("/Contents ".getBytes()); os.write(ob.toString().getBytes()); os.write("\n".getBytes()); @@ -566,7 +581,7 @@ public class PDFPage extends PDFObject implements Serializable } // The /Annots object - if(annotations.size()>0) { + if (annotations.size() > 0) { os.write("/Annots ".getBytes()); os.write(PDFObject.toArray(annotations).getBytes()); os.write("\n".getBytes()); @@ -580,9 +595,9 @@ public class PDFPage extends PDFObject implements Serializable * This creates a procset and sets up the page to reference it */ private void addProcset() { - if(procset==null) { + if (procset == null) { pdfDocument.add(procset = new procset()); - resources.addElement("/ProcSet "+procset); + resources.addElement("/ProcSet " + procset); } } @@ -590,6 +605,7 @@ public class PDFPage extends PDFObject implements Serializable * This defines a procset */ public class procset extends PDFObject { + private Vector set; /** @@ -608,7 +624,7 @@ public class PDFPage extends PDFObject implements Serializable * @param proc Entry to add to the procset */ public void add(String proc) { - set.addElement(" "+proc); + set.addElement(" " + proc); } /** @@ -624,8 +640,9 @@ public class PDFPage extends PDFObject implements Serializable // now the objects body os.write("[".getBytes()); - for(String str : set) + for (String str : set) { os.write(str.getBytes()); + } os.write("]\n".getBytes()); // finish off with its footer @@ -637,33 +654,36 @@ public class PDFPage extends PDFObject implements Serializable /** * This utility method converts the y coordinate from Java to User space * within the page. + * * @param x Coordinate in Java space * @param y Coordinate in Java space * @return y Coordinate in User space */ - public int cy(int x,int y) { - return cxy(x,y)[1]; + public int cy(int x, int y) { + return cxy(x, y)[1]; } /** * This utility method converts the y coordinate from Java to User space * within the page. + * * @param x Coordinate in Java space * @param y Coordinate in Java space * @return x Coordinate in User space */ public int cx(int x, int y) { - return cxy(x,y)[0]; + return cxy(x, y)[0]; } /** - * This utility method converts the Java coordinates to User space - * within the page. + * This utility method converts the Java coordinates to User space within + * the page. + * * @param x Coordinate in Java space * @param y Coordinate in Java space * @return array containing the x & y Coordinate in User space */ - public int[] cxy(int x,int y) { + public int[] cxy(int x, int y) { int r[] = new int[2]; r[0] = x; r[1] = (int) pageFormat.getHeight() - y; diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFPageList.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFPageList.java index 9b4691c27..b1774a04e 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFPageList.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFPageList.java @@ -31,65 +31,64 @@ import java.util.*; * @author Eric Z. Beard, ericzbeard@hotmail.com * @version $Revision: 1.2 $, $Date: 2007/08/26 18:56:35 $ */ -public class PDFPageList extends PDFObject -{ - - /** - * This holds the pages - */ - private Vector pages; - - /** - * This constructs a PDF Pages object. - */ - public PDFPageList() { - super("/Pages"); - pages = new Vector(); - } - - /** - * This adds a page to the document. - * - * @param page PDFPage to add - */ - public void add(PDFPage page) { - pages.addElement(page); - - // Tell the page of ourselves - page.pdfPageList = this; - } - - /** - * This returns a specific page. Used by the PDF class. - * @param page page number to return - * @return PDFPage at that position - */ - public PDFPage getPage(int page) { - return (PDFPage)(pages.elementAt(page)); - } - - /** - * @param os OutputStream to send the object to - * @exception IOException on error - */ - public void write(OutputStream os) throws IOException { - // Write the object header - writeStart(os); - - // now the objects body - - // the Kids array - os.write("/Kids ".getBytes()); - os.write(PDFObject.toArray(pages).getBytes()); - os.write("\n".getBytes()); - - // the number of Kids in this document - os.write("/Count ".getBytes()); - os.write(Integer.toString(pages.size()).getBytes()); - os.write("\n".getBytes()); - - // finish off with its footer - writeEnd(os); - } - +public class PDFPageList extends PDFObject { + + /** + * This holds the pages + */ + private Vector pages; + + /** + * This constructs a PDF Pages object. + */ + public PDFPageList() { + super("/Pages"); + pages = new Vector(); + } + + /** + * This adds a page to the document. + * + * @param page PDFPage to add + */ + public void add(PDFPage page) { + pages.addElement(page); + + // Tell the page of ourselves + page.pdfPageList = this; + } + + /** + * This returns a specific page. Used by the PDF class. + * + * @param page page number to return + * @return PDFPage at that position + */ + public PDFPage getPage(int page) { + return (PDFPage) (pages.elementAt(page)); + } + + /** + * @param os OutputStream to send the object to + * @exception IOException on error + */ + public void write(OutputStream os) throws IOException { + // Write the object header + writeStart(os); + + // now the objects body + // the Kids array + os.write("/Kids ".getBytes()); + os.write(PDFObject.toArray(pages).getBytes()); + os.write("\n".getBytes()); + + // the number of Kids in this document + os.write("/Count ".getBytes()); + os.write(Integer.toString(pages.size()).getBytes()); + os.write("\n".getBytes()); + + // finish off with its footer + writeEnd(os); + } + } // end class PDFPageList diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFPrinterJob.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFPrinterJob.java index bcac572a5..6dd3045ed 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFPrinterJob.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFPrinterJob.java @@ -25,250 +25,249 @@ import javax.swing.JFileChooser; * This class extends awt's PrinterJob, to provide a simple method of writing * PDF documents. *

- * + * *

* You can use this with any code that uses Java's printing mechanism. It does * include a few extra methods to provide access to some of PDF's features like * annotations, or outlines. *

- * + * * @author Gilbert DeLeeuw, gil1@users.sourceforge.net */ public class PDFPrinterJob extends PrinterJob { - /** - * The file chooser - */ - private static JFileChooser fileChooser; + /** + * The file chooser + */ + private static JFileChooser fileChooser; - /** - * Printing options; - */ - private PrintRequestAttributeSet attributes; + /** + * Printing options; + */ + private PrintRequestAttributeSet attributes; - /** - * PDF document properties - */ - private PDFInfo info; + /** + * PDF document properties + */ + private PDFInfo info; - /** - * A pageable, or null - */ - private Pageable pageable = null; + /** + * A pageable, or null + */ + private Pageable pageable = null; - /** - * Page format. - */ - private PageFormat pageFormat; + /** + * Page format. + */ + private PageFormat pageFormat; - /** - * The Printable object to print. - */ - private Printable printable; + /** + * The Printable object to print. + */ + private Printable printable; - /** - * The actual print job. - */ - private PDFJob printJob; + /** + * The actual print job. + */ + private PDFJob printJob; - /** - * Initializes a new instance of PDFPrinterJob. - */ - public PDFPrinterJob() { - attributes = new HashPrintRequestAttributeSet(); - info = new PDFInfo(); - pageFormat = new PageFormat(); // default page format. - setJobName("Java Printing"); - } + /** + * Initializes a new instance of PDFPrinterJob. + */ + public PDFPrinterJob() { + attributes = new HashPrintRequestAttributeSet(); + info = new PDFInfo(); + pageFormat = new PageFormat(); // default page format. + setJobName("Java Printing"); + } - @Override - public void cancel() { - // Cancel is not an option - } + @Override + public void cancel() { + // Cancel is not an option + } - @Override - public PageFormat defaultPage(PageFormat page) { - return validatePage(page); - } + @Override + public PageFormat defaultPage(PageFormat page) { + return validatePage(page); + } - @Override - public int getCopies() { - return ((IntegerSyntax) attributes.get(Copies.class)).getValue(); - } + @Override + public int getCopies() { + return ((IntegerSyntax) attributes.get(Copies.class)).getValue(); + } - @Override - public String getJobName() { - return ((TextSyntax) attributes.get(JobName.class)).getValue(); - } + @Override + public String getJobName() { + return ((TextSyntax) attributes.get(JobName.class)).getValue(); + } - public static PrinterJob getPrinterJob() { - return new PDFPrinterJob(); - } + public static PrinterJob getPrinterJob() { + return new PDFPrinterJob(); + } - @Override - public String getUserName() { - return ((TextSyntax) attributes.get(RequestingUserName.class)) - .getValue(); - } + @Override + public String getUserName() { + return ((TextSyntax) attributes.get(RequestingUserName.class)) + .getValue(); + } - @Override - public boolean isCancelled() { - return false; - } + @Override + public boolean isCancelled() { + return false; + } - @Override - public PageFormat pageDialog(PageFormat page) throws HeadlessException { - // No page dialog is supported. - return (PageFormat) page.clone(); - } + @Override + public PageFormat pageDialog(PageFormat page) throws HeadlessException { + // No page dialog is supported. + return (PageFormat) page.clone(); + } - /** - * Prints a set of pages. - * - * @param pathname - * the full path for the output PDF file. - * @exception PrinterException - * an error in the print system caused the job to be aborted. - * @see Book - * @see Pageable - * @see Printable - */ - public void print(String pathname) throws PrinterException { - int pageCount; - File file = null; - FileOutputStream fileOutputStream = null; + /** + * Prints a set of pages. + * + * @param pathname the full path for the output PDF file. + * @exception PrinterException an error in the print system caused the job + * to be aborted. + * @see Book + * @see Pageable + * @see Printable + */ + public void print(String pathname) throws PrinterException { + int pageCount; + File file = null; + FileOutputStream fileOutputStream = null; - try { - file = new File(pathname); - fileOutputStream = new FileOutputStream(file); - } catch (Exception e) { - System.err.println("Error!! - Invalid output file path: " - + pathname); - } + try { + file = new File(pathname); + fileOutputStream = new FileOutputStream(file); + } catch (Exception e) { + System.err.println("Error!! - Invalid output file path: " + + pathname); + } - PDFGraphics pdfGraphics = null; - printJob = new PDFJob(fileOutputStream); + PDFGraphics pdfGraphics = null; + printJob = new PDFJob(fileOutputStream); - if (info != null) { - printJob.getPDFDocument().setPDFInfo(info); - } + if (info != null) { + printJob.getPDFDocument().setPDFInfo(info); + } - pageCount = pageable.getNumberOfPages(); - for (int pageIndex = 0; pageIndex < pageCount; pageIndex++) { - pageFormat = pageable.getPageFormat(pageIndex); + pageCount = pageable.getNumberOfPages(); + for (int pageIndex = 0; pageIndex < pageCount; pageIndex++) { + pageFormat = pageable.getPageFormat(pageIndex); - pdfGraphics = (PDFGraphics) printJob.getGraphics(pageFormat); - printable = pageable.getPrintable(pageIndex); - printable.print(pdfGraphics, pageFormat, pageIndex); - pdfGraphics.dispose(); - } + pdfGraphics = (PDFGraphics) printJob.getGraphics(pageFormat); + printable = pageable.getPrintable(pageIndex); + printable.print(pdfGraphics, pageFormat, pageIndex); + pdfGraphics.dispose(); + } - printJob.end(); + printJob.end(); - } + } - @Override - public void print() throws PrinterException { - File file; - File path; - String jobName = getJobName(); + @Override + public void print() throws PrinterException { + File file; + File path; + String jobName = getJobName(); - if (fileChooser == null) { - fileChooser = new JFileChooser(); - fileChooser.setMultiSelectionEnabled(false); - fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - } + if (fileChooser == null) { + fileChooser = new JFileChooser(); + fileChooser.setMultiSelectionEnabled(false); + fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + } - // Make sure job name is not blank - if (jobName.equals("")) { - jobName = "Java Printing"; - } - // Eliminate invalid characters from job name. - jobName = jobName.replaceAll("\\\\", "-"); - jobName = jobName.replaceAll("/", "-"); + // Make sure job name is not blank + if (jobName.equals("")) { + jobName = "Java Printing"; + } + // Eliminate invalid characters from job name. + jobName = jobName.replaceAll("\\\\", "-"); + jobName = jobName.replaceAll("/", "-"); - path = fileChooser.getCurrentDirectory(); - file = new File(path, jobName + ".pdf"); + path = fileChooser.getCurrentDirectory(); + file = new File(path, jobName + ".pdf"); - // Dialog to get file name... - fileChooser.setSelectedFile(file); + // Dialog to get file name... + fileChooser.setSelectedFile(file); - // Print - if (fileChooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { - file = fileChooser.getSelectedFile(); - print(file.getAbsolutePath()); - } - } + // Print + if (fileChooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { + file = fileChooser.getSelectedFile(); + print(file.getAbsolutePath()); + } + } - @Override - public boolean printDialog() throws HeadlessException { - return true; - } + @Override + public boolean printDialog() throws HeadlessException { + return true; + } - /** - * Sets the author for this document. - * - * @param author the author's name. - */ - public void setAuthor(String author) { - info.setAuthor(author); - } - - @Override - public void setCopies(int copies) { - // Will be ignored, but add attribute anyway - attributes.add(new Copies(copies)); - } + /** + * Sets the author for this document. + * + * @param author the author's name. + */ + public void setAuthor(String author) { + info.setAuthor(author); + } - /** - * Sets the creator for this document. - * - * @param creator the application name. - */ - public void setCreator(String creator) { - info.setCreator(creator); - } + @Override + public void setCopies(int copies) { + // Will be ignored, but add attribute anyway + attributes.add(new Copies(copies)); + } - @Override - public void setJobName(String jobName) { - attributes.add(new JobName(jobName, Locale.getDefault())); + /** + * Sets the creator for this document. + * + * @param creator the application name. + */ + public void setCreator(String creator) { + info.setCreator(creator); + } - if (info.getTitle() == null) { - info.setTitle(jobName); - } - } + @Override + public void setJobName(String jobName) { + attributes.add(new JobName(jobName, Locale.getDefault())); - @Override - public void setPageable(Pageable document) throws NullPointerException { - if (document == null) { - throw new NullPointerException("Pageable cannot be null."); - } - this.pageable = document; - } + if (info.getTitle() == null) { + info.setTitle(jobName); + } + } - @Override - public void setPrintable(Printable painter) { - this.printable = painter; - } + @Override + public void setPageable(Pageable document) throws NullPointerException { + if (document == null) { + throw new NullPointerException("Pageable cannot be null."); + } + this.pageable = document; + } - @Override - public void setPrintable(Printable painter, PageFormat format) { - this.printable = painter; - this.pageFormat = format; - } + @Override + public void setPrintable(Printable painter) { + this.printable = painter; + } - /** - * Sets the title for this document. - * - * @param title the document title. - */ - public void setTitle(String title) { - info.setTitle(title); - } + @Override + public void setPrintable(Printable painter, PageFormat format) { + this.printable = painter; + this.pageFormat = format; + } - @Override - public PageFormat validatePage(PageFormat page) { - return (PageFormat) page.clone(); - } + /** + * Sets the title for this document. + * + * @param title the document title. + */ + public void setTitle(String title) { + info.setTitle(title); + } + + @Override + public PageFormat validatePage(PageFormat page) { + return (PageFormat) page.clone(); + } } diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFStream.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFStream.java index 3c2162208..611b0673b 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFStream.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFStream.java @@ -27,105 +27,111 @@ import java.io.Serializable; import java.util.zip.DeflaterOutputStream; /** - * This class implements a PDF stream object. In PDF, streams contain data - * like the graphic operators that render a page, or the pixels of an image. + * This class implements a PDF stream object. In PDF, streams contain data like + * the graphic operators that render a page, or the pixels of an image. * - *

In PDF, a stream can be compressed using several different methods, or - * left uncompressed. Here we support both uncompressed, and FlateDecode as - * it's supported by the java core. + *

+ * In PDF, a stream can be compressed using several different methods, or left + * uncompressed. Here we support both uncompressed, and FlateDecode as it's + * supported by the java core. * * @author Peter T Mount http://www.retep.org.uk/pdf/ * @author Eric Z. Beard, ericzbeard@hotmail.com * @version $Revision: 1.2 $, $Date: 2007/08/26 18:56:35 $ * */ -public class PDFStream extends PDFObject implements Serializable -{ +public class PDFStream extends PDFObject implements Serializable { - /* + /* * NOTE: The original class is the work of Peter T. Mount, who released it * in the uk.org.retep.pdf package. It was modified by Eric Z. Beard as * follows: * The package name was changed to gnu.jpdf. * The formatting was changed a little bit. * It is still licensed under the LGPL. - */ - + */ /** * This holds the stream's content. */ transient ByteArrayOutputStream buf; - + /** * True if we will compress the stream in the pdf file */ boolean deflate; - + /** * Constructs a plain stream. - *

By default, the stream will be compressed. + *

+ * By default, the stream will be compressed. */ public PDFStream() { this(null); } - + /** * Constructs a stream. The supplied type is stored in the stream's header * and is used by other objects that extend the PDFStream class (like * PDFImage). - *

By default, the stream will be compressed. + *

+ * By default, the stream will be compressed. + * * @param type type for the stream * @see PDFImage */ public PDFStream(String type) { super(type); buf = new ByteArrayOutputStream(); - + // default deflate mode deflate = false; } - + /** * @param mode true will FlatDecode the stream */ public void setDeflate(boolean mode) { - // TODO: Restore the next line of code to allow deflate to occur. + // TODO: Restore the next line of code to allow deflate to occur. deflate = mode; } - + /** * Returs true if the stream will be compressed. + * * @return true if compression is enabled */ public boolean getDeflate() { return deflate; } - + /** * Returns the OutputStream that will append to this stream. + * * @return The stream for this object */ public OutputStream getOutputStream() { - return (OutputStream)buf; + return (OutputStream) buf; } - + /** * Creates a PrintWriter that will append to this stream. + * * @return a PrintWriter to write to the stream */ public PrintWriter getWriter() { - return new PrintWriter(buf,true); + return new PrintWriter(buf, true); } - + /** * This is for extenders, and provides access to the stream. + * * @return ByteArrayOutputStream containing the contents. */ public ByteArrayOutputStream getStream() { return buf; } - + /** * @param os OutputStream to send the object to * @exception IOException on error @@ -136,31 +142,32 @@ public class PDFStream extends PDFObject implements Serializable // Unlike most PDF objects, we dont call writeEnd(os) because we // contain a stream } - + /** - * This inserts the Streams length, then the actual stream, finally - * the end of stream/object markers. + * This inserts the Streams length, then the actual stream, finally the end + * of stream/object markers. * - *

This is intended for anyone extending PDFStream, as objects - * containing streams do no use writeEnd(), and they must be able - * to write the actual stream. + *

+ * This is intended for anyone extending PDFStream, as objects containing + * streams do no use writeEnd(), and they must be able to write the actual + * stream. * * @param os OutputStream to send the object to * @exception IOException on error */ public void writeStream(OutputStream os) throws IOException { - if(deflate) { + if (deflate) { ByteArrayOutputStream b = new ByteArrayOutputStream(); DeflaterOutputStream dos = new DeflaterOutputStream(b); //,new Deflater(Deflater.BEST_COMPRESSION,true)); buf.writeTo(dos); dos.finish(); dos.close(); - + // FlatDecode is compatible with the java.util.zip.Deflater class os.write("/Filter /FlateDecode\n".getBytes()); os.write("/Length ".getBytes()); - os.write(Integer.toString(b.size()+1).getBytes()); + os.write(Integer.toString(b.size() + 1).getBytes()); os.write("\n>>\nstream\n".getBytes()); b.writeTo(os); os.write("\n".getBytes()); @@ -171,48 +178,44 @@ public class PDFStream extends PDFObject implements Serializable os.write("\n>>\nstream\n".getBytes()); buf.writeTo(os); } - + os.write("endstream\nendobj\n".getBytes()); - + // Unlike most PDF objects, we dont call writeEnd(os) because we // contain a stream } - - - // Why is this here? Did it have a specific purpose? - - + // Why is this here? Did it have a specific purpose? /** * This implements our own special Serialization for this object. * - *

Here we write the length of the stream's contents, then a byte - * array of the contents. We have to do this, as ByteArrayOutputStream - * is not serializable (hence the transient tag). + *

+ * Here we write the length of the stream's contents, then a byte array of + * the contents. We have to do this, as ByteArrayOutputStream is not + * serializable (hence the transient tag). * */ - private void writeObject(java.io.ObjectOutputStream out) throws IOException - { + private void writeObject(java.io.ObjectOutputStream out) throws IOException { out.writeInt(buf.size()); out.write(buf.toByteArray()); } - + /** * This implements our own special Serialization for this object * - *

Here we read the length of the stream's contents, then a byte - * array of the contents. Then we recreate a new ByteArrayOutputStream. - * We have to do this, as ByteArrayOutputStream is not serializable - * (hence the transient tag). + *

+ * Here we read the length of the stream's contents, then a byte array of + * the contents. Then we recreate a new ByteArrayOutputStream. We have to do + * this, as ByteArrayOutputStream is not serializable (hence the transient + * tag). * */ - private void readObject(java.io.ObjectInputStream in) throws IOException - { + private void readObject(java.io.ObjectInputStream in) throws IOException { int l = in.readInt(); byte b[] = new byte[l]; - in.read(b,0,l); - buf=new ByteArrayOutputStream(l); + in.read(b, 0, l); + buf = new ByteArrayOutputStream(l); buf.write(b); } - + } diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFStringHelper.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFStringHelper.java index 25b80b514..9a2fb9faf 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/PDFStringHelper.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFStringHelper.java @@ -21,7 +21,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - package gnu.jpdf; import java.io.UnsupportedEncodingException; @@ -37,22 +36,25 @@ import java.util.logging.Logger; * @version $Revision: 1.2 $, $Date: 2007/08/26 18:56:35 $ * */ -public class PDFStringHelper -{ - /** - * This converts a string into PDF. It prefixes ( or ) with \ - * and wraps the string in a ( ) pair. - * @param s String to convert - * @return String that can be placed in a PDF (or Postscript) stream - */ - public static String makePDFString(String s) { - if(s.indexOf("(")>-1) - s = replace(s,"(","\\("); - - if(s.indexOf(")")>-1) - s = replace(s,")","\\)"); - - return "("+s+")"; +public class PDFStringHelper { + + /** + * This converts a string into PDF. It prefixes ( or ) with \ and wraps the + * string in a ( ) pair. + * + * @param s String to convert + * @return String that can be placed in a PDF (or Postscript) stream + */ + public static String makePDFString(String s) { + if (s.indexOf("(") > -1) { + s = replace(s, "(", "\\("); + } + + if (s.indexOf(")") > -1) { + s = replace(s, ")", "\\)"); + } + + return "(" + s + ")"; } public static byte[] makeRawPDFString(String s) { @@ -84,32 +86,34 @@ public class PDFStringHelper } return null; } - - /** - * Helper method for toString() - * @param s source string - * @param f string to remove - * @param t string to replace f - * @return string with f replaced by t - */ - private static String replace(String source, - String removeThis, - String replaceWith) { - StringBuffer b = new StringBuffer(); - int p = 0, c=0; - - while(c>-1) { - if((c = source.indexOf(removeThis,p)) > -1) { - b.append(source.substring(p,c)); - b.append(replaceWith); - p=c+1; - } + + /** + * Helper method for toString() + * + * @param s source string + * @param f string to remove + * @param t string to replace f + * @return string with f replaced by t + */ + private static String replace(String source, + String removeThis, + String replaceWith) { + StringBuffer b = new StringBuffer(); + int p = 0, c = 0; + + while (c > -1) { + if ((c = source.indexOf(removeThis, p)) > -1) { + b.append(source.substring(p, c)); + b.append(replaceWith); + p = c + 1; + } + } + + // include any remaining text + if (p < source.length()) { + b.append(source.substring(p)); + } + + return b.toString(); } - - // include any remaining text - if(pThis class is used to hold the xref information in the PDF - * Trailer block.

+ *

+ * This class is used to hold the xref information in the PDF Trailer block.

* - *

Basically, each object has an id, and an offset in the end file.

+ *

+ * Basically, each object has an id, and an offset in the end file.

* - *

See the Adobe PDF Manual for more information. This class will - * normally not be used directly by a developer

+ *

+ * See the Adobe PDF Manual for more information. This class will normally not + * be used directly by a developer

* * @author Peter T. Mount * @author Eric Z. Beard, ericzbeard@hotmail.com * @version $Revision: 1.2 $, $Date: 2007/08/26 18:56:35 $ * */ -public class PDFXref -{ +public class PDFXref { - /* + /* * NOTE: Originally an inner class in PDF.java (now PDFDocument) written * by Peter Mount for uk.org.retep.pdf - */ + */ + /** + * The id of a PDF Object + */ + public int id; - /** - * The id of a PDF Object - */ - public int id; + /** + * The offset within the PDF file + */ + public int offset; - /** - * The offset within the PDF file - */ - public int offset; - - /** - * The generation of the object, usually 0 - */ - public int generation; - - /** - * Creates a crossreference for a PDF Object - * @param id The object's ID - * @param offset The object's position in the file - */ - public PDFXref(int id,int offset) - { - this(id,offset,0); - } - - /** - * Creates a crossreference for a PDF Object - * - * @param id The object's ID - * @param offset The object's position in the file - * @param generation The object's generation, usually 0 - */ - public PDFXref(int id,int offset,int generation) - { - this.id = id; - this.offset = offset; - this.generation = generation; - } - - /** - * @return The xref in the format of the xref section in the PDF file - */ - public String toString() - { - String of = Integer.toString(offset); - String ge = Integer.toString(generation); - String rs = "0000000000".substring(0, 10-of.length()) + - of + - " " + - "00000".substring(0,5-ge.length())+ge; - if(generation==65535) - return rs+" f "; - return rs+" n "; - } + /** + * The generation of the object, usually 0 + */ + public int generation; + + /** + * Creates a crossreference for a PDF Object + * + * @param id The object's ID + * @param offset The object's position in the file + */ + public PDFXref(int id, int offset) { + this(id, offset, 0); + } + + /** + * Creates a crossreference for a PDF Object + * + * @param id The object's ID + * @param offset The object's position in the file + * @param generation The object's generation, usually 0 + */ + public PDFXref(int id, int offset, int generation) { + this.id = id; + this.offset = offset; + this.generation = generation; + } + + /** + * @return The xref in the format of the xref section in the PDF file + */ + public String toString() { + String of = Integer.toString(offset); + String ge = Integer.toString(generation); + String rs = "0000000000".substring(0, 10 - of.length()) + + of + + " " + + "00000".substring(0, 5 - ge.length()) + ge; + if (generation == 65535) { + return rs + " f "; + } + return rs + " n "; + } } // end class PDFXref - + diff --git a/libsrc/gnujpdf/src/gnu/jpdf/StringTooLongException.java b/libsrc/gnujpdf/src/gnu/jpdf/StringTooLongException.java index 4fabb6b39..0163f406c 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/StringTooLongException.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/StringTooLongException.java @@ -20,34 +20,35 @@ */ package gnu.jpdf; - /** - *

This exception is thrown from {@link gnu.jpdf.BoundingBox} if the - * string won't fit into the box

+ *

+ * This exception is thrown from {@link gnu.jpdf.BoundingBox} if the string + * won't fit into the box

* * @author Eric Z. Beard, erizbeard@hotmail.com * @version $Revision: 1.1 $ $Date: 2007/08/22 01:02:32 $ */ public class StringTooLongException extends Exception { - private String msg; + private String msg; - /** - *

Normally this exception is constructed with a message containing - * information about the sizes of the parent and child box, and maybe the - * string that caused the overflow.

- * - * @param msg a String, some informative message for the logs - */ - public StringTooLongException(String msg) { - this.msg = msg; - } + /** + *

+ * Normally this exception is constructed with a message containing + * information about the sizes of the parent and child box, and maybe the + * string that caused the overflow.

+ * + * @param msg a String, some informative message for the logs + */ + public StringTooLongException(String msg) { + this.msg = msg; + } - public String toString() { - return msg; - } + public String toString() { + return msg; + } - public String getMessage() { - return msg; - } + public String getMessage() { + return msg; + } } // end class StringTooLongException diff --git a/libsrc/gnujpdf/src/gnu/jpdf/Test.java b/libsrc/gnujpdf/src/gnu/jpdf/Test.java index ead5dbf11..ac1475d71 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/Test.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/Test.java @@ -1,6 +1,5 @@ package gnu.jpdf; - import gnu.jpdf.PDFJob; import java.awt.Graphics; import java.awt.image.BufferedImage; @@ -10,31 +9,30 @@ import java.io.File; import java.io.FileOutputStream; import javax.imageio.ImageIO; - - /** * * @author JPEXS */ public class Test { + public static void main(String[] args) throws Exception { - PDFJob job=new PDFJob(new FileOutputStream("test.pdf")); - PageFormat pf=new PageFormat(); + PDFJob job = new PDFJob(new FileOutputStream("test.pdf")); + PageFormat pf = new PageFormat(); pf.setOrientation(PageFormat.PORTRAIT); Paper p = new Paper(); - p.setSize(210,297); //A4 + p.setSize(210, 297); //A4 pf.setPaper(p); - + BufferedImage img = ImageIO.read(new File("earth.jpg")); - + int w = 200; - - for(int i=0;i<10;i++){ + + for (int i = 0; i < 10; i++) { Graphics g = job.getGraphics(); - g.drawImage(img, 0, 0,w,w, null); + g.drawImage(img, 0, 0, w, w, null); g.dispose(); } - + job.end(); } } diff --git a/libsrc/gnujpdf/src/gnu/jpdf/TtfParser.java b/libsrc/gnujpdf/src/gnu/jpdf/TtfParser.java index 0fbdee710..ec3abe9e8 100644 --- a/libsrc/gnujpdf/src/gnu/jpdf/TtfParser.java +++ b/libsrc/gnujpdf/src/gnu/jpdf/TtfParser.java @@ -60,7 +60,6 @@ public class TtfParser { private byte[] cidtogidmap = new byte[131072]; - public void loadFromTTF(File file) throws IOException, FontFormatException { RandomAccessFile input = new RandomAccessFile(file, "r"); readTableDirectory(input); @@ -171,7 +170,6 @@ public class TtfParser { return dw; } - private void readTableDirectory(RandomAccessFile input) throws IOException { skip(input, 4); int tableCount = readUnsignedShort(input);