0001: /*
0002: * $Id: PDFGraphics.java,v 1.2 2001/11/16 15:26:04 ezb Exp $
0003: *
0004: * $Date: 2001/11/16 15:26:04 $
0005: *
0006: *
0007: * This library is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU Lesser General Public
0009: * License as published by the Free Software Foundation; either
0010: * version 2.1 of the License, or (at your option) any later version.
0011: *
0012: * This library is distributed in the hope that it will be useful,
0013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0015: * Lesser General Public License for more details.
0016: *
0017: * You should have received a copy of the GNU Lesser General Public
0018: * License along with this library; if not, write to the Free Software
0019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0020: */
0021: package gnu.jpdf;
0022:
0023: import java.awt.*;
0024: import java.awt.image.*;
0025: import java.io.*;
0026: import java.util.*;
0027:
0028: /**
0029: * This class is our implementation of AWT's Graphics class. It provides a
0030: * Java standard way of rendering into a PDF Document's Page.
0031: *
0032: * @author Peter T Mount, http://www.retep.org.uk/pdf/
0033: * @author Eric Z. Beard, ericzbeard@hotmail.com
0034: * @author $Author: ezb $
0035: * @version $Revision: 1.2 $, $Date: 2001/11/16 15:26:04 $
0036: * @see gnu.jpdf.PDFGraphics
0037: */
0038: public class PDFGraphics extends Graphics implements Serializable {
0039:
0040: /*
0041: * NOTE: The original class is the work of Peter T. Mount, who released it
0042: * in the uk.org.retep.pdf package. It was modified by Eric Z. Beard as
0043: * follows:
0044: * The package name was changed to gnu.pdf.
0045: * The formatting was changed a little bit.
0046: * This used to subclass an abstract class in a different package with
0047: * the same name (confusing). Now it's one concrete class.
0048: * drawImage() was implemented
0049: * It is still licensed under the LGPL.
0050: */
0051:
0052: // Implementation notes:
0053: //
0054: // Pages 333-335 of the PDF Reference Manual
0055: //
0056: // Unless absolutely required, use the moveto, lineto and rectangle
0057: // operators to perform those actions.
0058: // They contain some extra optimisations
0059: // which will reduce the output size by up to half in some cases.
0060: //
0061: // About fill operators: For correct operation, any fill operation should
0062: // start with closeBlock(), which will ensure any previous path is completed,
0063: // otherwise you may find the fill will include previous items
0064: /**
0065: * This is the media we are working with
0066: */
0067: protected Rectangle media;
0068:
0069: /**
0070: * The media's rotation, either 0,90,180 or 270.
0071: */
0072: private int mediaRot;
0073:
0074: /**
0075: * This is used to translate coordinates
0076: */
0077: protected int trax;
0078:
0079: /**
0080: * This is used to translate coordinates
0081: */
0082: protected int tray;
0083:
0084: /**
0085: * Part of the optimiser:
0086: * This is written to the stream when the newPath() is called. np then clears
0087: * this value.
0088: */
0089: private String pre_np;
0090:
0091: /**
0092: * Part of the optimiser:
0093: * When true, we are drawing a path.
0094: */
0095: private boolean inStroke;
0096:
0097: /**
0098: * Part of the optimiser:
0099: * The last known moveto/lineto x coordinate
0100: * @see #moveto
0101: * @see #lineto
0102: */
0103: private int lx; // last known moveto/lineto coords
0104:
0105: /**
0106: * Part of the optimiser:
0107: * The last known moveto/lineto y coordinate
0108: * @see #moveto
0109: * @see #lineto
0110: */
0111: private int ly; // last known moveto/lineto coords
0112:
0113: /**
0114: * Part of the optimiser:
0115: * When true, we are within a Text Block.
0116: */
0117: private boolean inText; // true if within a Text Block - see newTextBlock()
0118:
0119: /**
0120: * Part of the optimiser:
0121: * When true, the font has changed.
0122: */
0123: private boolean newFont; // true if the font changes - see newTextBlock()
0124:
0125: /**
0126: * Part of the optimiser:
0127: * The last x coordinate when rendering text
0128: */
0129: private int tx; // the last coordinate for text rendering
0130:
0131: /**
0132: * Part of the optimiser:
0133: * The last y coordinate when rendering text
0134: */
0135: private int ty; // the last coordinate for text rendering
0136:
0137: /**
0138: * This is the current pen/fill color
0139: */
0140: private Color color;
0141:
0142: /**
0143: * This is the current font (in PDF format)
0144: */
0145: private PDFFont pdffont;
0146:
0147: /**
0148: * This is the current font (in Java format)
0149: */
0150: private Font font;
0151:
0152: /**
0153: * This is the PrintWriter used to write PDF drawing commands to the Stream
0154: */
0155: private PrintWriter pw;
0156:
0157: /**
0158: * This is a reference to the PDFPage we are rendering to.
0159: */
0160: private PDFPage page;
0161:
0162: /**
0163: * This is true for any Graphics instance that didn't create the stream.
0164: * @see #create
0165: */
0166: private boolean child;
0167:
0168: /**
0169: * This method creates a new instance of the class based on the page
0170: * and a print writer.
0171: *
0172: * @param page the page to attach to
0173: * @param pw the <code>PrintWriter</code> to attach to.
0174: */
0175: protected PDFGraphics createGraphic(PDFPage page, PrintWriter pw) {
0176: PDFGraphics g = new PDFGraphics();
0177: g.init(page, pw);
0178: return g;
0179: }
0180:
0181: /**
0182: * This is called by PDFPage when creating a Graphcis instance.
0183: * @param page The PDFPage to draw onto.
0184: */
0185: protected void init(PDFPage page) {
0186: this .page = page;
0187:
0188: // We are the parent instance
0189: child = false;
0190:
0191: // Now create a stream to store the graphics in
0192: PDFStream stream = new PDFStream();
0193: page.getPDFDocument().add(stream);
0194: page.add(stream);
0195: pw = stream.getWriter();
0196:
0197: // initially, we are limited to the page size
0198: clipRectangle = new Rectangle(page.getMedia());
0199:
0200: // finally initialise the stream
0201: init();
0202: }
0203:
0204: /**
0205: * This method is used internally by create() and by the PDFJob class
0206: * @param page PDFPage to draw into
0207: * @param pw PrintWriter to use
0208: */
0209: protected void init(PDFPage page, PrintWriter pw) {
0210: this .page = page;
0211: this .pw = pw;
0212:
0213: // In this case, we didn't create the stream (our parent did)
0214: // so child is true (see dispose)
0215: child = true;
0216:
0217: // finally initialise the stream
0218: init();
0219: }
0220:
0221: /**
0222: * This initialises the stream by saving the current graphics state, and
0223: * setting up the default line width (for us).
0224: *
0225: * It also sets up the instance ready for graphic operations and any
0226: * optimisations.
0227: *
0228: * <p>For child instances, the stream is already open, so this should keep
0229: * things happy.
0230: */
0231: private void init() {
0232: // save graphics state (restored by dispose)
0233: if (child) {
0234: pw.print("q ");
0235: }
0236:
0237: // Set the line width
0238: setDefaultLineWidth();
0239:
0240: // now initialise the instance
0241: //setColor(Color.black);
0242: color = Color.black;
0243: // possible: if parent.color is not black, then force black?
0244: // must check to see what AWT does?
0245:
0246: // get the page dimensions (needed to get the orientation correct)
0247: media = page.getMedia();
0248: mediaRot = page.getOrientation();
0249:
0250: // Finally set the page Orientation
0251: if (!child) {
0252: setOrientation();
0253: }
0254: }
0255:
0256: /**
0257: * Returns the PrintWriter handling the underlying stream
0258: * @return the PrintWriter handling the underlying stream
0259: */
0260: public PrintWriter getWriter() {
0261: return pw;
0262: }
0263:
0264: /**
0265: * Returns the associated PDFPage for this graphic
0266: * @return the associated PDFPage for this graphic
0267: */
0268: public PDFPage getPage() {
0269: return page;
0270: }
0271:
0272: /**
0273: * <p>This returns a child instance of this Graphics object. As with AWT, the
0274: * affects of using the parent instance while the child exists, is not
0275: * determined.</p>
0276: *
0277: * <p>Once complete, the child should be released with it's dispose()
0278: * method which will restore the graphics state to it's parent.</p>
0279: *
0280: * @return Graphics object to render onto the page
0281: */
0282: public Graphics create() {
0283: closeBlock();
0284:
0285: PDFGraphics g = createGraphic(page, pw);
0286:
0287: // The new instance inherits a few items
0288: g.media = new Rectangle(media);
0289: g.trax = trax;
0290: g.tray = tray;
0291: g.clipRectangle = new Rectangle(clipRectangle);
0292:
0293: return (Graphics) g;
0294: } // end create()
0295:
0296: /**
0297: * <p>This releases any resources used by this Graphics object. You must use
0298: * this method once finished with it. Leaving it open will leave the PDF
0299: * stream in an inconsistent state, and will produce errors.</p>
0300: *
0301: * <p>If this was created with Graphics.create() then the parent instance
0302: * can be used again. If not, then this closes the graphics operations for
0303: * this page when used with PDFJob.</p>
0304: *
0305: * <p>When using PDFPage, you can create another fresh Graphics instance,
0306: * which will draw over this one.</p>
0307: *
0308: */
0309: public void dispose() {
0310: closeBlock();
0311: if (child) {
0312: pw.println("Q"); // restore graphics context
0313: } else {
0314: pw.close(); // close the stream if were the parent
0315: }
0316: }
0317:
0318: // *********************************************
0319: // **** Implementation of java.awt.Graphics ****
0320: // *********************************************
0321:
0322: //============ Rectangle operations =======================
0323:
0324: /**
0325: * This simply draws a White Rectangle to clear the area
0326: * @param x coord
0327: * @param y coord
0328: * @param w width
0329: * @param h height
0330: */
0331: public void clearRect(int x, int y, int w, int h) {
0332: closeBlock();
0333: pw.print("q 1 1 1 RG ");// save state, set colour to White
0334: drawRect(x, y, w, h);
0335: closeBlock("B Q"); // close fill & stroke, then restore state
0336: }
0337:
0338: /**
0339: * We override Graphics.drawRect as it doesn't join the 4 lines.
0340: * Also, PDF provides us with a Rectangle operator, so we will use that.
0341: * @param x coord
0342: * @param y coord
0343: * @param w width
0344: * @param h height
0345: */
0346: public void drawRect(int x, int y, int w, int h) {
0347: newPath();
0348: pw.print(cxy(x, y) + cwh(w, h) + "re "); // rectangle
0349: lx = x; // I don't know if this is correct, but lets see if PDF ends
0350: ly = y; // the rectangle at it's start.
0351: // stroke (optimised)
0352: }
0353:
0354: /**
0355: * <p>Not implemented</p>
0356: *
0357: * <p>Draws a 3-D highlighted outline of the specified rectangle.
0358: * The edges of the rectangle are highlighted so that they appear
0359: * to be beveled and lit from the upper left corner.
0360: * The colors used for the highlighting effect are determined based on
0361: * the current color. The resulting rectangle covers an area that
0362: * is width + 1 pixels wide by height + 1 pixels tall.
0363: *</p>
0364: *
0365: * @param x an <code>int</code> value
0366: * @param y an <code>int</code> value
0367: * @param width an <code>int</code> value
0368: * @param height an <code>int</code> value
0369: * @param raised a <code>boolean</code> value
0370: */
0371: public void draw3DRect(int x, int y, int width, int height,
0372: boolean raised) {
0373: // Not implemented
0374: }
0375:
0376: /**
0377: * <p>Not implemented</p>
0378: *
0379: * @param x an <code>int</code> value
0380: * @param y an <code>int</code> value
0381: * @param width an <code>int</code> value
0382: * @param height an <code>int</code> value
0383: * @param raised a <code>boolean</code> value
0384: */
0385: public void fill3DRect(int x, int y, int width, int height,
0386: boolean raised) {
0387: // Not implemented
0388: }
0389:
0390: /**
0391: * Fills a rectangle with the current colour
0392: *
0393: * @param x coord
0394: * @param y coord
0395: * @param w width
0396: * @param h height
0397: */
0398: public void fillRect(int x, int y, int w, int h) {
0399: // end any path & stroke. This ensures the fill is on this
0400: // rectangle, and not on any previous graphics
0401: closeBlock();
0402: drawRect(x, y, w, h);
0403: closeBlock("B"); // rectangle, fill stroke
0404: }
0405:
0406: //============ Round Rectangle operations =======================
0407:
0408: /**
0409: * This is not yet implemented
0410: *
0411: * @param x coord
0412: * @param y coord
0413: * @param w width
0414: * @param h height
0415: * @param aw a-width
0416: * @param ah a-height
0417: */
0418: public void fillRoundRect(int x, int y, int w, int h, int aw, int ah) {
0419: }
0420:
0421: /**
0422: * This is not yet implemented
0423: *
0424: * @param x coord
0425: * @param y coord
0426: * @param w width
0427: * @param h height
0428: * @param aw a-width
0429: * @param ah a-height
0430: */
0431: public void drawRoundRect(int x, int y, int w, int h, int aw, int ah) {
0432: }
0433:
0434: //============ Oval operations =======================
0435:
0436: /**
0437: * <p>Draws an oval</p>
0438: *
0439: * @param x coord
0440: * @param y coord
0441: * @param w width
0442: * @param h height
0443: */
0444: public void drawOval(int x, int y, int w, int h) {
0445: drawArc(x, y, w, h, 0, 360);
0446: }
0447:
0448: /**
0449: * <p>Draws a filled oval</p>
0450: *
0451: * @param x coord
0452: * @param y coord
0453: * @param w width
0454: * @param h height
0455: */
0456: public void fillOval(int x, int y, int w, int h) {
0457: fillArc(x, y, w, h, 0, 360);
0458: }
0459:
0460: //============ Polygon operations =======================
0461:
0462: /**
0463: * Draws a polygon, linking the first and last coordinates.
0464: * @param xp Array of x coordinates
0465: * @param yp Array of y coordinates
0466: * @param np number of points in polygon
0467: */
0468: public void drawPolygon(int[] xp, int[] yp, int np) {
0469: polygon(xp, yp, np);
0470: closeBlock("s"); // closepath and stroke
0471: }
0472:
0473: /**
0474: * Draws a polyline. The first and last coordinates are not linked.
0475: * @param xp Array of x coordinates
0476: * @param yp Array of y coordinates
0477: * @param np number of points in polyline
0478: */
0479: public void drawPolyline(int[] xp, int[] yp, int np) {
0480: polygon(xp, yp, np);
0481: // no stroke, as we keep the optimiser in stroke state
0482: }
0483:
0484: /**
0485: * Fills a polygon.
0486: * @param xp Array of x coordinates
0487: * @param yp Array of y coordinates
0488: * @param np number of points in polygon
0489: */
0490: public void fillPolygon(int[] xp, int[] yp, int np) {
0491: closeBlock(); // finish off any previous paths
0492: polygon(xp, yp, np);
0493: closeBlock("b"); // closepath, fill and stroke
0494: }
0495:
0496: //============ Image operations =======================
0497:
0498: /**
0499: * Draw's an image onto the page
0500: * @param img The java.awt.Image
0501: * @param x coordinate on page
0502: * @param y coordinate on page
0503: * @param obs ImageObserver
0504: * @return true if drawn
0505: */
0506: public boolean drawImage(Image img, int x, int y, ImageObserver obs) {
0507: return drawImage(img, x, y, img.getWidth(obs), img
0508: .getHeight(obs), obs);
0509: }
0510:
0511: /**
0512: * <p>Draws an image onto the page.</p>
0513: *
0514: * <p>This method is implemented with ASCIIbase85 encoding and the
0515: * zip stream deflater. It results in a stream that is anywhere
0516: * from 3 to 10 times as big as the image. This obviusly needs some
0517: * improvement, but it works well for small images</p>
0518: *
0519: * @param img The java.awt.Image
0520: * @param x coordinate on page
0521: * @param y coordinate on page
0522: * @param w Width on page
0523: * @param h height on page
0524: * @param obs ImageObserver
0525: * @return true if drawn
0526: */
0527: public boolean drawImage(Image img, int x, int y, int w, int h,
0528: ImageObserver obs) {
0529: closeBlock();
0530: PDFImage image = new PDFImage(img, x, y, w, h, obs);
0531: // The image needs to be registered in several places
0532: page.getPDFDocument().setImageName(image);
0533: page.getPDFDocument().add(image);
0534: page.addToProcset("/ImageC");
0535: page.addResource("/XObject << " + image.getName() + " "
0536: + image.getSerialID() + " 0 R >>");
0537: // q w 0 0 h x y cm % the coordinate matrix
0538: pw.print("q "
0539: + image.getWidth()
0540: + " 0 0 "
0541: + image.getHeight()
0542: + " "
0543: + x
0544: + " "
0545: + ((int) page.getDimension().getHeight() - y - image
0546: .getHeight()) + " cm \n" + image.getName()
0547: + " Do\nQ\n");
0548: return false;
0549: }
0550:
0551: /**
0552: * <p>Draw's an image onto the page, with a backing colour.</p>
0553: *
0554: * @param img The java.awt.Image
0555: * @param x coordinate on page
0556: * @param y coordinate on page
0557: * @param bgcolor Background colour
0558: * @param obs ImageObserver
0559: * @return true if drawn
0560: */
0561: public boolean drawImage(Image img, int x, int y, Color bgcolor,
0562: ImageObserver obs) {
0563: return drawImage(img, x, y, img.getWidth(obs), img
0564: .getHeight(obs), bgcolor, obs);
0565: }
0566:
0567: /**
0568: * <p>Draw's an image onto the page, with a backing colour.</p>
0569: *
0570: * @param img The java.awt.Image
0571: * @param x coordinate on page
0572: * @param y coordinate on page
0573: * @param w Width on page
0574: * @param h height on page
0575: * @param bgcolor Background colour
0576: * @param obs ImageObserver
0577: * @return true if drawn
0578: */
0579: public boolean drawImage(Image img, int x, int y, int w, int h,
0580: Color bgcolor, ImageObserver obs) {
0581: closeBlock();
0582: pw.print("q "); // save state
0583: Color c = color; // save current colour
0584: setColor(bgcolor); // change the colour
0585: drawRect(x, y, w, h);
0586: closeBlock("B Q"); // fill stroke, restore state
0587: color = c; // restore original colour
0588: return drawImage(img, x, y, img.getWidth(obs), img
0589: .getHeight(obs), obs);
0590: }
0591:
0592: /**
0593: * Draw's an image onto the page, with scaling
0594: * <p>This is not yet supported.
0595: *
0596: * @param img The java.awt.Image
0597: * @param dx1 coordinate on page
0598: * @param dy1 coordinate on page
0599: * @param dx2 coordinate on page
0600: * @param dy2 coordinate on page
0601: * @param sx1 coordinate on image
0602: * @param sy1 coordinate on image
0603: * @param sx2 coordinate on image
0604: * @param sy2 coordinate on image
0605: * @param obs ImageObserver
0606: * @return true if drawn
0607: */
0608: public boolean drawImage(Image img, int dx1, int dy1, int dx2,
0609: int dy2, int sx1, int sy1, int sx2, int sy2,
0610: ImageObserver obs) {
0611: // This shouldn't be too bad, just change the coordinate matrix
0612: return false;
0613: }
0614:
0615: /**
0616: * Draw's an image onto the page, with scaling
0617: * <p>This is not yet supported.
0618: *
0619: * @param img The java.awt.Image
0620: * @param dx1 coordinate on page
0621: * @param dy1 coordinate on page
0622: * @param dx2 coordinate on page
0623: * @param dy2 coordinate on page
0624: * @param sx1 coordinate on image
0625: * @param sy1 coordinate on image
0626: * @param sx2 coordinate on image
0627: * @param sy2 coordinate on image
0628: * @param bgcolor Background colour
0629: * @param obs ImageObserver
0630: * @return true if drawn
0631: */
0632: public boolean drawImage(Image img, int dx1, int dy1, int dx2,
0633: int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor,
0634: ImageObserver obs) {
0635: return false;
0636: }
0637:
0638: //============ Clipping operations =======================
0639:
0640: /**
0641: * This holds the current clipRectangle
0642: */
0643: protected Rectangle clipRectangle;
0644:
0645: /**
0646: * Clips to a set of coordinates
0647: * @param x coord
0648: * @param y coord
0649: * @param w width
0650: * @param h height
0651: */
0652: public void clipRect(int x, int y, int w, int h) {
0653: setClip(x, y, w, h);
0654: }
0655:
0656: /**
0657: * Clips to a set of coordinates
0658: * @param x coord
0659: * @param y coord
0660: * @param w width
0661: * @param h height
0662: */
0663: public void setClip(int x, int y, int w, int h) {
0664: clipRectangle = new Rectangle(x, y, w, h);
0665: closeBlock(); // finish off any existing paths
0666: drawRect(x, y, w, h);
0667: closeBlock("W n"); // clip to current path
0668: }
0669:
0670: /**
0671: * As my JDK docs say, this may break with Java 2D.
0672: * <p>Sets the clipping region to that of a Shape.
0673: * @param s Shape to clip to.
0674: */
0675: public void setClip(Shape s) {
0676: Rectangle r = s.getBounds();
0677: setClip(r.x, r.y, r.width, r.height);
0678: }
0679:
0680: /**
0681: * This extra method allows PDF users to clip to a Polygon.
0682: *
0683: * <p>In theory you could use setClip(), except that java.awt.Graphics
0684: * only supports Rectangle with that method, so we will have an extra
0685: * method.
0686: * @param p Polygon to clip to
0687: */
0688: public void clipPolygon(Polygon p) {
0689: closeBlock(); // finish off any existing path
0690: polygon(p.xpoints, p.ypoints, p.npoints);
0691: closeBlock("W"); // clip to current path
0692: clipRectangle = p.getBounds();
0693: }
0694:
0695: /**
0696: * Returns the Rectangle that fits the current clipping region
0697: * @return the Rectangle that fits the current clipping region
0698: */
0699: public Rectangle getClipBounds() {
0700: return clipRectangle;
0701: }
0702:
0703: //============ Colour operations =======================
0704:
0705: /**
0706: * Returns the current pen Colour
0707: * @return the current pen Colour
0708: */
0709: public Color getColor() {
0710: return color;
0711: }
0712:
0713: /**
0714: * Sets the colour for drawing
0715: * @param c Color to use
0716: */
0717: public void setColor(Color c) {
0718: color = c;
0719: double r = ((double) c.getRed()) / 255.0;
0720: double g = ((double) c.getGreen()) / 255.0;
0721: double b = ((double) c.getBlue()) / 255.0;
0722: closeBlock(); // This ensures any paths are drawn in the previous colours
0723: pw.println("" + r + " " + g + " " + b + " rg " + r + " " + g
0724: + " " + b + " RG");
0725: }
0726:
0727: /**
0728: * Not implemented, as this is not supported in the PDF specification.
0729: */
0730: public void setPaintMode() {
0731: }
0732:
0733: /**
0734: * Not implemented, as this is not supported in the PDF specification.
0735: * @param c1 Color to xor with
0736: */
0737: public void setXORMode(Color c1) {
0738: }
0739:
0740: //============ Text operations =======================
0741:
0742: /**
0743: * Returns the FontMetrics for a font.
0744: * <p>This doesn't work correctly. Perhaps having some way of mapping
0745: * the base 14 fonts to our own FontMetrics implementation?
0746: * @param font The java.awt.Font to return the metrics for
0747: * @return FontMetrics for a font
0748: */
0749: public FontMetrics getFontMetrics(Font font) {
0750: Frame dummy = new Frame();
0751: dummy.addNotify();
0752: Image image = dummy.createImage(100, 100);
0753: if (image == null) {
0754: System.err.println("getFontMetrics: image is null");
0755: }
0756: Graphics graphics = image.getGraphics();
0757: return graphics.getFontMetrics(font);
0758:
0759: }
0760:
0761: /**
0762: * Return's the current font.
0763: * @return the current font.
0764: */
0765: public Font getFont() {
0766: if (font == null)
0767: setFont(new Font("SansSerif", Font.PLAIN, 12));
0768: return font;
0769: }
0770:
0771: /**
0772: * This sets the font.
0773: * @param f java.awt.Font to set to.
0774: */
0775: public void setFont(Font f) {
0776: // Optimise: Save some space if the font is already the current one.
0777: if (font != f) {
0778: font = f;
0779: pdffont = page.getFont("/Type1", f.getName(), f.getStyle());
0780:
0781: // mark the font as changed
0782: newFont = true;
0783: }
0784: }
0785:
0786: /**
0787: * This draws a string.
0788: *
0789: * @oaran s String to draw
0790: * @param x coord
0791: * @param y coord
0792: */
0793: public void drawString(String s, int x, int y) {
0794: newTextBlock(x, y);
0795: pw.println(PDFStringHelper.makePDFString(s) + " Tj");
0796: }
0797:
0798: /**
0799: * <p>Not implemented</p>
0800: *
0801: * @param data a <code>byte[]</code> value
0802: * @param offset an <code>int</code> value
0803: * @param length an <code>int</code> value
0804: * @param x an <code>int</code> value
0805: * @param y an <code>int</code> value
0806: */
0807: public void drawBytes(byte[] data, int offset, int length, int x,
0808: int y) {
0809:
0810: }
0811:
0812: //============ Optimizers =======================
0813:
0814: /**
0815: * All functions should call this to close any existing optimised blocks.
0816: */
0817: void closeBlock() {
0818: closeBlock("S");
0819: }
0820:
0821: /**
0822: * <p>This is used by code that use the path in any way other than Stroke
0823: * (like Fill, close path & Stroke etc). Usually this is used internally.</p>
0824: *
0825: * @param code PDF operators that will close the path
0826: */
0827: void closeBlock(String code) {
0828: if (inText) {
0829: pw.println("ET Q");
0830: setOrientation(); // fixes Orientation matrix
0831: }
0832:
0833: if (inStroke) {
0834: pw.println(code);
0835: }
0836:
0837: inStroke = inText = false;
0838: }
0839:
0840: /**
0841: * Functions that draw lines should start by calling this. It starts a
0842: * new path unless inStroke is set, in that case it uses the existing path
0843: */
0844: void newPath() {
0845: if (inText) {
0846: closeBlock();
0847: }
0848: if (!inStroke) {
0849: if (pre_np != null) {
0850: pw.print(pre_np); // this is the prefix set by setOrientation()
0851: pre_np = null;
0852: }
0853: pw.print("n ");
0854: }
0855:
0856: inText = false;
0857: inStroke = true;
0858:
0859: // an unlikely coordinate to fool the moveto() optimizer
0860: lx = ly = -9999;
0861: }
0862:
0863: /**
0864: * <p>Functions that draw text should start by calling this. It starts a text
0865: * block (accounting for media orientation) unless we are already in a Text
0866: * block.</p>
0867: *
0868: * <p>It also handles if the font has been changed since the current text
0869: * block was started, so your function will be current.</p>
0870: *
0871: * @param x x coord in java space
0872: * @param y y coord in java space
0873: */
0874: void newTextBlock(int x, int y) {
0875: // close the current path if there is one
0876: if (inStroke) {
0877: closeBlock();
0878: }
0879: // create the text block if one is not current. If we are, the newFont
0880: // condition at the end catches font changes
0881: if (!inText) {
0882: // This ensures that there is a font available
0883: getFont();
0884:
0885: pw.print("q BT ");
0886: tx = ty = 0;
0887:
0888: // produce the text matrix for the media
0889: switch (mediaRot) {
0890: case 0: // Portrait
0891: //pw.println("1 0 0 1 0 0 Tm");
0892: break;
0893:
0894: case 90: // Landscape
0895: pw.println("0 1 -1 0 0 0 Tm"); // rotate
0896: break;
0897:
0898: case 180: // Inverted Portrait
0899: pw.println("1 0 0 -1 0 0 Tm");
0900: break;
0901:
0902: case 270: // Seascape
0903: pw.println("0 -1 1 0 0 0 Tm"); // rotate
0904: break;
0905: }
0906:
0907: // move the text cursor by an absolute amount
0908: pw.print(txy(x, y) + "Td ");
0909:
0910: } else {
0911: // move the text cursor by a relative amount
0912: //int ox=x-tx, oy=ty-y;
0913: //pw.print(""+ox+" "+oy+" Td ");
0914: //pw.print(cwh(x-tx,y-ty)+"Td ");
0915: pw.print(twh(x, y, tx, ty) + "Td ");
0916: }
0917:
0918: // preserve the coordinates for the next time
0919: tx = x;
0920: ty = y;
0921:
0922: if (newFont || !inText)
0923: pw.print(pdffont.getName() + " " + font.getSize() + " Tf ");
0924:
0925: // later add colour changes here (if required)
0926:
0927: inStroke = newFont = false;
0928: inText = true;
0929: }
0930:
0931: /**
0932: * This is unsupported - how do you do this with Vector graphics?
0933: * @param x coord
0934: * @param y coord
0935: * @param w width
0936: * @param h height
0937: * @param dx coord
0938: * @param dy coord
0939: */
0940: public void copyArea(int x, int y, int w, int h, int dx, int dy) {
0941: // Hmm... Probably need to keep track of everything
0942: // that has been drawn so far to get the contents of an area
0943: }
0944:
0945: //============ Line operations =======================
0946:
0947: /**
0948: * Draws a line between two coordinates.
0949: *
0950: * If the first coordinate is the same as the last one drawn
0951: * (ie a previous drawLine, moveto, etc) it is ignored.
0952: * @param x1 coord
0953: * @param y1 coord
0954: * @param x2 coord
0955: * @param y2 coord
0956: */
0957: public void drawLine(int x1, int y1, int x2, int y2) {
0958: moveto(x1, y1);
0959: lineto(x2, y2);
0960: }
0961:
0962: /**
0963: * Translate the origin.
0964: * @param x coord offset
0965: * @param y coord offset
0966: */
0967: public void translate(int x, int y) {
0968: trax += x;
0969: tray += y;
0970: //closeBlock();
0971: //// we use cw & ch here as the coordinates are relative not absolute
0972: //pw.println("1 0 0 1 "+cwh(x,y)+" cm");
0973: }
0974:
0975: //============ Arcs operations ==============================
0976: // These are the standard Graphics operators. They use the
0977: // arc extension operators to achieve the affect.
0978:
0979: /**
0980: * Draws an arc
0981: * @param x coord
0982: * @param y coord
0983: * @param w width
0984: * @param h height
0985: * @param sa Start angle
0986: * @param aa End angle
0987: */
0988: public void drawArc(int x, int y, int w, int h, int sa, int aa) {
0989: w = w >> 1;
0990: h = h >> 1;
0991: x += w;
0992: y += h;
0993:
0994: arc((double) x, (double) y, (double) w, (double) h,
0995: (double) -sa, (double) (-sa - aa), false);
0996: }
0997:
0998: /**
0999: * Fills an arc, joining the start and end coordinates
1000: * @param x coord
1001: * @param y coord
1002: * @param w width
1003: * @param h height
1004: * @param sa Start angle
1005: * @param aa End angle
1006: */
1007: public void fillArc(int x, int y, int w, int h, int sa, int aa) {
1008: // here we fool the optimizer. We force any open path to be closed,
1009: // then draw the arc. Finally, as the optimizer hasn't stroke'd the
1010: // path, we close and fill it, and mark the Stroke as closed.
1011: //
1012: // Note: The lineto to the centre of the object is required, because
1013: // the fill only fills the arc. Skipping this includes an extra
1014: // chord, which isn't correct. Peter May 31 2000
1015: closeBlock();
1016: drawArc(x, y, w, h, sa, aa);
1017: lineto(x + (w >> 1), y + (h >> 1));
1018: closeBlock("b"); // closepath and fill
1019: }
1020:
1021: //============ Extension operations ==============================
1022: // These are extensions, and provide access to PDF Specific
1023: // operators.
1024:
1025: /**
1026: * This moves the current drawing point.
1027: * @param x coord
1028: * @param y coord
1029: */
1030: public void moveto(int x, int y) {
1031: newPath();
1032: if (lx != x && ly != y)
1033: pw.print(cxy(x, y) + "m ");
1034: lx = x;
1035: ly = y;
1036: }
1037:
1038: /**
1039: * This moves the current drawing point.
1040: * @param x coord
1041: * @param y coord
1042: */
1043: public void moveto(double x, double y) {
1044: newPath();
1045: // no optimisation here as it may introduce errors on decimal coords.
1046: pw.print(cxy(x, y) + "m ");
1047: lx = (int) x;
1048: ly = (int) y;
1049: }
1050:
1051: /**
1052: * This adds a line segment to the current path
1053: * @param x coord
1054: * @param y coord
1055: */
1056: public void lineto(int x, int y) {
1057: newPath();
1058: if (lx != x && ly != y)
1059: pw.print(cxy(x, y) + "l ");
1060: lx = x;
1061: ly = y;
1062: }
1063:
1064: /**
1065: * This adds a line segment to the current path
1066: * @param x coord
1067: * @param y coord
1068: */
1069: public void lineto(double x, double y) {
1070: newPath();
1071: // no optimisation here as it may introduce errors on decimal coords.
1072: pw.print(cxy(x, y) + "l ");
1073: lx = (int) x;
1074: ly = (int) y;
1075: }
1076:
1077: /**
1078: * This extension allows the width of the drawn line to be set
1079: * @param w Line width in mm
1080: */
1081: public void setLineWidth(double w) {
1082: closeBlock(); // draw any path before we change the line width
1083: pw.println("" + w + " w");
1084: }
1085:
1086: /**
1087: * This extension sets the line width to the default of 1mm which is what
1088: * Java uses when drawing to a PrintJob.
1089: */
1090: public void setDefaultLineWidth() {
1091: closeBlock(); // draw any path before we change the line width
1092: pw.println("1 w");
1093: }
1094:
1095: /**
1096: * This is used to add a polygon to the current path.
1097: * Used by drawPolygon(), drawPolyline() and fillPolygon() etal
1098: * @param xp Array of x coordinates
1099: * @param yp Array of y coordinates
1100: * @param np number of points in polygon
1101: * @see #drawPolygon
1102: * @see #drawPolyline
1103: * @see #fillPolygon
1104: */
1105: public void polygon(int[] xp, int[] yp, int np) {
1106: // newPath() not needed here as moveto does it ;-)
1107: moveto(xp[0], yp[0]);
1108: for (int i = 1; i < np; i++)
1109: lineto(xp[i], yp[i]);
1110: }
1111:
1112: /**
1113: * This extension appends a Bezier curve to the path. The curve
1114: * extends from the current point to (x3,y3) using (x1,y1) and
1115: * (x2,y2) as the Bezier control points.
1116: * <p>The new current point is (x3,y3)
1117: *
1118: * @param x1 First control point
1119: * @param y1 First control point
1120: * @param x2 Second control point
1121: * @param y2 Second control point
1122: * @param x3 Destination point
1123: * @param y3 Destination point
1124: */
1125: public void curveto(int x1, int y1, int x2, int y2, int x3, int y3) {
1126: newPath();
1127: pw.println(cxy(x1, y1) + cxy(x2, y2) + cxy(x3, y3) + "c");
1128: lx = x3;
1129: ly = y3;
1130: }
1131:
1132: /**
1133: * This extension appends a Bezier curve to the path. The curve
1134: * extends from the current point to (x3,y3) using (x1,y1) and
1135: * (x2,y2) as the Bezier control points.
1136: * <p>The new current point is (x3,y3)
1137: *
1138: * @param x1 First control point
1139: * @param y1 First control point
1140: * @param x2 Second control point
1141: * @param y2 Second control point
1142: * @param x3 Destination point
1143: * @param y3 Destination point
1144: */
1145: public void curveto(double x1, double y1, double x2, double y2,
1146: double x3, double y3) {
1147: newPath();
1148: pw.println(cxy(x1, y1) + cxy(x2, y2) + cxy(x3, y3) + "c");
1149: lx = (int) x3;
1150: ly = (int) y3;
1151: }
1152:
1153: /**
1154: * This extension appends a Bezier curve to the path. The curve
1155: * extends from the current point to (x2,y2) using the current
1156: * point and (x1,y1) as the Bezier control points.
1157: * <p>The new current point is (x2,y2)
1158: *
1159: * @param x1 Second control point
1160: * @param y1 Second control point
1161: * @param x2 Destination point
1162: * @param y2 Destination point
1163: */
1164: public void curveto(int x1, int y1, int x2, int y2) {
1165: newPath();
1166: pw.println(cxy(x1, y1) + cxy(x2, y2) + "v");
1167: lx = x2;
1168: ly = y2;
1169: }
1170:
1171: /**
1172: * This extension appends a Bezier curve to the path. The curve
1173: * extends from the current point to (x2,y2) using the current
1174: * point and (x1,y1) as the Bezier control points.
1175: * <p>The new current point is (x2,y2)
1176: *
1177: * @param x1 Second control point
1178: * @param y1 Second control point
1179: * @param x2 Destination point
1180: * @param y2 Destination point
1181: */
1182: public void curveto(double x1, double y1, double x2, double y2) {
1183: newPath();
1184: pw.println(cxy(x1, y1) + cxy(x2, y2) + "v");
1185: lx = (int) x2;
1186: ly = (int) y2;
1187: }
1188:
1189: /**
1190: * This extension appends a Bezier curve to the path. The curve
1191: * extends from the current point to (x2,y2) using (x1,y1) and
1192: * the end point as the Bezier control points.
1193: * <p>The new current point is (x2,y2)
1194: *
1195: * @param x1 Second control point
1196: * @param y1 Second control point
1197: * @param x2 Destination point
1198: * @param y2 Destination point
1199: */
1200: public void curveto2(int x1, int y1, int x2, int y2) {
1201: newPath();
1202: pw.println(cxy(x1, y1) + cxy(x2, y2) + "y");
1203: lx = x2;
1204: ly = y2;
1205: }
1206:
1207: /**
1208: * This extension appends a Bezier curve to the path. The curve
1209: * extends from the current point to (x2,y2) using (x1,y1) and
1210: * the end point as the Bezier control points.
1211: * <p>The new current point is (x2,y2)
1212: *
1213: * @param x1 Second control point
1214: * @param y1 Second control point
1215: * @param x2 Destination point
1216: * @param y2 Destination point
1217: */
1218: public void curveto2(double x1, double y1, double x2, double y2) {
1219: newPath();
1220: pw.println(cxy(x1, y1) + cxy(x2, y2) + "y");
1221: lx = (int) x2;
1222: ly = (int) y2;
1223: }
1224:
1225: // Arcs are horrible and complex. They are at the end of the
1226: // file, because they are the largest. This is because, unlike
1227: // Postscript, PDF doesn't have any arc operators, so we must
1228: // implement them by converting into one or more Bezier curves
1229: // (which is how Postscript does them internally).
1230:
1231: /**
1232: * One degree in radians
1233: */
1234: private static final double degrees_to_radians = Math.PI / 180.0;
1235:
1236: /**
1237: * This produces an arc by breaking it down into one or more Bezier curves.
1238: * It is used internally to implement the drawArc and fillArc methods.
1239: *
1240: * @param axc X coordinate of arc centre
1241: * @param ayc Y coordinate of arc centre
1242: * @param width of bounding rectangle
1243: * @param height of bounding rectangle
1244: * @param ang1 Start angle
1245: * @param ang2 End angle
1246: * @param clockwise true to draw clockwise, false anti-clockwise
1247: */
1248: public void arc(double axc, double ayc, double width,
1249: double height, double ang1, double ang2, boolean clockwise) {
1250:
1251: double adiff;
1252: double x0, y0;
1253: double x3r, y3r;
1254: boolean first = true;
1255:
1256: // may not need this
1257: //if( ar < 0 ) {
1258: //ang1 += fixed_180;
1259: //ang2 += fixed_180;
1260: //ar = - ar;
1261: //}
1262:
1263: double ang1r = (ang1 % 360.0) * degrees_to_radians;
1264:
1265: double sin0 = Math.sin(ang1r);
1266: double cos0 = Math.cos(ang1r);
1267:
1268: x0 = axc + width * cos0;
1269: y0 = ayc + height * sin0;
1270:
1271: // NB: !clockwise here as Java Space is inverted to User Space
1272: if (!clockwise) {
1273: // Quadrant reduction
1274: while (ang1 < ang2)
1275: ang2 -= 360.0;
1276: while ((adiff = ang2 - ang1) < -90.0) {
1277: double w = sin0;
1278: sin0 = -cos0;
1279: cos0 = w;
1280: x3r = axc + width * cos0;
1281: y3r = ayc + height * sin0;
1282: arc_add(first, width, height, x0, y0, x3r, y3r,
1283: (x0 + width * cos0), (y0 + height * sin0));
1284:
1285: x0 = x3r;
1286: y0 = y3r;
1287: ang1 -= 90.0;
1288: first = false;
1289: }
1290: } else {
1291: // Quadrant reduction
1292: while (ang2 < ang1)
1293: ang2 += 360.0;
1294: while ((adiff = ang2 - ang1) > 90.0) {
1295: double w = cos0;
1296: cos0 = -sin0;
1297: sin0 = w;
1298: x3r = axc + width * cos0;
1299: y3r = ayc + height * sin0;
1300: arc_add(first, width, height, x0, y0, x3r, y3r,
1301: (x0 + width * cos0), (y0 + height * sin0));
1302:
1303: x0 = x3r;
1304: y0 = y3r;
1305: ang1 += 90.0;
1306: first = false;
1307: }
1308: }
1309:
1310: // Compute the intersection of the tangents.
1311: // We know that -fixed_90 <= adiff <= fixed_90.
1312: double trad = Math.tan(adiff * (degrees_to_radians / 2));
1313: double ang2r = ang2 * degrees_to_radians;
1314: double xt = x0 - trad * width * sin0;
1315: double yt = y0 + trad * height * cos0;
1316: arc_add(first, width, height, x0, y0, (axc + width
1317: * Math.cos(ang2r)), (ayc + height * Math.sin(ang2r)),
1318: xt, yt);
1319: }
1320:
1321: /**
1322: * Used by the arc method to actually add an arc to the path
1323: * Important: We write directly to the stream here, because this method
1324: * operates in User space, rather than Java space.
1325: * @param first true if the first arc
1326: * @param w width
1327: * @param h height
1328: * @param x0 coord
1329: * @param y0 coord
1330: * @param x3 coord
1331: * @param y3 coord
1332: * @param xt coord
1333: * @param yt coord
1334: */
1335: private void arc_add(boolean first, double w, double h, double x0,
1336: double y0, double x3, double y3, double xt, double yt) {
1337: double dx = xt - x0, dy = yt - y0;
1338: double dist = dx * dx + dy * dy;
1339: double w2 = w * w, h2 = h * h;
1340: double r2 = w2 + h2;
1341:
1342: double fw = 0.0, fh = 0.0;
1343: if (dist < (r2 * 1.0e8)) {
1344: fw = (4.0 / 3.0) / (1 + Math.sqrt(1 + dist / w2));
1345: fh = (4.0 / 3.0) / (1 + Math.sqrt(1 + dist / h2));
1346: }
1347:
1348: // The path must have a starting point
1349: if (first)
1350: moveto(x0, y0);
1351:
1352: double x = x0 + ((xt - x0) * fw);
1353: double y = y0 + ((yt - y0) * fh);
1354: x0 = x3 + ((xt - x3) * fw);
1355: y0 = y3 + ((yt - y3) * fh);
1356:
1357: // Finally the actual curve.
1358: curveto(x, y, x0, y0, x3, y3);
1359: }
1360:
1361: /**
1362: * This sets the media Orientation (0=Portrait, 90=Landscape,
1363: * 180=Inverse, 270=Seascape).
1364: *
1365: * <p>Normally, this is called when the Graphics instance is created, but
1366: * if the media is changed, then this must be called, especially when using
1367: * the PDFJob class to create the file.
1368: *
1369: */
1370: public void setOrientation() {
1371: mediaRot = page.getOrientation();
1372: switch (mediaRot) {
1373: case 0: // Portrait
1374: //pre_np = "1 0 0 1 0 "+media.height+" cm 1 0 0 -1 0 0 cm ";
1375: break;
1376:
1377: case 90: // Landscape
1378: //pw.println("0.7071067 0.7071067 -0.7071067 0.7071067 0 0 Tm");
1379: //pw.println("1 0 0 1 0 -"+page.getMedia().height+" Tm");
1380: //pre_np = "1 0 0 1 "+page.getMedia().width+" 0 cm 0 1 -1 0 0 0 cm ";
1381: break;
1382:
1383: case 180: // Inverted Portrait
1384: //pre_np = "1 0 0 1 "+media.width+" 0 cm -1 0 0 1 0 0 cm ";
1385: break;
1386:
1387: case 270: // Seascape
1388: // check this
1389: //pre_np = "1 0 0 1 -"+page.getMedia().width+" 0 cm 0 -1 1 0 0 0 cm ";
1390: break;
1391: }
1392: }
1393:
1394: /**
1395: * Converts the Java space coordinates into pdf.
1396: * @param x coord
1397: * @param y coord
1398: * @return String containing the coordinates in PDF space
1399: */
1400: private String cxy(int x, int y) {
1401: return cxy((double) x, (double) y);
1402: }
1403:
1404: /**
1405: * Converts the Java space coordinates into pdf.
1406: * @param x coord
1407: * @param y coord
1408: * @return String containing the coordinates in PDF space
1409: */
1410: private String cxy(double x, double y) {
1411: double nx = x, ny = y; // scratch
1412: double mw = (double) (media.width);
1413: double mh = (double) (media.height);
1414:
1415: // handle any translations
1416: x -= trax;
1417: y -= tray;
1418:
1419: switch (mediaRot) {
1420: case 0:
1421: // Portrait
1422: //nx = x;
1423: ny = mh - y;
1424: break;
1425:
1426: case 90:
1427: // Landscape
1428: nx = y;
1429: ny = x;
1430: break;
1431:
1432: case 180:
1433: // Inverse Portrait
1434: nx = mw - x;
1435: //ny = y;
1436: break;
1437:
1438: case 270:
1439: // Seascape
1440: nx = mw - y;
1441: ny = mh - x;
1442: break;
1443: }
1444:
1445: return "" + nx + " " + ny + " ";
1446: }
1447:
1448: /**
1449: * Converts the Java space dimension into pdf.
1450: * @param w width
1451: * @param h height
1452: * @return String containing the coordinates in PDF space
1453: */
1454: private String cwh(int w, int h) {
1455: return cwh((double) w, (double) h);
1456: }
1457:
1458: /**
1459: * Converts the Java space dimension into pdf.
1460: * @param w width
1461: * @param h height
1462: * @return String containing the coordinates in PDF space
1463: */
1464: private String cwh(double w, double h) {
1465: double nw = w, nh = h; // scratch
1466:
1467: switch (mediaRot) {
1468: case 0:
1469: // Portrait
1470: //nw = w;
1471: nh = -h;
1472: break;
1473:
1474: case 90:
1475: // Landscape
1476: nw = h;
1477: nh = w;
1478: break;
1479:
1480: case 180:
1481: // Inverse Portrait
1482: nw = -w;
1483: //nh = h;
1484: break;
1485:
1486: case 270:
1487: // Seascape
1488: nw = -h;
1489: nh = -w;
1490: break;
1491: }
1492:
1493: return "" + nw + " " + nh + " ";
1494: }
1495:
1496: /**
1497: * Converts the Java space coordinates into pdf text space.
1498: * @param x coord
1499: * @param y coord
1500: * @return String containing the coordinates in PDF text space
1501: */
1502: private String txy(int x, int y) {
1503: int nx = x, ny = y;
1504: int mw = media.width;
1505: int mh = media.height;
1506:
1507: // handle any translations
1508: x += trax;
1509: y += tray;
1510:
1511: switch (mediaRot) {
1512: case 0:
1513: // Portrait
1514: //nx = x;
1515: ny = mh - y;
1516: break;
1517:
1518: case 90:
1519: // Landscape
1520: //nx = y;
1521: //ny = x;
1522: nx = x;
1523: ny = -y;
1524: break;
1525:
1526: case 180:
1527: // Inverse Portrait
1528: // to be completed
1529: nx = mw - x;
1530: //ny = y;
1531: break;
1532:
1533: case 270:
1534: // Seascape
1535: // to be completed
1536: nx = mw - y;
1537: ny = mh - x;
1538: break;
1539: }
1540:
1541: return "" + nx + " " + ny + " ";
1542: }
1543:
1544: /**
1545: * Converts the Java space coordinates into pdf text space.
1546: * @param x coord
1547: * @param y coord
1548: * @param tx coord
1549: * @param ty coord
1550: * @return String containing the coordinates in PDF text space
1551: */
1552: private String twh(int x, int y, int tx, int ty) {
1553: int nx = x, ny = y;
1554: int ntx = tx, nty = ty;
1555: int mw = media.width;
1556: int mh = media.height;
1557: int sx = 1, sy = 1;
1558: switch (mediaRot) {
1559: case 0:
1560: // Portrait
1561: //nx = x;
1562: ny = mh - y;
1563: nty = mh - ty;
1564: break;
1565:
1566: case 90:
1567: // Landscape
1568: //nx = y;
1569: //ny = x;
1570: //ntx = ty;
1571: //nty = tx;
1572: //sy=-1;
1573: nx = x;
1574: ny = -y;
1575: ntx = tx;
1576: nty = -ty;
1577: //sy=-1;
1578: break;
1579:
1580: case 180:
1581: // Inverse Portrait
1582: // to be completed
1583: nx = mw - x;
1584: //ny = y;
1585: break;
1586:
1587: case 270:
1588: // Seascape
1589: // to be completed
1590: nx = mw - y;
1591: ny = mh - x;
1592: break;
1593: }
1594:
1595: nx = sx * (nx - ntx);
1596: ny = sy * (ny - nty);
1597: return "" + nx + " " + ny + " ";
1598: }
1599:
1600: /**
1601: * Returns the Shape of the clipping region
1602: * As my JDK docs say, this may break with Java 2D.
1603: * @return Shape of the clipping region
1604: */
1605: public Shape getClip() {
1606: return null;
1607: }
1608:
1609: /**
1610: * Draws a string using a AttributedCharacterIterator.
1611: * <p>This is not supported yet, as I have no idea what an
1612: * AttributedCharacterIterator is.
1613: * <p>This method is new to the Java2 API.
1614: */
1615: public void drawString(java.text.AttributedCharacterIterator aci,
1616: int x, int y) {
1617: }
1618:
1619: } // end class PDFGraphics
|