KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > faceless > pdf > PDFPage


1 // $Id: PDFPage.java,v 1.11 2005/08/23 14:31:09 mike Exp $
2

3 package org.faceless.pdf;
4
5 import java.util.*;
6 import java.io.*;
7
8 /**
9  * <p>
10  * This class represents a single page in a PDF document. This class
11  * takes care of drawing shapes, text and images to the document.
12  * </p>
13  *
14  * <b>1. Geometry</b>
15  * <p>
16  * By default, the geometry of a PDF page is measured in points (defined in
17  * PostScript as 1/72 of an inch), from the bottom-left hand corner of the page.
18  * This can be altered by calling the <code>setCanvas</code> method as shown
19  * here.</p>
20  * <p>All methods which specify a rectangle on the page take both corners
21  * of the rectangle as parameters, rather than one corner plus the width and
22  * height. This is less ambiguous when a page can be measured in different
23  * directions.
24  * </p>
25  * <pre>
26  * // Create a canvas measured from the top-left of the page
27  * // in points, with a 100 point margin around it to the edge
28  * // of the page.
29  * //
30  * PDFPage page = pdf.newPage(800,500);
31  * page.setCanvas(100, 100, 600, 300, POINTS, PAGETOP+PAGELEFT);
32  * page.drawText("This is 100 points from the left and top of the page", 0, 0);
33  * </pre>
34  *
35  * <b>2. Drawing shapes</b>
36  * <p>
37  * Geometric shapes are drawn using either the simple "draw" methods or
38  * the more powerful "path" methods. Whether the shape is filled or just
39  * drawn as an outline depends on the <code>FillColor</code>
40  * and <code>LineColor</code> of the current style.
41  * <ul>
42  * <li><b><code>drawLine, drawRectangle, drawPolygon, drawEllipse,</code></b>
43  * and (since 1.1) <b><code>drawCircle, drawCircleArc, drawEllipseArc,
44  * drawRoundedRectangle</code></b>: These methods draw simple shapes onto the
45  * page with a single method call.
46  * <pre>
47  * PDFPage page = pdf.newPage(PAGESIZE_A4);
48  * PDFStyle linestyle = new PDFStyle();
49  * linestyle.setLineColor(java.awt.Color.red);
50  *
51  * // Draw a rectangle with two diagonal lines inside it.
52  * page.setStyle(linestyle);
53  * page.drawRectangle(100,100, 300, 200); // Box
54  * page.drawLine(100,100, 400, 300); // Diagonal 1
55  * page.drawLine(100,300, 400, 100); // Diagonal 2
56  * </pre>
57  </li>
58  * <li><b><code>pathMove, pathLine, pathBezier, pathClose</code></b>, and (since 1.1)
59  * <code><b>pathArc</code></b>: These more primitive methods allow greater
60  * control over the creation of geometric shapes, by creating a "path" which
61  * can then be drawn with the <code>pathPaint</code> method.
62  * <pre>
63  * PDFPage page = pdf.newPage(PAGESIZE_A4);
64  * PDFStyle linestyle = new PDFStyle();
65  * linestyle.setLineColor(java.awt.Color.red);
66  *
67  * // Draw the same rectangle with two diagonal lines inside it.
68  * page.setStyle(linestyle);
69  * page.pathMove(100,100); // Start Box
70  * page.pathLine(100,300);
71  * page.pathLine(400,300);
72  * page.pathLine(400,100);
73  * page.pathLine(100,300); // Diagonal 1
74  * page.pathPaint(); // Paint the box and the first diagonal
75  * page.pathMove(100,100); // Start Diagonal 2
76  * page.pathLine(400,300);
77  * page.pathPaint(); // Paint the second diagonal
78  * </pre>
79  * </ul>
80  * </p>
81  *
82  * <b>3. Drawing Text</b>
83  * <p>
84  * <ul>
85  * <li>A single lines of text can be drawn at a specified location by using the
86  * <b><code>drawText</code></b> method.
87  * <pre>
88  * PDFPage page = pdf.newPage(PAGESIZE_A4);
89  * PDFStyle textstyle = new PDFStyle();
90  * textstyle.setFillColor(java.awt.Color.black);
91  * textstyle.setFont(new StandardFont(StandardFont.COURIER), 12);
92  *
93  * // Draw some text at the specified location
94  * page.setStyle(textstyle);
95  * page.drawText("This is some text", 100, 100);
96  * </pre>
97  * <li>Larger blocks of text can be drawn by calling <b><code>beginText</code></b>,
98  * followed by one or more calls to <b><code>drawText</code></b>, and closing with
99  * a call to <b><code>endText</code></b>.
100  * This method can be used to mix several styles, even different fonts, in a single
101  * paragraph, and since 1.1 the methods <code>beginTextLink</code> and
102  * <code>endTextLink</code> can turn portions of the text into HTML-like hyperlinks.
103  * <pre>
104  * PDFPage page = pdf.newPage(PAGESIZE_A4); // 595 x 842 points
105  *
106  * // Create first style - 12pt black Helvetica
107  * PDFStyle style1 = new PDFStyle();
108  * style1.setFillColor(java.awt.Color.black);
109  * style1.setFont(new StandardFont(StandardFont.HELVETICA), 12);
110  *
111  * // Create second style - 12pt black Verdana (TrueType font)
112  * PDFStyle style2 = (PDFStyle)style1.clone();
113  * PDFFont ver = new TrueTypeFont(new FileInputStream("verdana.ttf"), true, true);
114  * style2.setFont(ver, 12);
115  *
116  * // Create an action to perform when the user clicks on the word "hyperlink".
117  * PDFAction action = PDFAction.goToURL(new java.net.URL("http://big.faceless.org"));
118  *
119  * // Draw some text. Use the whole page, less a 100 point margin.
120  * page.beginText(100,100, page.getWidth()-100, page.getHeight()-100);
121  *
122  * page.setStyle(style1);
123  * page.drawText("This text is in ");
124  * page.setStyle(style2);
125  * page.drawText("Verdana.\n");
126  *
127  * page.setStyle(style1);
128  * page.drawText("And this text is a ");
129  * page.beginTextLink(action, null);
130  * page.drawText("hyperlink");
131  * page.endTextLink();
132  *
133  * page.endText(false);
134  * </pre>
135  * </p>
136  *
137  * <b>4. Drawing Images</b>
138  * <p>
139  * Bitmap images are drawn using the <b><code>drawImage</code></b> method.
140  * <pre>
141  * PDFImage img = new PDFImage(new FileInputStream("mypicture.jpg"));
142  * page.drawImage(img, 100, 100, 200, 200);
143  * </pre>
144  * </p>
145  *
146  * <b>5. Transformations</b>
147  * <p>
148  * As well as adding graphic elements to the page, adjustments can be made to the
149  * page itself. A page can be rotated, offset by an amount or scaled in the X and Y
150  * directions by calling the <b><code>rotate</code></b>,
151  * <b><code>translate</code></b> and <b><code>scale</code></b> methods.
152  * These methods affect all operations on the page, like drawing lines or text, and
153  * also cause any future transformations to be transformed. This can be confusing.
154  * For example:
155  * <pre>
156  * page.rotate(0,0,90);
157  * page.translate(0,100);
158  * </pre>
159  * This section of code first rotates the page 90 degrees clockwise around (0,0), then
160  * translates the page by 100 points in the Y axis. Because the page has been rotated
161  * 90 degrees, the <code>translate</code> actually has the effect of moving all future
162  * operations 100 points <i>to the right</i>, rather than 100 points up the page. The
163  * order that transformations are made in is consequently very important.
164  * </p>
165  *
166  * <b>6. Save, Restore and Undo</b>
167  * <p>
168  * Three further operations simplify page layout, especially when using transformations.
169  * The <b><code>save</code></b> and <b><code>restore</code></b> methods allow you to
170  * backup and restore the state of a page, and since 1.1 the <b><code>undo</code></b>
171  * method allows you to restore the page to the state before the last call to
172  * <code>save</code>. It's often a good idea to save the page stage before applying any
173  * transformations, so you can quickly get back to exactly the way it was before.
174  * <pre>
175  * page.save(); // Save the page before we mess it up.
176  * page.translate(100,200);
177  * page.rotate(300,100,45);
178  * page.setStyle(weirdstyle);
179  * .
180  * .
181  * page.restore(); // Everything is now as it was.
182  * </pre>
183  * </p>
184  *
185  * <b>7. Clipping</b>
186  * <p>
187  * Similar to the <tt>drawRectangle</tt>, <tt>drawCircle</tt> etc. methods above, the
188  * <tt>clipRectangle</tt>, <tt>clipRoundedRectangle</tt>, <tt>clipCircle</tt>,
189  * <tt>clipEllipse</tt> and <tt>clipPolygon</tt> methods can be used to set the current
190  * <i>clipping area</i> on the page. Any future graphics or text operations will only
191  * take place inside that clipping area, which defaults to the entire page. For finer
192  * control, a path can be drawn using the <tt>path</tt> methods demonstrated above,
193  * and the <tt>pathClip</tt> method used to set the clipping area.
194  * </p><p>
195  * There is no way to enlarge the current clipping area, or to set a new clipping area
196  * without reference to the current one. However, as the current clipping area is part
197  * of the graphics state, it can (and should) be nested inside calls to <tt>save</tt>
198  * and <tt>restore</tt> to limit its effect.
199  * </p><p>Here's an example which draws an image on the page, clipped to a circle.</p>
200  * <pre>
201  * page.save(); // Save the current clipping path - the whole page
202  *
203  * PDFImage img = new PDFImage(new FileInputStream("mypicture.jpg"));
204  * page.clipEllipse(100,100,300,300);
205  * page.drawImage(img, 100, 100, 300, 300);
206  *
207  * page.restore(); // Restore the previous clipping path
208  * </pre>
209  *
210  * @see PDFStyle
211  * @see PDFFont
212  * @see PDFImage
213  * @see PDF
214  * @version $Revision: 1.11 $
215  *
216  */

