diff --git a/.gitignore b/.gitignore
index 2bf24c098..9b40cc14a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,4 +21,5 @@
/libsrc/jsyntaxpane/jsyntaxpane/src/target/
hs_err_pid*.log
*.~*
-/revision.txt
\ No newline at end of file
+/revision.txt
+/libsrc/gnujpdf/dist/
\ No newline at end of file
diff --git a/lib/gnujpdf.jar b/lib/gnujpdf.jar
new file mode 100644
index 000000000..bc765e18c
Binary files /dev/null and b/lib/gnujpdf.jar differ
diff --git a/libsrc/gnujpdf/build.xml b/libsrc/gnujpdf/build.xml
new file mode 100644
index 000000000..129873d08
--- /dev/null
+++ b/libsrc/gnujpdf/build.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
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
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
+ * + * @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; + + /** Used to a align a String centered vertically */ + public static final int VERT_ALIGN_CENTER = 0; + + /** Used to align a String at the top of the box */ + public static final int VERT_ALIGN_TOP = 1; + + /** Used to align a String at the bottom of the box */ + public static final int VERT_ALIGN_BOTTOM = 2; + + /** 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 to the left in the box */ + public static final int HORIZ_ALIGN_LEFT = 4; + + /** 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 top portion */ + public static final int SUBTRACT_FROM_TOP = 6; + + /** 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 left portion */ + public static final int SUBTRACT_FROM_LEFT = 8; + + /** Used to subtract a child from a box, *leaving" the right portion */ + public static final int SUBTRACT_FROM_RIGHT = 9; + + private static final int[] VERT_ALIGNS = {VERT_ALIGN_CENTER, + VERT_ALIGN_TOP, + VERT_ALIGN_BOTTOM}; + + private static final int[] HORIZ_ALIGNS = {HORIZ_ALIGN_CENTER, + HORIZ_ALIGN_LEFT, + HORIZ_ALIGN_RIGHT}; + + private static final int[] SUBTRACTS = {SUBTRACT_FROM_TOP, + SUBTRACT_FROM_BOTTOM, + SUBTRACT_FROM_LEFT, + SUBTRACT_FROM_RIGHT}; + + /** The point to use for Graphics.drawString() */ + private Point drawingPoint; + + /** The absolute, world location of the box */ + private Point absoluteLocation; + + /** 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 string specified in getStringBounds */ + private String fullString; + + /** + * Creates a newBoundingBox 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();
+ }
+
+
+
+ /**
+ * Returns true if this box has a parent. The 'world', or + * enclosing canvas is not considered a parent
+ * + * @return aboolean value
+ */
+ public boolean hasParent() {
+ return parent != null;
+ }
+
+ /**
+ * Get this box's parent box
+ * + * @return aBoundingBox 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
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 aBoundingBox value
+ */
+ public void setParent(BoundingBox parent) {
+ // Prevent infinite recursion
+ if (this == parent) {
+ return;
+ }
+ 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;
+
+ 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 aString[] array of strings, top to bottom in layout
+ */
+ public String[] getStringArray() {
+ return stringArray;
+ } // end getStringArray
+
+
+
+ /**
+ * Set the value of the string array
+ * + * @param strArray aString array
+ *
+ */
+ public void setStringArray(String[] strArray) {
+ this.stringArray = strArray;
+ }
+
+
+ /**
+ * Set the absolute upper left world location point for this box
+ * + * @param point aPoint 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 aPoint value
+ */
+ public Point getAbsoluteLocation() {
+ return absoluteLocation;
+ }
+
+
+ /**
+ * Returns the full string associated with a call to
+ * getStringBounds
Sets the full string associated with getStringBounds
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 aString, 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 aString, 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}
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 theGraphics 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;
+ }
+ }
+ }
+ 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 theGraphics 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 - theString 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);
+
+
+
+ VectorRemoves 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 aBoundingBox 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 aPoint
+ */
+ public Point getDrawingPoint() {
+ return drawingPoint;
+ }
+
+
+
+
+
+ // 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...");
+
+ 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);
+ }
+ 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;
+ }
+
+
+ /**
+ * Checks the horizontal alignment passed into a + * method to make sure it is one of the valid values
+ * + * @param hAlign anint 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;
+ }
+
+
+
+ /**
+ * Checks the vertical alignment passed into a + * method to make sure it is one of the valid values
+ * + * @param vAlign anint 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;
+ }
+
+} // end class BoundingBox
+
+
+
+
diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFAnnot.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFAnnot.java
new file mode 100644
index 000000000..910bb70cd
--- /dev/null
+++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFAnnot.java
@@ -0,0 +1,272 @@
+/*
+ * $Id: PDFAnnot.java,v 1.2 2007/08/26 18:56:35 gil1 Exp $
+ *
+ * $Date: 2007/08/26 18:56:35 $
+ *
+ * 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.io.IOException;
+import java.io.OutputStream;
+import java.io.Serializable;
+
+/**
+ * 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 +{ + /* + * 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 + *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); + } +} diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFBorder.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFBorder.java new file mode 100644 index 000000000..f96e7b3cf --- /dev/null +++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFBorder.java @@ -0,0 +1,112 @@ +/* + * $Id: PDFBorder.java,v 1.2 2007/08/26 18:56:35 gil1 Exp $ + * + * $Date: 2007/08/26 18:56:35 $ + * + * 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.io.IOException; +import java.io.OutputStream; + +/** + *
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 +{ + /* + * 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.
+ *
+ * @param style The style of the border
+ * @param width The width of the border
+ * @see PDFAnnot
+ */
+ 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[]) {
+ super("/Border");
+ this.style = PDFAnnot.DASHED;
+ this.width = width;
+ this.dash = dash;
+ }
+
+ /**
+ * @param os OutputStream to send the object to
+ * @exception IOException on error
+ */
+ public void write(OutputStream os) throws IOException {
+ //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(" /W ".getBytes());
+ os.write(Double.toString(width).getBytes());
+ if(dash!=null) {
+ os.write(" /D [".getBytes());
+ os.write(Double.toString(dash[0]).getBytes());
+ for(int i=1;i
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
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 +{ + + /* + * 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 vector contains each indirect object within the document. + */ + protected VectorThis 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 VectorThis 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 VectorOnce 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; + } + + /** + * 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);
+ }
+
+ // 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/PDFFont.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFFont.java
new file mode 100644
index 000000000..73147d65d
--- /dev/null
+++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFFont.java
@@ -0,0 +1,250 @@
+/*
+ * $Id: PDFFont.java,v 1.3 2007/08/26 19:00:11 gil1 Exp $
+ *
+ * $Date: 2007/08/26 19:00:11 $
+ *
+ * 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.Font;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Serializable;
+
+/**
+ * This class defines a font within a PDF document.
+ *
+ * @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.3 $, $Date: 2007/08/26 19:00:11 $
+ */
+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
+// 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 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. 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. 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) {
// double nx = x, ny = y; // scratch
// double mh = page.getPageFormat().getHeight();
Point2D ptSrc = new Point2D.Double(x, y);
Point2D ptDst = new Point2D.Double();
transform.transform(ptSrc, ptDst);
// x += trax;
// y += tray;
//
// nx = x;
// ny = mh - y;
//
// System.out.println("\ncxy(" + ptSrc.getX() + ", " + ptSrc.getY() + ")");
// System.out.println("Old [" + nx + "," + ny + "]");
// System.out.println("Trn [" + ptDst.getX() + ", " + ptDst.getY() + "]");
//
// return "" + df.format(nx) + " " + df.format(ny) + " ";
return ""+df.format(ptDst.getX())+" "+df.format(ptDst.getY())+" ";
}
/**
* 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. 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.
* Not implemented Draw's an image onto the page, with a backing colour. Draw's an image onto the page, with a backing colour. 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 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 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 drawString(String s,float x,float y) {
newTextBlock(x, y);
pw.println(PDFStringHelper.makePDFString(s)+" Tj");
}
/**
* This draws a string.
*
* @oaran s String to draw
* @param x coordinate
* @param y coordinate
*/
public void drawString(String s,int x,int y) {
newTextBlock(x,y);
pw.println(PDFStringHelper.makePDFString(s)+" Tj");
}
/**
* @see Graphics2D#fill(Shape)
*/
public void fill(Shape s) {
followPath(s, FILL);
}
/**
* Not implemented Draws a filled oval 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 originalStroke;
}
/**
* @see Graphics2D#getTransform()
*/
public AffineTransform getTransform() {
return new AffineTransform(oTransform);
}
/**
* Returns the PrintWriter handling the underlying stream
* @return the PrintWriter handling the underlying stream
*/
public PrintWriter getWriter() {
return pw;
}
/**
* @see Graphics2D#hit(Rectangle, Shape, boolean)
*/
public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
if (onStroke) {
s = stroke.createStrokedShape(s);
}
s = transform.createTransformedShape(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)
oTransform = new AffineTransform();
// Transform from Java Space to PDF Space
pTransform = new AffineTransform();
pTransform.translate(0, pf.getHeight());
pTransform.scale(1d, -1d);
// Combined Transform User->Java->PDF
transform = new AffineTransform(oTransform);
transform.concatenate(pTransform);
// 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 = stream.getWriter();
// 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,PrintWriter 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. This implements the Image XObject. Calling one of the
+ * 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 Compression needs to be improved here Converts a pixel to a hex string This class stores details of the author, the PDF generator etc.
+ * The values are accessible via the PDFDocument class. 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. 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 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. 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" 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 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 writes the PDF document to the OutputStream, finishing the
+ * document. 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 Returns the page dimension How about a setPageDimension(Rectangle media) ?? This is the PDF (and Postscript) device resolution of 72 dpi
+ * (equivalent to 1 point). 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. Returns the current PDFPage being worked on. Useful for working on
+ * Annotations (like links), etc. Returns the current page number.
+ * Useful if you need to include one in the document 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 specified region. 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. 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
new file mode 100644
index 000000000..e2b0e6a47
--- /dev/null
+++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFObject.java
@@ -0,0 +1,177 @@
+/*
+ *
+ * $Id: PDFObject.java,v 1.3 2007/09/22 12:48:16 gil1 Exp $
+ *
+ * $Date: 2007/09/22 12:48:16 $
+ *
+ * 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.io.*;
+import java.util.*;
+
+/**
+ * This is the base class for all Objects that form the PDF document.
+ *
+ * @author Peter T Mount, http://www.retep.org.uk/pdf/
+ * @author Eric Z. Beard, ericzbeard@hotmail.com
+ * @version $Revision: 1.3 $, $Date: 2007/09/22 12:48:16 $
+ */
+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 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. 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 extends PDFObject> 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();
+ }
+}
diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFOutline.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFOutline.java
new file mode 100644
index 000000000..e68f558fc
--- /dev/null
+++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFOutline.java
@@ -0,0 +1,340 @@
+/*
+ * $Id: PDFOutline.java,v 1.3 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.io.*;
+import java.util.*;
+
+/**
+ * This class manages the documents outlines (also known as bookmarks).
+ *
+ * @author Peter T Mount http://www.retep.org.uk/pdf/
+ * @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
+{
+
+ /*
+ * 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 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
+ */
+ 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.
+ *
+ * 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.
+ *
+ * @param title Title of the outline
+ * @param dest The destination page
+ * @param x coordinate of region in Java space
+ * @param y coordinate of region in Java space
+ * @param w width of region in Java space
+ * @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]);
+ 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.
+ *
+ * @param outline PDFOutline to add
+ */
+ 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
+ {
+ // Write the object header
+ writeStart(os);
+
+ // now the objects body
+
+ // These are for kids only
+ 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) {
+ //os.write(" null null null]\n/Parent ".getBytes());
+ os.write(" /Fit]\n/Parent ".getBytes());
+ } else {
+ os.write(" /FitR ".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/Parent ".getBytes());
+ }
+ os.write(parent.toString().getBytes());
+ os.write("\n".getBytes());
+ }
+
+ // the number of outlines in this document
+ if(parent==null) {
+ // were the top level node, so all are open by default
+ os.write("/Count ".getBytes());
+ os.write(Integer.toString(outlines.size()).getBytes());
+ os.write("\n".getBytes());
+ } else {
+ // were a decendent, so by default we are closed. Find out how many
+ // entries are below us
+ int c = descendants();
+ 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) {
+ // 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("\n".getBytes());
+ }
+
+ if(parent!=null) {
+ int index = parent.getIndex(this);
+ 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("\n".getBytes());
+ }
+ if(index 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 This class defines a single page within a document. It is linked to a
+ * single PDFGraphics object 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.
+ */
+ public PDFPage()
+ {
+ super("/Page");
+ pageFormat = DEF_FORMAT;
+ contents = new Vector Normally, this should be done when the page is created, to avoid
+ * problems.
+ *
+ * @param orientation a PageFormat orientation constant:
+ * PageFormat.PORTRAIT, PageFormat.LANDSACPE or PageFromat.REVERSE_LANDSACPE
+ */
+ public void setOrientation(int 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
+ */
+ public int getOrientation() {
+ return pageFormat.getOrientation();
+ }
+
+ /**
+ * This adds an object that describes some content to this page.
+ *
+ * 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
+ */
+ public void add(PDFObject ob) {
+ contents.addElement(ob);
+ }
+
+ /**
+ * 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.
+ *
+ * @param ob Annotation to add.
+ */
+ public void addAnnotation(PDFObject ob) {
+ annotations.addElement(ob);
+ }
+
+ /**
+ * 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
+ * @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) {
+ 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;
+ }
+
+ /**
+ * 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
+ * @param h Height of the active area
+ * @param dest Page that will be displayed when the link is activated. When
+ * 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
+ );
+ pdfDocument.add(ob);
+ annotations.addElement(ob);
+ return ob;
+ }
+
+ /**
+ * 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
+ * @param h Height of the active area
+ * @param dest Page that will be displayed when the link is activated
+ * @param vx Coordinate of view area
+ * @param vy Coordinate of view area
+ * @param vw Width of the view area
+ * @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]
+ );
+ pdfDocument.add(ob);
+ annotations.addElement(ob);
+ return ob;
+ }
+
+ /** Contains the text strings for the xobjects. */
+ private Vector 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)
+ {
+ 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);
+ 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.
+ *
+ * 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
+ * @param y Bottom coordinate of region
+ * @param w Width of region
+ * @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]);
+ pdfDocument.add(outline);
+ pdfDocument.getOutline().add(outline);
+ return 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
+
+ // the /Parent pages object
+ os.write("/Parent ".getBytes());
+ os.write(pdfPageList.toString().getBytes());
+ os.write("\n".getBytes());
+
+ // the /MediaBox for the page size
+ os.write("/MediaBox [".getBytes());
+ os.write(Integer.toString(0).getBytes());
+ os.write(" ".getBytes());
+ os.write(Integer.toString(0).getBytes());
+ os.write(" ".getBytes());
+ os.write(Integer.toString((int)pageFormat.getWidth()).getBytes());
+ os.write(" ".getBytes());
+ os.write(Integer.toString((int)pageFormat.getHeight()).getBytes());
+ os.write("]\n".getBytes());
+
+ // Rotation (if not zero)
+// if(rotate!=0) {
+// os.write("/Rotate ".getBytes());
+// 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());
+ os.write("\n/Font << ".getBytes());
+ for(PDFFont font : fonts) {
+ os.write(font.getName().getBytes());
+ os.write(" ".getBytes());
+ os.write(font.toString().getBytes());
+ os.write(" ".getBytes());
+ }
+ os.write(">> ".getBytes());
+ }
+ // Now the XObjects
+ if (xobjects.size() > 0){
+ os.write("\n/XObject << ".getBytes());
+ for(String str : xobjects) {
+ os.write(str.getBytes());
+ os.write(" ".getBytes());
+ }
+ os.write(">> ".getBytes());
+ }
+ // Any other 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());
+ }
+ os.write(">>\n".getBytes());
+
+ // The thumbnail
+ 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);
+ os.write("/Contents ".getBytes());
+ os.write(ob.toString().getBytes());
+ os.write("\n".getBytes());
+ } else {
+ os.write("/Contents [".getBytes());
+ os.write(PDFObject.toArray(contents).getBytes());
+ os.write("\n".getBytes());
+ }
+ }
+
+ // The /Annots object
+ if(annotations.size()>0) {
+ os.write("/Annots ".getBytes());
+ os.write(PDFObject.toArray(annotations).getBytes());
+ os.write("\n".getBytes());
+ }
+
+ // finish off with its footer
+ writeEnd(os);
+ }
+
+ /**
+ * This creates a procset and sets up the page to reference it
+ */
+ private void addProcset() {
+ if(procset==null) {
+ pdfDocument.add(procset = new procset());
+ resources.addElement("/ProcSet "+procset);
+ }
+ }
+
+ /**
+ * This defines a procset
+ */
+ public class procset extends PDFObject {
+ private Vector
+ * 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.
+ * 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
+{
+
+
+ /*
+ * 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.
+ */
+ 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.
+ * @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.
+ 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;
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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
+ */
+ public void write(OutputStream os) throws IOException {
+ writeStart(os);
+ writeStream(os);
+ // 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 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) {
+ 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("\n>>\nstream\n".getBytes());
+ b.writeTo(os);
+ os.write("\n".getBytes());
+ } else {
+ // This is a non-deflated stream
+ os.write("/Length ".getBytes());
+ os.write(Integer.toString(buf.size()).getBytes());
+ 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?
+
+
+ /**
+ * 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).
+ *
+ */
+ 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).
+ *
+ */
+ 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);
+ buf.write(b);
+ }
+
+}
diff --git a/libsrc/gnujpdf/src/gnu/jpdf/PDFStringHelper.java b/libsrc/gnujpdf/src/gnu/jpdf/PDFStringHelper.java
new file mode 100644
index 000000000..4c33df9cd
--- /dev/null
+++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFStringHelper.java
@@ -0,0 +1,79 @@
+/*
+ * $Id: PDFStringHelper.java,v 1.2 2007/08/26 18:56:35 gil1 Exp $
+ *
+ * $Date: 2007/08/26 18:56:35 $
+ *
+ * Copyright (C) 2001 Eric Z. Beard, ericzbeard@hotmail.com
+ *
+ *
+ * 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;
+
+/**
+ * String manipulation methods
+ *
+ * @author Eric Z. Beard, ericzbeard@hotmail.com
+ * @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+")";
+ }
+
+ /**
+ * 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 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 This exception is thrown from {@link gnu.jpdf.BoundingBox} if the
+ * string won't fit into the box 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.PrintWriter to attach to.
*/
protected PDFGraphics createGraphic(PDFPage page,
PrintWriter 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.
* 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);
}
/**
* 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;
}
/**
* 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.
/**
* 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.PDFImage instance.
+ *
+ */
+ public PDFImage()
+ {
+ super("/XObject");
+ }
+
+ /**
+ * Creates a new PDFImage instance.
+ *
+ * @param img an Image value
+ */
+ public PDFImage(Image img) {
+ this();
+ setImage(img,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,ImageObserver obs) {
+ this();
+ setImage(img, 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 w,int h,ImageObserver obs) {
+ this.img = img;
+ width = w;
+ height = h;
+ }
+
+
+
+ /**
+ * 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";
+ }
+ VectorOutputStream 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());
+ os.write("\n/Filter /ASCII85Decode".getBytes());
+ 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();
+
+ // 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
+
+
+ /**
+ * 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;
+
+ //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
new file mode 100644
index 000000000..fb216295b
--- /dev/null
+++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFInfo.java
@@ -0,0 +1,193 @@
+/*
+ * $Id: PDFInfo.java,v 1.2 2007/08/26 18:56:35 gil1 Exp $
+ *
+ * $Date: 2007/08/26 18:56:35 $
+ *
+ *
+ * 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.io.*;
+
+/**
+ * OutputStream to use for the pdf output
+ */
+ public PDFJob(OutputStream os) {
+ this(os, "PDF Doc");
+ }
+
+ /**
+ * 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);
+ }
+
+
+ /**
+ * 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);
+ }
+
+
+ /**
+ * Graphics object to draw to.
+ */
+ public Graphics getGraphics() {
+ return getGraphics(PageFormat.PORTRAIT);
+ }
+
+
+
+ /**
+ * Dimension instance, the size of the page
+ */
+ public Dimension getPageDimension() {
+ if (page == null) {
+ System.err.println("PDFJob.getPageDimension(), page is null");
+ }
+ return page.getDimension();
+ }
+
+
+ /**
+ * int, the resolution in pixels per inch
+ */
+ public int getPageResolution() {
+ return 72;
+ }
+
+
+
+
+ /**
+ * PDFPage currently being constructed
+ */
+ public PDFPage getCurrentPage() {
+ return page;
+ }
+
+ /**
+ * int current page number
+ */
+ public int getCurrentPageNumber() {
+ return pagenum;
+ }
+
+
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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);
+ }
+
+
+ /**
+ * 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 PageFormat defaultPage(PageFormat page) {
+ return validatePage(page);
+ }
+
+ @Override
+ public int getCopies() {
+ return ((IntegerSyntax) attributes.get(Copies.class)).getValue();
+ }
+
+ @Override
+ public String getJobName() {
+ return ((TextSyntax) attributes.get(JobName.class)).getValue();
+ }
+
+ public static PrinterJob getPrinterJob() {
+ return new PDFPrinterJob();
+ }
+
+ @Override
+ public String getUserName() {
+ return ((TextSyntax) attributes.get(RequestingUserName.class))
+ .getValue();
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
+ }
+
+ @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;
+
+ 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);
+
+ if (info != null) {
+ printJob.getPDFDocument().setPDFInfo(info);
+ }
+
+ 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();
+ }
+
+ printJob.end();
+
+ }
+
+ @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);
+ }
+
+ // 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");
+
+ // Dialog to get file name...
+ fileChooser.setSelectedFile(file);
+
+ // Print
+ if (fileChooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
+ file = fileChooser.getSelectedFile();
+ print(file.getAbsolutePath());
+ }
+ }
+
+ @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 creator for this document.
+ *
+ * @param creator the application name.
+ */
+ public void setCreator(String creator) {
+ info.setCreator(creator);
+ }
+
+ @Override
+ public void setJobName(String jobName) {
+ attributes.add(new JobName(jobName, Locale.getDefault()));
+
+ if (info.getTitle() == null) {
+ info.setTitle(jobName);
+ }
+ }
+
+ @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) {
+ this.printable = painter;
+ }
+
+ @Override
+ public void setPrintable(Printable painter, PageFormat format) {
+ this.printable = painter;
+ this.pageFormat = format;
+ }
+
+ /**
+ * 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
new file mode 100644
index 000000000..7702d5574
--- /dev/null
+++ b/libsrc/gnujpdf/src/gnu/jpdf/PDFStream.java
@@ -0,0 +1,218 @@
+/*
+ * $Id: PDFStream.java,v 1.2 2007/08/26 18:56:35 gil1 Exp $
+ *
+ * $Date: 2007/08/26 18:56:35 $
+ *
+ * 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.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+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.
+ *
+ * String, some informative message for the logs
+ */
+ public StringTooLongException(String msg) {
+ this.msg = msg;
+ }
+
+ public String toString() {
+ 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
new file mode 100644
index 000000000..ce45fd9fe
--- /dev/null
+++ b/libsrc/gnujpdf/src/gnu/jpdf/Test.java
@@ -0,0 +1,40 @@
+package gnu.jpdf;
+
+
+import gnu.jpdf.PDFJob;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+import java.awt.print.PageFormat;
+import java.awt.print.Paper;
+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();
+ pf.setOrientation(PageFormat.PORTRAIT);
+ Paper p = new Paper();
+ 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++){
+ Graphics g = job.getGraphics();
+ g.drawImage(img, 0, 0,w,w, null);
+ g.dispose();
+ }
+
+ job.end();
+ }
+}
diff --git a/nbproject/project.xml b/nbproject/project.xml
index b6652643b..c0b1e84ff 100644
--- a/nbproject/project.xml
+++ b/nbproject/project.xml
@@ -156,7 +156,7 @@