217 public final class PDFPage extends PeeredObject
218 {
219     final org.faceless.pdf2.PDFPage page;
220     private PDFStyle tempstyle;
221     private State state;
222     private Stack statestack;
223     private float translatex, translatey, scalex, scaley, canvaswidth, canvasheight;
224
225     private class State
226     {
227         float translatex, translatey, scalex, scaley;
228     public State()
229     {
230         scalex=scaley=1;
231     }
232     }
233
234
235     /**
236      * Argument to <code>setFilter</code> to compress the page using the
237      * <code>java.util.zip.Deflater</code> filter (the default).
238      */

239     public static final int FILTER_FLATE = 0;
240
241     /**
242      * Argument to <code>setFilter</code> to not compress the page.
243      */

244     public static final int FILTER_NONE = 0;
245
246     /**
247      * Argument to <code>setCanvas</code> to measure the page in inches
248      */

249     public static final int INCHES=4;
250
251     /**
252      * Argument to <code>setCanvas</code> to measure the page in centimeters
253      */

254     public static final int CM=8;
255
256     /**
257      * Argument to <code>setCanvas</code> to measure the page in millimeters
258      */

259     public static final int MM=12;
260
261     /**
262      * Argument to <code>setCanvas</code> to measure the page in picas (1 pica=12 points)
263      */

264     public static final int PICAS=16;
265
266     /**
267      * Argument to <code>setCanvas</code> to measure the page in percent. Unlike
268      * the other measurements, this can result in changes to the aspect ratio.
269      * (10% of the page width is usually less than 10% of the page height).
270      */

271     public static final int PERCENT=20;
272
273     /**
274      * Argument to <code>setCanvas</code> to measure the page in points (the default)
275      */

276     public static final int POINTS=24;
277
278     /**
279      * Argument to <code>setCanvas</code> to measure the page from the bottom
280      */

281     public static final int PAGEBOTTOM=0;
282
283     /**
284      * Argument to <code>setCanvas</code> to measure the page from the top
285      */

286     public static final int PAGETOP=1;
287
288     /**
289      * Argument to <code>setCanvas</code> to measure the page from the left
290      */

291     public static final int PAGELEFT=0;
292
293     /**
294      * Argument to <code>setCanvas</code> to measure the page from the right
295      */

296     public static final int PAGERIGHT=2;
297
298     /**
299      * Barcode type for <code>drawBarCode</code> representing a "Code 39" barcode.
300      * This barcode can display digits, the 26 upper-case letters, the space character
301      * and the symbols '-', '+', '/', '.', '$' and '%'.
302      */

303     public static final int BARCODE39=0;
304
305     /**
306      * Barcode type for <code>drawBarCode</code> representing a "Code 39" barcode, with
307      * checksum. This barcode can display digits, the 26 capital letters, the space character
308      * and the symbols '-', '+', '/', '.', '$' and '%'. The checksum algorithm is described
309      * on <a target=_new HREF="http://www.adams1.com/pub/russadam/39code.html">this page</a>.
310      */

311     public static final int BARCODE39CHECKSUM=1;
312
313     /**
314      * Barcode type for <code>drawBarCode</code> representing an
315      * "Interleaved 2 of 5" barcode. The interleaved 2 of 5 barcode
316      * is only suitable for numbers, and requires an even number of
317      * digits (a leading "0" will be automatically added if required).
318      */

319     public static final int BARCODE25=2;
320
321     /**
322      * Barcode type for <code>drawBarCode</code> representing an "Interleaved 2 of 5" barcode,
323      * with checksum. The interleaved 2 of 5 barcode is only suitable for numbers and requires
324      * an even number of digits including the checksum digit - a leading "0" will be
325      * automatically added if required. The checksum digit is added at the end, and is the
326      * value of the equation <tt>(10 - ((s[0]*3 + s[1] + s[2]*3 + s[3] <i><small>and so on,
327      * multiplying every second digit by 3</small></i>) % 10)) % 10 </tt>
328      */

329     public static final int BARCODE25CHECKSUM=3;
330
331     /**
332      * Barcode type for <code>drawBarCode</code> representing the "Extended Code 39" barcode.
333      * This barcode can display all the characters in the U+0000 to U+007F range (i.e. US ASCII)
334      * by re-encoding those characters into two character pairs and then using the normal
335      * Code 39 barcode. The re-encoding algorithm is described on
336      * <a target=_new HREF="http://www.barcodeman.com/info/c39_ext.php3">this page</a>.
337      */

338     public static final int BARCODE39X=4;
339
340     /**
341      * Barcode type for <code>drawBarCode</code> representing the "Extended Code 39" barcode,
342      * with checksum. This barcode can display all the characters in the U+0000 to U+007F
343      * range (i.e. US ASCII), by re-encoding those characters into two character pairs and then
344      * using the normal Code 39 barcode. The re-encoding algorithm is described on
345      * <a target=_new HREF="http://www.barcodeman.com/info/c39_ext.php3">this page</a>.
346      */

347     public static final int BARCODE39XCHECKSUM=5;
348
349     /**
350      * Barcode type for <code>drawBarCode</code> representing the "Code 128" barcode.
351      * The Code 128 barcode can display digits, upper and lower-case letters and most
352      * punctuation characters from the U+0020 - U+007E (US-ASCII) range. A checksum is
353      * automatically included as part of the barcode. The appropriate varient
354      * (CodeB or CodeC) is chosen automatically depending on the code that is printed.
355      * EAN128 barcodes can also be printed by using a newline (<tt>\n</tt>) to represent
356      * the FNC1 control character (this feature was added in version 1.1.23)
357      */

358     public static final int BARCODE128=6;
359
360     /**
361      * Barcode type for <code>drawBarCode</code> representing the EAN-13 barcode. An EAN-13
362      * code represents a 13 digit number - broadly speaking, the first 7 digits the
363      * country and manufacturer code, the next 5 digits the product code, and the final
364      * digit the checksum. The 12 digit UPC-A barcodes as used in the USA are just EAN-13
365      * codes with a leading zero. Most EAN-13 bar codes are an inch wide, so the recommended
366      * <tt>width</tt>, as passed into the <code>drawBarCode</code> method, is 0.75.
367      * @since 1.1.14
368      */

369     public static final int BARCODEEAN13=7;
370
371     /**
372      * Barcode type for <code>drawBarCode</code> representing the UPC-A barcode. Although
373      * the Uniform Code Council in the US has declared that all UPC-A readers be able to
374      * read EAN-13 codes by 2005, some clients may still prefer to use the older format
375      * 12 digit UPC-A codes. Barcodes using this code type must be 11 digits long, or 12
376      * digits if the check digit is pre-calculated. As with EAN-13, the recommended
377      * <tt>width</tt> is 0.75
378      * @since 1.2
379      */

380     public static final int BARCODEUPCA=9;
381
382     /**
383      * Barcode type for <code>drawBarCode</code> representing the "Codabar" barcode. A Codabar
384      * code can contain the digits 0 to 9, plus the characters +, /, $, -, : and the decimal
385      * point (.). Additionally it must begin and end with a "stop letter", which may be one
386      * of A, B, C or D.
387      * @since 1.1.14
388      */

389     public static final int BARCODECODABAR=8;
390
391
392     PDFPage(org.faceless.pdf2.PDFPage page)
393     {
394     this.page = page;
395     state=new State();
396     statestack = new Stack();
397     setCanvas(0,0,page.getWidth(), page.getHeight(), POINTS, PAGEBOTTOM|PAGELEFT);
398     }
399
400     Object JavaDoc getPeer()
401     {
402         return page;
403     }
404
405     /**
406      * Return the width of the page in points. This returns the width of the
407      * visible page (as defined by the CropBox) as opposed to the width of
408      * the physical page. For 99% of documents this is the same value.
409      */

410     public float getWidth()
411     {
412     return page.getWidth();
413     }
414
415     /**
416      * Return the height of the page in points. This returns the height of the
417      * visible page (as defined by the CropBox) as opposed to the height of
418      * the physical page. For 99% of documents this is the same value.
419      */

420     public float getHeight()
421     {
422     return page.getHeight();
423     }
424
425     /**
426      * Get which page this is in the PDF document - the first page is number 1.
427      * @since 1.1
428      */

429     public int getPageNumber()
430     {
431     return page.getPageNumber();
432     }
433
434     /**
435      * Set the current "canvas", or drawing area. When a new page is
436      * created, the canvas defaults to the entire page, measured in points
437      * from the bottom-left hand corner of the page. The canvas can be reset
438      * as many times as necessary.
439      *
440      * @param left the left edge of the canvas, in points
441      * @param bottom the bottom edge of the canvas, in points
442      * @param width the width of the canvas, in points
443      * @param height the height of the canvas, in points
444      * @param scale the units to measure it in. Can be {@link #POINTS} (the default),
445      * {@link #INCHES}, {@link #CM}, {@link #MM}, {@link #PICAS} or {@link #PERCENT}
446      * @param zerocorner which corner of the page is nearest to (0,0). A logical-or
447      * of {@link #PAGETOP}, {@link #PAGELEFT}, {@link #PAGERIGHT} and {@link #PAGEBOTTOM}
448      *
449      */

450     public void setCanvas(float left, float bottom, float width, float height, int scale, int zerocorner)
451     {
452     float newscale=page.UNITS_POINTS;
453     int neworigin=0;
454
455     translatex=left;
456     translatey=bottom;
457     if (scale==POINTS) scalex=scaley=page.UNITS_POINTS;
458     else if (scale==INCHES) scalex=scaley=page.UNITS_INCHES;
459     else if (scale==CM) scalex=scaley=page.UNITS_CM;
460     else if (scale==MM) scalex=scaley=page.UNITS_MM;
461     else if (scale==PICAS) scalex=scaley=page.UNITS_PICAS;
462     else if (scale==PERCENT) {
463         scaley=height/100;
464         scalex=width/100;
465     }
466
467     if ((zerocorner&PAGETOP)==PAGETOP) { scaley=-scaley; translatey+=height; }
468     if ((zerocorner&PAGERIGHT)==PAGERIGHT) { scalex=-scalex; translatex+=width; }
469
470     canvaswidth=width;
471     canvasheight=height;
472     }
473
474     private final float cx(float x) { return (translatex+x*scalex)*state.scalex + state.translatex; }
475     private final float cy(float y) { return (translatey+y*scaley)*state.scaley + state.translatey; }
476     private final float canvasx(float x) { return translatex + x*scalex; }
477     private final float canvasy(float y) { return translatey + y*scaley; }
478
479
480     /**
481      * Get the height of the current canvas in points.
482      */

483     public float getCanvasHeight()
484     {
485     return canvasheight;
486     }
487
488     /**
489      * Get the width of the current canvas in points.
490      */

491     public float getCanvasWidth()
492     {
493     return canvaswidth;
494     }
495
496     /**
497      * Set the current style.
498      */

499     public void setStyle(PDFStyle style)
500     {
501     page.setStyle(style.style);
502     this.tempstyle=style;
503     }
504
505     /**
506      * Return a copy of the the currently applied Style. Any changes to the
507      * returned style won't take effect unless it's applied by calling
508      * <code>setStyle</code>
509      */

510     public PDFStyle getStyle()
511     {
512     return (PDFStyle)PeeredObject.getPeer(page.getStyle());
513     }
514
515     /**
516      * Draw a line from x1,y1 to x2,y2 in the current styles <code>LineColor</code>.
517      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
518      * @param x1 the X co-ordinate of the start of the line
519      * @param y1 the Y co-ordinate of the start of the line
520      * @param x2 the X co-ordinate of the end of the line
521      * @param y2 the Y co-ordinate of the end of the line
522      * @throws IllegalStateException if the current style has no LineColor specified, or if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
523      */

524     public void drawLine(float x1, float y1, float x2, float y2)
525     {
526     page.drawLine(cx(x1),cy(y1),cx(x2),cy(y2));
527     }
528
529     /**
530      * <p>
531      * Draw a rectangle through the two corners (x1,y1) and
532      * (x2,y2). Whether the rectangle is drawn as an outline
533      * or filled depends on the <code>LineColor</code> and
534      * <code>FillColor</code> of the current style (see the
535      * {@link #pathPaint} method for more information).
536      * </p>
537      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
538      * @param x1 the X co-ordinate of the first corner of the rectangle
539      * @param y1 the Y co-ordinate of the first corner of the rectangle
540      * @param x2 the X co-ordinate of the second corner of the rectangle
541      * @param y2 the Y co-ordinate of the second corner of the rectangle
542      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
543      */

544     public void drawRectangle(float x1, float y1, float x2, float y2)
545     {
546     page.drawRectangle(cx(x1),cy(y1),cx(x2),cy(y2));
547     }
548
549     /**
550      * <p>
551      * Draw a rectangle between the two corners (x1,y1) and
552      * (x2,y2). The corners of the rectangle are rounded, the
553      * radius of the corner arcs is specified by the parameter
554      * <code>r</code>.
555      * </p>
556      * <p>
557      * Whether the rectangle is drawn as an outline or filled depends
558      * the current style (see the {@link #pathPaint} method for more
559      * information).
560      * </p>
561      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
562      * @param x1 the X co-ordinate of the first corner of the rectangle
563      * @param y1 the Y co-ordinate of the first corner of the rectangle
564      * @param x2 the X co-ordinate of the second corner of the rectangle
565      * @param y2 the Y co-ordinate of the second corner of the rectangle
566      * @param r The radius of the circle used to round the corners. A value
567      * of zero produces an identical result to <code>drawRectangle</code>.
568      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
569      * @since 1.1
570      */

571     public void drawRoundedRectangle(float x1, float y1, float x2, float y2, float r)
572     {
573     page.drawRoundedRectangle(cx(x1),cy(y1),cx(x2),cy(y2),r);
574     }
575
576
577     /**
578      * <p>
579      * Draw a polygon. The X and Y co-ordinates of the vertices are
580      * in the supplied arrays. Whether the polygon is drawn as an
581      * outline or filled depends on the <code>LineColor</code> and
582      * <code>FillColor</code> of the current style (see the
583      * {@link #pathPaint} method for more information).
584      * </p>
585      * <p>
586      * (The resulting shape isn't a true polygon, in that it doesn't
587      * have to be closed, but we felt that <code>drawPolygon</code>
588      * was catchier than <code>drawSequenceOfLineSegments</code>.)
589      * </p>
590      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
591      * @param x the X co-ordinates of the vertices
592      * @param y the Y co-ordinates of the vertices
593      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
594      */

595     public void drawPolygon(float[] x, float[] y)
596     {
597     float[] x2 = new float[x.length];
598     float[] y2 = new float[y.length];
599     for (int i=0;i<x.length;i++) x2[i]=cx(x[i]);
600     for (int i=0;i<y.length;i++) y2[i]=cy(y[i]);
601     
602     page.drawPolygon(x2, y2);
603     }
604
605
606     /**
607      * <p>
608      * Draw an ellipse inside the specified rectangle. To
609      * draw a circle centered on 300,200 with a radius of
610      * 50, the invocation would be
611      * <code>drawEllipse(250,150,350,250)</code>. (<i>since
612      * 1.1 this is a contrived example - it's easier to call
613      * <code>drawCircle</code>)</i>
614      * </p>
615      * <p>
616      * Whether the ellipse is drawn as an outline or filled depends on the
617      * <code>LineColor</code> and <code>FillColor</code> of the current style
618      * (see the {@link #pathPaint} method for more information).
619      * </p>
620      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
621      * @param x1 the X co-ordinate of the first corner of the rectangle
622      * @param y1 the Y co-ordinate of the first corner of the rectangle
623      * @param x2 the X co-ordinate of the second corner of the rectangle
624      * @param y2 the Y co-ordinate of the second corner of the rectangle
625      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
626      */

627     public void drawEllipse(float x1, float y1, float x2, float y2)
628     {
629     page.drawEllipse(cx(x1), cy(y1), cx(x2), cy(y2));
630     }
631
632
633     /**
634      * Draw a circle centered on <code>x</code>, <code>y</code>
635      * with a radius of <code>r</code>. A more convenient way to
636      * draw circles than with <code>drawEllipse</code>.
637      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
638      * @param x the X co-ordinate of the center of the circle
639      * @param y the Y co-ordinate of the center of the circle
640      * @param r the radius of the circle
641      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
642      * @since 1.1
643      */

644     public void drawCircle(float x, float y, float r)
645     {
646     page.drawEllipse(cx(x-r), cy(y-r), cx(x+r), cy(y+r));
647     }
648
649     /**
650      * <p>
651      * Draw an arc inside the specified rectangle. The same as
652      * <code>drawEllipse</code>, but allows you to specify a start
653      * and end angle, and the line is always drawn as an outline.
654      * </p>
655      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
656      * @param x1 the X co-ordinate of the first corner of the rectangle
657      * @param y1 the Y co-ordinate of the first corner of the rectangle
658      * @param x2 the X co-ordinate of the second corner of the rectangle
659      * @param y2 the Y co-ordinate of the second corner of the rectangle
660      * @param start the angle to start the arc, in degrees clockwise
661      * (with zero at 12 o'clock)
662      * @param end the angle to end the arc, in degrees
663      * @since 1.1
664      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
665      */

666     public void drawEllipseArc(float x1, float y1, float x2, float y2, float start, float end)
667     {
668     page.drawEllipseArc(cx(x1),cy(y1),cx(x2),cy(y2),start,end);
669     }
670
671     /**
672      * Draw an arc of the circle centered on
673      * <code>x</code>, <code>y</code> with a radius
674      * of <code>r</code>. A more convenient way to
675      * draw circular arcs than <code>drawEllipseArc</code>.
676      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
677      * @param x the X co-ordinate of the center of the circle
678      * @param y the Y co-ordinate of the center of the circle
679      * @param start the angle to start the arc, in degrees clockwise
680      * (with zero at 12 o'clock)
681      * @param end the angle to end the arc, in degrees
682      * @since 1.1
683      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
684      */

685     public void drawCircleArc(float x, float y, float r, float start, float end)
686     {
687     page.drawEllipseArc(cx(x-r),cy(y-r),cx(x+r),cy(y+r),start,end);
688     }
689
690
691     /**
692      * Start a new path at the specified position. If a path has
693      * already been started, move the cursor without drawing a line.
694      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
695      * @param x the X co-ordinate to move to
696      * @param y the Y co-ordinate to move to
697      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
698      */

699     public void pathMove(float x, float y)
700     {
701     page.pathMove(cx(x),cy(y));
702     }
703
704     /**
705      * Continue the path in a straight line to the specified point
706      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
707      * @param x the X co-ordinate to move to
708      * @param y the Y co-ordinate to move to
709      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
710      */

711     public void pathLine(float x, float y)
712     {
713     page.pathLine(cx(x),cy(y));
714     }
715
716     /**
717      * Continue the path in a bezier curve to the specified point.
718      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
719      * @param cx1 the X co-ordinate of the first control point for the curve
720      * @param cy1 the Y co-ordinate of the first control point for the curve
721      * @param cx2 the X co-ordinate of the second control point for the curve
722      * @param cy2 the Y co-ordinate of the second control point for the curve
723      * @param x the X co-ordinate to move to
724      * @param y the Y co-ordinate to move to
725      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
726      */

727     public void pathBezier(float cx1, float cy1, float cx2, float cy2, float x, float y)
728     {
729     page.pathBezier(cx(cx1),cy(cy1),cx(cx2),cy(cy2),cx(x),cy(y));
730     }
731
732     /**
733      * Continue the path in an arc
734      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
735      * @param width the width of the ellipse to take the arc from
736      * @param height the height of the ellipse to take the arc from
737      * @param start the angle to start the arc from, in degrees clockwise
738      * @param end the angle to finish the arc on, in degrees clockwise
739      * @since 1.1
740      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
741      */

742     public void pathArc(float width, float height, float start, float end)
743     {
744     page.pathArc(width,height,start,end);
745     }
746
747     /**
748      * Close the path by drawing a straight line back to its beginning.
749      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
750      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
751      */

752     public void pathClose()
753     {
754     page.pathClose();
755     }
756
757     /**
758      * Cancel the current path.
759      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
760      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
761      */

762     public void pathCancel()
763     {
764     page.pathCancel();
765     }
766
767     /**
768      * Paint the path. What this actually does depends on the currently
769      * applied <code>PDFStyle</code>.
770      * <ul>
771      * <li>If the style has a LineColor specified but no FillColor, "stroke"
772      * the path by drawing it as an outline in the current line color</li>
773      * <li>If the style has a FillColor specified but no LineColor, call
774      * {@link #pathClose} and "fill" the path with the current fill color</li>
775      * <li>If the style has both a FillColor and a LineColor, call {@link
776      * #pathClose}, "fill" the path with the current fill color then "stroke"
777      * the path with the current line color.</li>
778      * </ul>
779      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
780      * @throws IllegalStateException if neither a fill color or a line color
781      * is specified.
782      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
783      */

784     public void pathPaint()
785     {
786     page.pathPaint();
787     }
788
789     /**
790      * Allows the path to be painted and used to set the clipping area
791      * in one operation. See the {@link #pathPaint} and {@link #pathClip}
792      * methods for more information
793      * @since 1.1.10
794      */

795     public void pathClipAndPaint()
796     {
797     page.pathClipAndPaint();
798     }
799
800     /**
801      * <p>
802      * Set the "clipping area" of the page to be the intersection of
803      * the current clipping area and the shape defined by this path.
804      * Any future graphics or text operations on the page are only
805      * applied within this area.
806      * </p><p>
807      * There is no way to enlarge the current clipping area, or to set
808      * a new clipping area without reference to the current one. However,
809      * as the current clipping area is part of the graphics state, it
810      * can and should be nested inside calls to {@link #save} and
811      * {@link #restore} to limit its effect.
812      * </p>
813      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
814      * @since 1.1.5
815      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
816      */

817     public void pathClip()
818     {
819     page.pathClip();
820     }
821
822     /**
823      * <p>
824      * Identical to {@link #drawRectangle}, but instead of drawing this
825      * method sets the clipping area to the specified rectangle
826      * </p><p>
827      * There is no way to enlarge the current clipping area, or to set
828      * a new clipping area without reference to the current one. However,
829      * as the current clipping area is part of the graphics state, it
830      * can and should be nested inside calls to {@link #save} and
831      * {@link #restore} to limit its effect.
832      * </p>
833      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
834      * @param x1 the X co-ordinate of the first corner of the rectangle
835      * @param y1 the Y co-ordinate of the first corner of the rectangle
836      * @param x2 the X co-ordinate of the second corner of the rectangle
837      * @param y2 the Y co-ordinate of the second corner of the rectangle
838      * @since 1.1.5
839      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
840      */

841     public void clipRectangle(float x1, float y1, float x2, float y2)
842     {
843     page.clipRectangle(cx(x1),cy(y1),cx(x2),cy(y2));
844     }
845
846
847     /**
848      * <p>
849      * Identical to {@link #drawRoundedRectangle}, but instead of drawing this
850      * method sets the clipping area to the specified shape
851      * </p><p>
852      * There is no way to enlarge the current clipping area, or to set
853      * a new clipping area without reference to the current one. However,
854      * as the current clipping area is part of the graphics state, it
855      * can and should be nested inside calls to {@link #save} and
856      * {@link #restore} to limit its effect.
857      * </p>
858      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
859      * @param x1 the X co-ordinate of the first corner of the rectangle
860      * @param y1 the Y co-ordinate of the first corner of the rectangle
861      * @param x2 the X co-ordinate of the second corner of the rectangle
862      * @param y2 the Y co-ordinate of the second corner of the rectangle
863      * @param r The radius of the circle used to round the corners. A value
864      * of zero produces an identical result to <code>clipRectangle</code>.
865      * @since 1.1.5
866      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
867      */

868     public void clipRoundedRectangle(float x1, float y1, float x2, float y2, float r)
869     {
870     page.clipRoundedRectangle(cx(x1),cy(y1),cx(x2),cy(y2),r);
871     }
872
873     /**
874      * <p>
875      * Identical to {@link #drawPolygon}, but instead of drawing this
876      * method sets the clipping area to the specified shape.
877      * </p><p>
878      * There is no way to enlarge the current clipping area, or to set
879      * a new clipping area without reference to the current one. However,
880      * as the current clipping area is part of the graphics state, it
881      * can and should be nested inside calls to {@link #save} and
882      * {@link #restore} to limit its effect.
883      * </p>
884      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
885      * </p>
886      * @param x the X co-ordinates of the vertices
887      * @param y the Y co-ordinates of the vertices
888      * @since 1.1.5
889      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
890      */

891     public void clipPolygon(float[] x, float[] y)
892     {
893     float[] x2 = new float[x.length];
894     float[] y2 = new float[y.length];
895     for (int i=0;i<x.length;i++) x2[i]=cx(x[i]);
896     for (int i=0;i<y.length;i++) y2[i]=cy(y[i]);
897
898     page.clipPolygon(x2,y2);
899     }
900
901     /**
902      * <p>
903      * Identical to {@link #drawEllipse}, but instead of drawing this
904      * method sets the clipping area to the specified shape
905      * </p><p>
906      * There is no way to enlarge the current clipping area, or to set
907      * a new clipping area without reference to the current one. However,
908      * as the current clipping area is part of the graphics state, it
909      * can and should be nested inside calls to {@link #save} and
910      * {@link #restore} to limit its effect.
911      * </p>
912      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
913      * @param x1 the X co-ordinate of the first corner of the rectangle
914      * @param y1 the Y co-ordinate of the first corner of the rectangle
915      * @param x2 the X co-ordinate of the second corner of the rectangle
916      * @param y2 the Y co-ordinate of the second corner of the rectangle
917      * @since 1.1.5
918      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
919      */

920     public void clipEllipse(float x1, float y1, float x2, float y2)
921     {
922     page.clipEllipse(cx(x1),cy(y1),cx(x2),cy(y2));
923     }
924
925     /**
926      * <p>
927      * Identical to {@link #drawCircle}, but instead of drawing this
928      * method sets the clipping area to the specified shape
929      * </p><p>
930      * There is no way to enlarge the current clipping area, or to set
931      * a new clipping area without reference to the current one. However,
932      * as the current clipping area is part of the graphics state, it
933      * can and should be nested inside calls to {@link #save} and
934      * {@link #restore} to limit its effect.
935      * </p>
936      * <p>Calls to this method can't be made between calls to <tt>beginText</tt> and <tt>endText</tt>, as this violates the PDF specification. Since 1.1.6 An <tt>IllegalStateException</tt> will be thrown.
937      * @param x the X co-ordinate of the center of the circle
938      * @param y the Y co-ordinate of the center of the circle
939      * @param r the radius of the circle
940      * @since 1.1.5
941      * @throws IllegalStateException if the call is nested between a call to <tt>beginText</tt> and <tt>endText</tt>
942      */

943     public void clipCircle(float x, float y, float r)
944     {
945     page.clipCircle(cx(x),cy(y),r);
946     }
947
948     /**
949      * <p>
950      * Save the state of this page. This takes a snapshot of the
951      * currently applied style, position, clipping area and any
952      * rotation/translation/scaling that has been applied, which can
953      * be later restored with a call to {@link #restore} or undone
954      * with a call to {@link #undo}.
955      * </p><p>
956      * Calls to <code>save</code> can be nested, but note that for
957      * most PDF viewers it is an error to save the page state but
958      * not restore it. The <tt>save()</tt> method now saves the
959      * entire state of the style.
960      * </p><p>
961      * Since version 1.1, additional restrictions have been placed
962      * on the <code>save</code> and <code>restore</code> methods.
963      * <li>They can only be nested 28 deep</li>
964      * <li>They cannot be called betweem a <code>pathMove</code>
965      * and a <code>pathPaint</code> or <code>pathCancel</code> call, or
966      * between <code>beginText</code> and <code>endText</code>. This
967      * is because in PDF (unlike its parent PostScript), save does <i>not</i>
968      * save path information.</li>
969      * This ties in more accurately with the PDF specification.
970      * </p>
971      *
972      * @throws IllegalStateException if a save is performed between a
973      * call to <code>beginText</code> and <code>endText</code>, if there
974      * is an open path, or if saves are nested more than 12 deep.
975      */

976     public void save()
977     {
978     page.save();
979     statestack.push(state);
980     }
981
982     /**
983      * <p>
984      * Restore the state saved with the last call to {@link #save}.
985      * </p>
986      * @throws IllegalStateException if the state wasn't previously saved
987      */

988     public void restore()
989     {
990     page.restore();
991     state = (State)statestack.pop();
992     }
993
994     /**
995      * <p>
996      * Undo the page to the state at the last call to <code>save()</code>
997      * </p>
998      * @throws IllegalStateException if the state wasn't previously saved
999      * </p>
1000     * @since 1.1
1001     */

1002    public void undo()
1003    {
1004    throw new UnsupportedOperationException JavaDoc("The undo() method has been removed in version 2 with no replacement. You'll need to rewrite your code or stick with version 1");
1005    }
1006
1007
1008    /**
1009     * <p>
1010     * Rotate the page. All future actions, like drawing lines or text,
1011     * will be rotated around the specified point by the specified degrees.
1012     * </p>
1013     * @param x the X co-ordinate to rotate the page around
1014     * @param y the Y co-ordinate to rotate the page around
1015     * @param ang The number of degrees clockwise to rotate the page.
1016     */

1017    public void rotate(float x, float y, double ang)
1018    {
1019    page.rotate(cx(x),cy(y), ang);
1020    }
1021
1022    /**
1023     * <p>
1024     * Translate the page by the specified amount.
1025     * All future actions, like drawing lines or text,
1026     * will be offset by the specified amount.
1027     * </p>
1028     * @param x the distance to translate the page in the X axis
1029     * @param y the distance to translate the page in the Y axis
1030     */

1031    public void translate(float x, float y)
1032    {
1033    state.translatex += x*state.scalex;
1034    state.translatey += y*state.scaley;
1035    }
1036
1037    /**
1038     * <p>
1039     * Scale the page by the specified amount.
1040     * All future actions, like drawing lines or text,
1041     * will be scaled in both directions by the specified amounts.
1042     * </p>
1043     * @param x the scaling factor to apply in the X axis, with 1.0 being no change
1044     * @param y the scaling factor to apply in the Y axis, with 1.0 being no change
1045     */

1046    public void scale(float x, float y)
1047    {
1048    if (x*y==0) throw new IllegalArgumentException JavaDoc("X or Y is zero");
1049    state.scalex *= x;
1050    state.scaley *= y;
1051    }
1052
1053    /**
1054     * <p>
1055     * Set the action to perform when this page is displayed. This
1056     * method is conceptually similar to the method with the same name in
1057     * the {@link PDF} object, except that whereas that is run once when the
1058     * document is opened, this is run each time the page is displayed.
1059     * </p>
1060     * @param action the action to run each time this page is displayed, or
1061     * <code>null</code> to clear the action
1062     * @since 1.1
1063     */

1064    public void setOpenAction(PDFAction action)
1065    {
1066    page.setAction(org.faceless.pdf2.Event.OPEN, action==null ? null : action.action);
1067    }
1068
1069    /**
1070     * <p>
1071     * Set the action to perform when this page is closed. The opposite
1072     * of the <code>setOpenAction</code> method, this action will be
1073     * run each time the page is closed, either by closing the document
1074     * or by moving to another page.
1075     * </p>
1076     * @param action the action to run each time this page is closed, or
1077     * <code>null</code> to clear the action
1078     * @since 1.1
1079     */

1080    public void setCloseAction(PDFAction action)
1081    {
1082    page.setAction(org.faceless.pdf2.Event.CLOSE, action==null ? null : action.action);
1083    }
1084
1085    /**
1086     * <p>
1087     * Get the action that's perform when this page is displayed. This is
1088     * the value set by the {@link #setOpenAction} method.
1089     * @return the action performed whenever this page is displayed, or <tt>null</tt>
1090     * if no action is performed.
1091     * @since 1.1.12
1092     */

1093    public PDFAction getOpenAction()
1094    {
1095    return (PDFAction)PeeredObject.getPeer(page.getAction(org.faceless.pdf2.Event.OPEN));
1096    }
1097
1098    /**
1099     * <p>
1100     * Get the action that's perform when this page is displayed. This is
1101     * the value set by the {@link #setOpenAction} method.
1102     * @return the action performed whenever this page is displayed, or <tt>null</tt>
1103     * if no action is performed.
1104     * @since 1.1.12
1105     */

1106    public PDFAction getCloseAction()
1107    {
1108    return (PDFAction)PeeredObject.getPeer(page.getAction(org.faceless.pdf2.Event.CLOSE));
1109    }
1110
1111
1112    /**
1113     * <p>
1114     * Set the filter to be applied to this page. The default filter is set to
1115     * {@link #FILTER_FLATE}, but it can be set to {@link #FILTER_NONE}
1116     * to simplify debugging.
1117     * </p>
1118     * @param filter the filter to be applied to the page {@link PDFStream}
1119     */

1120    public void setFilter(int filter)
1121    {
1122        // NOOP
1123
}
1124
1125    /**
1126     * <p>
1127     * Add an annotation to the page.
1128     * </p>
1129     * @see PDFAnnotation
1130     * @since 1.1
1131     */

1132    public void addAnnotation(PDFAnnotation annotation)
1133    {
1134    page.getAnnotations().add(annotation.annot);
1135    }
1136
1137    /**
1138     * Remove the specified annotation from the page. If
1139     * the annotation is not on this page, this method
1140     * has no effect
1141     * @since 1.1.23
1142     */

1143    public void removeAnnotation(PDFAnnotation annotation)
1144    {
1145    page.getAnnotations().remove(annotation.annot);
1146    }
1147
1148    /**
1149     * Return a list of all the annotations on this page. If no
1150     * annotations exist, this returns a list of zero length.
1151     * @return the list of annotations on this page
1152     * @since 1.1.12
1153     */

1154    public PDFAnnotation[] getAnnotations()
1155    {
1156    List l = page.getAnnotations();
1157    PDFAnnotation[] z = new PDFAnnotation[l.size()];
1158    for (int i=0;i<z.length;i++) {
1159        z[i]=(PDFAnnotation)PeeredObject.getPeer(l.get(i));
1160    }
1161    return z;
1162    }
1163
1164    /**
1165     * <p>
1166     * Seek to the start of the page. Any items drawn after this call
1167     * will be drawn before any content already existing on the page, so
1168     * appearing under the current content.
1169     * </p><p>
1170     * This method will throw an <tt>IllegalStateException</tt> if called
1171     * while a path is open or between calls to <tt>beginText</tt> and
1172     * <tt>endText</tt>.
1173     * </p>
1174     * <p>
1175     * Note that if the document clears the page before writing, it will
1176     * overwrite any content written after a <tt>seetkStart</tt>
1177     * </p>
1178     * @since 1.1.12
1179     */

1180    public void seekStart()
1181    {
1182    page.seekStart();
1183    }
1184
1185    /**
1186     * <p>
1187     * Seek to the end of the page. Any items drawn after this call
1188     * will be drawn after any content already existing on the page, so
1189     * appearing above the current content. This is the default.
1190     * </p><p>
1191     * This method will throw an <tt>IllegalStateException</tt> if called
1192     * while a path is open or between calls to <tt>beginText</tt> and
1193     * <tt>endText</tt>.
1194     * </p>
1195     * @since 1.1.12
1196     */

1197    public void seekEnd()
1198    {
1199    page.seekEnd();
1200    }
1201
1202
1203    /**
1204     * <p>
1205     * Draw a <code>PDFImage</code> on the page at the specified location. The
1206     * aspect-ratio of the image is dependent on the with and height of the
1207     * rectangle given here, <i>not</i> the width and height of the original
1208     * image. To avoid distorting the aspect ratio, the method can be called
1209     * like so:
1210     * <pre>drawImage(img, 100, 100, 100+img.getWidth(), 100+img.getHeight());</pre>
1211     * </p>
1212     *
1213     * @param image The image to draw
1214     * @param x1 the X co-ordinate of the first corner of the image
1215     * @param y1 the Y co-ordinate of the first corner of the image
1216     * @param x2 the X co-ordinate of the second corner of the image
1217     * @param y2 the Y co-ordinate of the second corner of the image
1218     *
1219     */

1220    public void drawImage(PDFImage image, float x1, float y1, float x2, float y2)
1221    {
1222    page.drawImage(image.image,cx(x1),cy(y1),cx(x2),cy(y2));
1223    }
1224
1225    /**
1226     * <p>
1227     * Change the text in the supplied string to use the "correct" quote characters - i.e.
1228     * for English change "test" to ``test'', for German change it to ,,test`` and so on.
1229     * </p>
1230     * <p>
1231     * Exactly what substitution takes place depends on the current locale of the PDF
1232     * document. We've taken the definition of "correct" from the Unicode standard,
1233     * version 3.0 (in the event that either they or (more likely) us have got it wrong,
1234     * please let us know). The current implementation has rules for English, Dutch,
1235     * Italian, Spanish, Catalan, German, Portugese, Turkish, Polish, Hungarian, Swedish,
1236     * Finnish, Norwegian, Danish, Czech and Slovak. Languages using guillemets for
1237     * quotes (French, Greek, Russian and Slovenian) are not covered, as it's expected that
1238     * the guillemet characters will be used in place of the normal single (') and double
1239     * (") quote characters.
1240     * </p>
1241     * <p>
1242     * Please note the substitution will <i>only</i> take place if the current styles' font
1243     * has the required characters defined. The 14 standard fonts do, and most others
1244     * should.
1245     * </p>
1246     * <p>
1247     * Finally, the algorithm isn't perfect - it's more likely to work if spaces are placed
1248     * before opening quotes, and closing quotes are followed by a space or punctuation.
1249     * If it's still making mistakes, you can prevent a quote from being "turned" by
1250     * surrounding the character with U+200C (zero-width non-joiner) characters.
1251     * </p>
1252     * @param text the text to substitute
1253     * @return the passed in string with the appropriate quote characters for the Locale
1254     * in place of characters single quote (', 0x27) and double quote (", 0x22)
1255     * @since 1.1
1256     */

1257    public String JavaDoc requote(String JavaDoc text)
1258    {
1259    char[] c = text.toCharArray();
1260    // TODO - find proper locale
1261
PDFStyle style = getStyle();
1262        if (style!=null && style.getFont()!=null && style.getFont().requote(c,0,c.length, Locale.getDefault())) {
1263        return new String JavaDoc(c,0,c.length);
1264    } else {
1265        return text;
1266    }
1267    }
1268
1269    /**
1270     * <p>
1271     * Draw a barcode at the specified position. The type of barcode
1272     * is specified by the <code>type</code> parameter, and may be
1273     * one of {@link #BARCODE39}, {@link #BARCODE39CHECKSUM},
1274     * {@link #BARCODE39X}, {@link #BARCODE39XCHECKSUM},
1275     * {@link #BARCODE25}, {@link #BARCODE25CHECKSUM},
1276     * {@link #BARCODE128}, {@link #BARCODEEAN13} or {@link #BARCODECODABAR}.
1277     * Each of these algorithms has restrictions on what characters
1278     * can be displayed, and an exception is thrown if an illegal
1279     * character is given.
1280     * </p><p>
1281     * The width of the resulting barcode in points is returned.
1282     * The height of the barcode is 15% of the width, with a
1283     * minimum height of 18 points. If text is displayed, you can
1284     * add another <code>(8*width)</code> points to the height.
1285     * </p><p>
1286     * @param type the type of barcode to print
1287     * @param code the string to print
1288     * @param x the left-most position of the barcode on the page
1289     * @param y the vertical center of the barcode on the page
1290     * @param showtext whether to show the human-readable equivalent
1291     * of the barcode immediately beneath the code
1292     * @param width the width of the thinnest bar in points. Acceptable
1293     * values depend on your scanner. The recommended minimum is 0.54
1294     * points, or 0.0075 inches (0.19mm). If in doubt, use "1".
1295     * @return the width of the resulting barcode, in points
1296     * @throws IllegalArgumentException if the characters or the barcode
1297     * type is invalid
1298     * @since 1.1.5
1299     */

1300    public float drawBarCode(int type, String JavaDoc code, float x, float y, boolean showtext, float width)
1301        throws IllegalArgumentException JavaDoc
1302    {
1303        return drawBarCode(type, code, cx(x), cy(y), showtext, width, 18, 2.8f);
1304    }
1305
1306    /**
1307     * <p>
1308     * Draw a barcode at the specified position. Identical to the other
1309     * barcode routine, but allows two extra properties to be specified
1310     * for full control over the resulting code - the <code>height</code>,
1311     * which is the height of the barcode in points, and the <code>ratio</code>,
1312     * which is the thickbar/thinbar ratio for those codes that only use
1313     * two bar widths (CODE39 and CODE25).
1314     * </p><p>
1315     * The specified height will always be rounded up to 18 points or 15% of the
1316     * width of the barcode, whichever is greater.
1317     * </p><p>
1318     * The ratio should always be 2.0 and 3.0 - the default is 2.8. For most
1319     * algorithms, if the thinnest bar has a width of less than 1.5 points
1320     * then the ratio should be between 2.0 and 2.2.
1321     * </p>
1322     * @param type the type of barcode to print
1323     * @param code the string to print
1324     * @param x the left-most position of the barcode on the page
1325     * @param y the vertical center of the barcode on the page
1326     * @param showtext whether to show the human-readable equivalent
1327     * of the barcode immediately beneath the code
1328     * @param width the width of the thinnest bar in points. Acceptable
1329     * values depend on your scanner. The recommended minimum is 0.54
1330     * points, or 0.0075 inches (0.19mm). If in doubt, use "1"
1331     * @param height the height of the barcode in points. Minimum value is 18
1332     * @param ratio the ratio of the thickest bar in the barcode to the thinnest,
1333     * if applicable. Valid values are between 2.0 and 3.0. For multiple-width
1334     * codes like Code128, this is ignored. If in doubt, try "2.8"
1335     * @return the width of the resulting barcode, in points
1336     * @throws IllegalArgumentException if the characters or the barcode
1337     * type is invalid
1338     * @since 1.1.13
1339     */

1340    public float drawBarCode(int type, String JavaDoc code, float x, float y, boolean showtext, float width, int height, float ratio)
1341        throws IllegalArgumentException JavaDoc
1342    {
1343    int newtype;
1344    if (type==BARCODE39) newtype=org.faceless.pdf2.BarCode.CODE39;
1345    else if (type==BARCODE39CHECKSUM) newtype=org.faceless.pdf2.BarCode.CODE39_CHECKSUM;
1346    else if (type==BARCODE39X) newtype=org.faceless.pdf2.BarCode.CODE39X;
1347    else if (type==BARCODE39XCHECKSUM) newtype=org.faceless.pdf2.BarCode.CODE39X_CHECKSUM;
1348    else if (type==BARCODE25) newtype=org.faceless.pdf2.BarCode.INTERLEAVED25;
1349    else if (type==BARCODE25CHECKSUM) newtype=org.faceless.pdf2.BarCode.INTERLEAVED25_CHECKSUM;
1350    else if (type==BARCODE128) newtype=org.faceless.pdf2.BarCode.CODE128;
1351    else if (type==BARCODEEAN13) newtype=org.faceless.pdf2.BarCode.EAN13;
1352    else if (type==BARCODEUPCA) newtype=org.faceless.pdf2.BarCode.UPCA;
1353    else if (type==BARCODECODABAR) newtype=org.faceless.pdf2.BarCode.CODABAR;
1354    else throw new IllegalArgumentException JavaDoc("Unknown barcode type");
1355
1356    org.faceless.pdf2.BarCode codeo = new org.faceless.pdf2.BarCode(type, code);
1357    codeo.setShowText(showtext);
1358    codeo.setBarWidth(width);
1359    codeo.setHeight(height);
1360    codeo.setBarRatio(ratio);
1361
1362    float barwidth=codeo.getWidth();
1363    float fontheight = (showtext ? width*8 : 0)*1.25f;
1364    float barheight=height+fontheight;
1365
1366    page.drawBarCode(codeo, cx(x), cy(y)+(barheight/2)-(fontheight/2), cx(x)+barwidth, cy(y)-(barheight/2)-(fontheight/2));
1367    return barwidth;
1368    }
1369
1370    /**
1371     * Set the XML metadata associated with this object. See
1372     * {@link PDF#setMetaData} for more information.
1373     * @param xmldata the XML data to embed into the document, or <tt>null</tt> to clear any existing metadata. No validation is performed on this input.
1374     * @since 1.1.12
1375     */

1376    public void setMetaData(String JavaDoc xmldata)
1377    {
1378    page.setMetaData(xmldata);
1379    }
1380
1381    /**
1382     * Return any XML metadata associated with this object. See the
1383     * {@link PDF#getMetaData} for more information
1384     * @return a {@link java.io.Reader} containing the source of the XML or <tt>null</tt> if no metadata is available.
1385     * @throws IOException if the metadata can't be extracted
1386     * @since 1.1.12
1387     */

1388    public Reader getMetaData()
1389        throws IOException
1390    {
1391    return page.getMetaData();
1392    }
1393
1394    /**
1395     * <p>
1396     * Add the contents of the specified page to this page, at the specified
1397     * position. The page to be added is treated in a similar way to an image
1398     * in the {@link #drawImage} method - it's scaled to fit the specified
1399     * rectangle, but it's up to the user to preserve the original aspect ratio.
1400     * </p><p>
1401     * It is anticipated that this method will be used with the {@link PDFReader}
1402     * class to allow pages to stitched together, overlaid, changed from
1403     * Letter to A4 and so on.
1404     * </p>
1405     * <p>
1406     * Here's an example showing two pages being placed next to eachother in a
1407     * "2-up" layout.
1408     * </p>
1409     * <pre>
1410     * void drawTwoUp(PDFPage page1, PDFPage page2, PDFPage dest)
1411     * {
1412     * dest.setCanvas(0,0,dest.getWidth(),dest.getHeight(), PDFPage.PERCENT, PDFPage.PAGETOP);
1413     * dest.drawPage(page1, 0, 0, 50, 100); // from (0%,0%) to (50%,100%)
1414     * dest.drawPage(page2, 50, 0, 100, 100); // from (50%,0%) to (100%,100%)
1415     * }
1416     * </pre>
1417     * <b>Note</b>. For simply copying pages from one document to another, it's
1418     * <i>considerably</i> faster, and easier, to join the two pages together by
1419     * manipulating the list of pages returned from {@link PDF#getPages}.
1420     *
1421     * @param page The page whose contents are to be drawn onto this page
1422     * @param x1 the X co-ordinate of the first corner of the image
1423     * @param y1 the Y co-ordinate of the first corner of the image
1424     * @param x2 the X co-ordinate of the second corner of the image
1425     * @param y2 the Y co-ordinate of the second corner of the image
1426     *
1427     * @since 1.1.12
1428     */

1429    public void drawPage(PDFPage page, float x1, float y1, float x2, float y2)
1430    {
1431        page.page.flush();
1432    org.faceless.pdf2.PDFCanvas canvas = new org.faceless.pdf2.PDFCanvas(page.page);
1433    this.page.drawCanvas(canvas, cx(x1), cy(y1), cx(x2), cy(y2));
1434
1435    if (page.page.getAnnotations().size()>0) {
1436        org.faceless.pdf2.PDFPage clone = new org.faceless.pdf2.PDFPage(page.page);
1437
1438        x1 = canvasx(x1);
1439        y1 = canvasy(y1);
1440        x2 = canvasx(x2);
1441        y2 = canvasy(y2);
1442        if (x1>x2) { float t=x1; x1=x2; x2=t; }
1443        if (y1>y2) { float t=y1; y1=y2; y2=t; }
1444
1445// System.err.println("clone="+clone);
1446
List annots = clone.getAnnotations();
1447        for (int i=0;i<annots.size();i++) {
1448        org.faceless.pdf2.PDFAnnotation annot = (org.faceless.pdf2.PDFAnnotation)annots.get(i);
1449        float[] f = annot.getRectangle();
1450        if (f!=null) {
1451// System.err.println("page="+page.getWidth()+"x"+page.getHeight()+" x1="+x1+" y1="+y1+" x2="+x2+" y2="+y2);
1452
// System.err.println("WAS F="+f[0]+","+f[1]+"-"+f[2]+","+f[3]);
1453
f[0] = (f[0]/clone.getWidth()*(x2-x1))+x1;
1454            f[1] = (f[1]/clone.getHeight()*(y2-y1))+y1;
1455            f[2] = (f[2]/clone.getWidth()*(x2-x1))+x1;
1456            f[3] = (f[3]/clone.getHeight()*(y2-y1))+y1;
1457
1458            annot.setRectangle(f[0], f[1], f[2], f[3]);
1459// System.err.println("NOW F="+f[0]+","+f[1]+"-"+f[2]+","+f[3]);
1460
}
1461        this.page.getAnnotations().add(annot);
1462        }
1463    }
1464    }
1465
1466    /**
1467     * <p>
1468     * Draw a line of text at the specified position. A simple way to draw
1469     * a single line of text. The co-ordinates specify the position of the
1470     * baseline of the first character - for other positions (e.g. to align
1471     * the top of the text), adjust the co-ordinates by the return value from
1472     * {@link PDFStyle#getTextTop} and friends.
1473     * </p>
1474     * @param text the line of text to draw
1475     * @param x the X co-ordinate to draw the text at
1476     * @param y the Y co-ordinate to draw the text at
1477     */

1478    public void drawText(String JavaDoc text, float x, float y)
1479    {
1480    page.drawText(text,cx(x),cy(y));
1481    }
1482
1483    /**
1484     * <p>
1485     * Draw a line of text at a the specified position, and set it to
1486     * link to the specified action. A shorthand combination of
1487     * <code>drawText</code> and <code>beginTextLink</code>.
1488     * </p><p>
1489     * <i>Note that this method will not work as advertised if the position
1490     * of the text has been modified via the <code>rotate</code>, <code>scale</code>
1491     * or <code>translate</code> methods. This is a shortcoming inherent in
1492     * the PDF document specification</i>. See the {@link PDFAnnotation} class
1493     * documentation for more information.
1494     * </p>
1495     * @param text the line of text to draw
1496     * @param x the X co-ordinate to draw the text at
1497     * @param y the Y co-ordinate to draw the text at
1498     * @param action the action to perform when the text is clicked on
1499     * @since 1.1
1500     */

1501    public void drawTextLink(String JavaDoc text, float x, float y, PDFAction action)
1502    {
1503    page.drawTextLink(text,cx(x),cy(y),action.action);
1504    }
1505
1506    /**
1507     * <p>
1508     * Begin a paragraph of text. The parameters specify the rectangle
1509     * measured in the current canvas units that will fully contain the text.
1510     * Left-to-right text will wrap when it reaches the right margin and
1511     * continue being rendered until the bottom margin is reached, after which
1512     * the text will not be rendered and all calls to <code>drawText</code>
1513     * will return -1. This "overflowed" text can be rendered in a new block
1514     * by calling <code>continueText</code>
1515     * </p>
1516     * <p><b>Note:</b> The <code>beginText</code>/<code>drawText</code>/<code>endText</code>
1517     * methods date from the 1.0 release of the PDF library, and while they
1518     * are suitable for simple text layout, more complex layout is best done
1519     * with the {@link LayoutBox} class. In particular these methods have issues
1520     * with the height calculations of text, and with what to do when the box
1521     * defined by <code>beginText</code> is full.
1522     * </p>
1523     *
1524     * @see LayoutBox
1525     * @param x1 the X co-ordinate of the first corner of the text rectangle.
1526     * @param y1 the Y co-ordinate of the first corner of the text rectangle.
1527     * @param x2 the X co-ordinate of the second corner of the text rectangle.
1528     * @param y2 the Y co-ordinate of the second corner of the text rectangle.
1529     * @throws IllegalStateException if beginText has already been called
1530     * (<code>beginText-endText</code> pairs can't be nested).
1531     */

1532    public void beginText(float x1, float y1, float x2, float y2)
1533    {
1534    page.beginText(cx(x1),cy(y1),cx(x2),cy(y2));
1535    }
1536
1537    /**
1538     * <p>
1539     * As for beginText, but continue any text that overflowed from the
1540     * specified page. If the page being continued does not have an
1541     * unclosed <code>beginText</code> call, this method is identical
1542     * to calling <code>beginText</code> on the current page.
1543     * </p><p>
1544     * Since 1.1, this method automatically determines whether the new
1545     * text block should have any leading blank lines trimmed, or whether
1546     * the new block is contiguous with the old one.
1547     * </p>
1548     * <p><b>Note:</b> The <code>beginText</code>/<code>drawText</code>/<code>endText</code>
1549     * methods date from the 1.0 release of the PDF library, and while they
1550     * are suitable for simple text layout, more complex layout is best done
1551     * with the {@link LayoutBox} class. In particular these methods have issues
1552     * with the height calculations of text, and with what to do when the box
1553     * defined by <code>beginText</code> is full.
1554     * </p>
1555     * @see LayoutBox
1556     * @param x1 the X co-ordinate of the first corner of the text rectangle
1557     * @param y1 the Y co-ordinate of the first corner of the text rectangle
1558     * @param x2 the X co-ordinate of the second corner of the text rectangle
1559     * @param y2 the Y co-ordinate of the second corner of the text rectangle
1560     * @param page the page to take the overflowed text from
1561     */

1562    public float continueText(float x1, float y1, float x2, float y2, PDFPage page)
1563    {
1564    return this.page.continueText(cx(x1),cy(y1),cx(x2),cy(y2),page.page);
1565    }
1566
1567    /**
1568     * <p>
1569     * End the paragraph of text
1570     * </p>
1571     * <p><b>Note:</b> The <code>beginText</code>/<code>drawText</code>/<code>endText</code>
1572     * methods date from the 1.0 release of the PDF library, and while they
1573     * are suitable for simple text layout, more complex layout is best done
1574     * with the {@link LayoutBox} class. In particular these methods have issues
1575     * with the height calculations of text, and with what to do when the box
1576     * defined by <code>beginText</code> is full.
1577     * </p>
1578     *
1579     * @param justifylast if the current text style is justified, whether to justify
1580     * the last line of text. If the current style is not justified, this has no effect.
1581     * @return the number of points that needed to be rendered to clear the buffer
1582     * @throws IllegalStateException if beginText wasn't called first
1583     */

1584    public float endText(boolean justifylast)
1585    {
1586    return page.endText(justifylast);
1587    }
1588
1589    /**
1590     * Discard the paragraph of text. This method is identical to <code>endText</code>
1591     * in every way, except no text is actually rendered. This method is useful for
1592     * determining the size of a block of text without displaying it.
1593     * @since 1.0.1
1594     * @return the number of points that would have been rendered to clear the buffer
1595     */

1596    public float discardText()
1597    {
1598    return page.discardText();
1599    }
1600
1601    /**
1602     * <p>
1603     * Draw a paragraph of text in the current styles font, size and color.
1604     * The text is automatically wrapped at the edge of the box specified in
1605     * the call to <code>beginText</code>, and is aligned according to the
1606     * alignment of the current style.
1607     * </p><p>
1608     * If any characters in the string aren't available in the current font,
1609     * they are ignored and a warning message is printed to
1610     * <code>System.err</code>.
1611     * </p><p>
1612     * This method returns -1 if the text can't be displayed in the
1613     * box specified by <code>beginText</code>.
1614     * </p><p>
1615     * The text to be drawn may contain newline characters, which have the
1616     * predictable effect.
1617     * </p>
1618     * <p><b>Note:</b> The <code>beginText</code>/<code>drawText</code>/<code>endText</code>
1619     * methods date from the 1.0 release of the PDF library, and while they
1620     * are suitable for simple text layout, more complex layout is best done
1621     * with the {@link LayoutBox} class. In particular these methods have issues
1622     * with the height calculations of text, and with what to do when the box
1623     * defined by <code>beginText</code> is full.
1624     * </p>
1625     *
1626     * @param text the line of text to be drawn
1627     * @throws IllegalStateException if no font or color is specified,
1628     * or if <code>beginText</code> hasn't been called first.
1629     * @return the number of points required to render the lines to
1630     * the document (zero or more), or -1 if the text box is full.
1631     * @see LayoutBox
1632     * @see PDFEncoding
1633     * @see PDFFont
1634     */

1635    public float drawText(String JavaDoc text)
1636    {
1637    return page.drawText(text);
1638    }
1639
1640    /**
1641     * <p>
1642     * Start a "link" section in the text. Any text displayed between here
1643     * and the corresponding {@link #endTextLink} method call will act
1644     * as a <code>link</code> annotation, in the same way as the &lt;A&gt;
1645     * tag does in HTML: When the user clicks on the text, the specified
1646     * action is performed.
1647     * </p><p>
1648     * <i>Note that this method will not work as advertised if the position
1649     * of the text has been modified via the <code>rotate</code>, <code>scale</code>
1650     * or <code>translate</code> methods. This is a shortcoming inherent in
1651     * the PDF document specification</i>. See {@link PDFAnnotation#link} for
1652     * more information.
1653     * </p>
1654     * @param action the action to perform when the text is clicked on
1655     * @param linkstyle the style to apply to any text within the link area,
1656     * or <code>null</code> if the current style is to be used. For an underlined
1657     * link, use {@link PDFStyle#LINKSTYLE}
1658     * @throws IllegalStateException if a link has already been begun (links
1659     * can't be nested)
1660     * @see PDFAnnotation
1661     * @see PDFStyle#LINKSTYLE
1662     * @since 1.1
1663     */

1664    public void beginTextLink(PDFAction action, PDFStyle linkstyle)
1665    {
1666    page.beginTextLink(action.action, linkstyle.style);
1667    }
1668
1669    /**
1670     * <p>
1671     * End the "link" section in the text, analogous to the &lt;/A&gt; tag
1672     * in HTML.
1673     * </p>
1674     * <p>
1675     * This method returns the list of annotations that were added - it's a
1676     * list because if the link wrapped over several lines or pages, several
1677     * annotations would have been added. The idea behind this is that you
1678     * can add annotations to the text, and then set the actions they refer
1679     * to (via the {@link PDFAnnotation#setAction} method) <i>after</i>
1680     * they've been added - for example, to link to a page that hasn't been
1681     * created yet.
1682     * </p>
1683     * @throws IllegalStateException if a link has not been begun
1684     * @since 1.1
1685     */

1686    public PDFAnnotation[] endTextLink()
1687    {
1688    org.faceless.pdf2.PDFAnnotation[] newannots = page.endTextLink();
1689    PDFAnnotation[] oldannots = new PDFAnnotation[newannots.length];
1690    for (int i=0;i<newannots.length;i++) {
1691        oldannots[i]=(PDFAnnotation)PeeredObject.getPeer(newannots[i]);
1692    }
1693    return oldannots;
1694    }
1695
1696    /**
1697     * Draw a LayoutBox at the specified position on the page.
1698     * @param box the LayoutBox to draw
1699     * @param x the X co-ordinate of the left hand side of the LayoutBox
1700     * @param y the Y co-ordinate of the top of the LayoutBox
1701     */

1702    public void drawLayoutBox(LayoutBox box, float x, float y)
1703    {
1704    page.drawLayoutBox(box.box,cx(x),cy(y));
1705    }
1706
1707    public String JavaDoc toString()
1708    {
1709        return "{Page #"+getPageNumber()+"}";
1710    }
1711}
1712
Popular Tags