KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > quercus > lib > pdf > PDF


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.quercus.lib.pdf;
31
32 import com.caucho.quercus.annotation.NotNull;
33 import com.caucho.quercus.annotation.Optional;
34 import com.caucho.quercus.env.BooleanValue;
35 import com.caucho.quercus.env.Env;
36 import com.caucho.quercus.env.TempBufferStringValue;
37 import com.caucho.quercus.env.Value;
38 import com.caucho.util.L10N;
39 import com.caucho.vfs.Path;
40 import com.caucho.vfs.TempStream;
41 import com.caucho.vfs.WriteStream;
42
43 import java.io.IOException JavaDoc;
44 import java.util.ArrayList JavaDoc;
45 import java.util.HashMap JavaDoc;
46 import java.util.logging.Logger JavaDoc;
47
48 /**
49  * pdf object oriented API facade
50  */

51 public class PDF {
52   private static final Logger JavaDoc log = Logger.getLogger(PDF.class.getName());
53   private static final L10N L = new L10N(PDF.class);
54
55   private static final double KAPPA = 0.5522847498;
56
57   private static final int PAGE_GROUP = 8;
58
59   private static HashMap JavaDoc<String JavaDoc,Font> _faceMap = new HashMap JavaDoc<String JavaDoc,Font>();
60
61   private HashMap JavaDoc<PDFFont,PDFFont> _fontMap
62     = new HashMap JavaDoc<PDFFont,PDFFont>();
63
64   private HashMap JavaDoc<PDFProcSet,PDFProcSet> _procSetMap
65     = new HashMap JavaDoc<PDFProcSet,PDFProcSet>();
66
67   private TempStream _tempStream;
68   private WriteStream _os;
69   private PDFWriter _out;
70
71   private ArrayList JavaDoc<PDFPage> _pageGroup = new ArrayList JavaDoc<PDFPage>();
72   private ArrayList JavaDoc<Integer JavaDoc> _pagesGroupList = new ArrayList JavaDoc<Integer JavaDoc>();
73   private int _pageCount;
74
75   private int _catalogId;
76
77   private int _pageParentId;
78
79   private PDFPage _page;
80   private PDFStream _stream;
81
82   public PDF(Env env)
83   {
84     _out = new PDFWriter(env.getOut());
85   }
86
87   public boolean begin_document(@Optional String JavaDoc fileName,
88                                 @Optional String JavaDoc optList)
89     throws IOException JavaDoc
90   {
91     _tempStream = new TempStream();
92     _tempStream.openWrite();
93     _os = new WriteStream(_tempStream);
94
95     _out = new PDFWriter(_os);
96     _out.beginDocument();
97
98     _catalogId = _out.allocateId(1);
99     _pageParentId = _out.allocateId(1);
100
101     return true;
102   }
103
104   public boolean begin_page(double width, double height)
105     throws IOException JavaDoc
106   {
107     if (PAGE_GROUP <= _pageGroup.size()) {
108       _out.writePageGroup(_pageParentId, _pageGroup);
109       _pageGroup.clear();
110
111       _pagesGroupList.add(_pageParentId);
112       _pageParentId = _out.allocateId(1);
113     }
114
115     _page = new PDFPage(_out, _pageParentId, width, height);
116     _stream = _page.getStream();
117
118     _pageCount++;
119
120     _pageGroup.add(_page);
121
122     return true;
123   }
124
125   public boolean begin_page_ext(double width, double height, String JavaDoc opt)
126     throws IOException JavaDoc
127   {
128     return begin_page(width, height);
129   }
130
131   public boolean set_info(String JavaDoc key, String JavaDoc value)
132   {
133     if ("Author".equals(key)) {
134       _out.setAuthor(key);
135       return true;
136     }
137     else if ("Title".equals(key)) {
138       _out.setTitle(key);
139       return true;
140     }
141     else if ("Creator".equals(key)) {
142       _out.setCreator(key);
143       return true;
144     }
145     else
146       return false;
147   }
148
149   public boolean set_parameter(String JavaDoc key, String JavaDoc value)
150   {
151     return false;
152   }
153
154   public boolean set_value(String JavaDoc key, double value)
155   {
156     return false;
157   }
158
159   /**
160    * Returns the result as a string.
161    */

162   public Value get_buffer()
163   {
164     TempStream ts = _tempStream;
165     _tempStream = null;
166
167     if (ts == null)
168       return BooleanValue.FALSE;
169
170     return new TempBufferStringValue(ts.getHead());
171   }
172
173   /**
174    * Returns the error message.
175    */

176   public String JavaDoc get_errmsg()
177   {
178     return "";
179   }
180
181   /**
182    * Returns the error number.
183    */

184   public int get_errnum()
185   {
186     return 0;
187   }
188
189   /**
190    * Returns the value for a parameter.
191    */

192   public String JavaDoc get_parameter(String JavaDoc name, @Optional double modifier)
193   {
194     if ("fontname".equals(name)) {
195       PDFFont font = _stream.getFont();
196
197       if (font != null)
198         return font.getFontName();
199       else
200         return null;
201     }
202     else
203       return null;
204   }
205
206   /**
207    * Returns the value for a parameter.
208    */

209   public double get_value(String JavaDoc name, @Optional double modifier)
210   {
211     if ("ascender".equals(name)) {
212       PDFFont font = _stream.getFont();
213
214       if (font != null)
215         return font.getAscender();
216       else
217         return 0;
218     }
219     else if ("capheight".equals(name)) {
220       PDFFont font = _stream.getFont();
221
222       if (font != null)
223         return font.getCapHeight();
224       else
225         return 0;
226     }
227     else if ("descender".equals(name)) {
228       PDFFont font = _stream.getFont();
229
230       if (font != null)
231         return font.getDescender();
232       else
233         return 0;
234     }
235     else if ("fontsize".equals(name)) {
236       return _stream.getFontSize();
237     }
238     else
239       return 0;
240   }
241
242   public boolean initgraphics(Env env)
243   {
244     env.stub("initgraphics");
245
246     return false;
247   }
248
249   /**
250    * Loads a font for later use.
251    *
252    * @param name the font name, e.g. Helvetica
253    * @param encoding the font encoding, e.g. winansi
254    * @param opt any options
255    */

256   public PDFFont load_font(String JavaDoc name, String JavaDoc encoding, String JavaDoc opt)
257     throws IOException JavaDoc
258   {
259     Font face = loadFont(name);
260
261     PDFFont font = new PDFFont(face, encoding, opt);
262
263     PDFFont oldFont = _fontMap.get(font);
264
265     if (oldFont != null)
266       return oldFont;
267
268     font.setId(_out.allocateId(1));
269
270     _fontMap.put(font, font);
271
272     _out.addPendingObject(font);
273
274     return font;
275   }
276
277   private Font loadFont(String JavaDoc name)
278     throws IOException JavaDoc
279   {
280     synchronized (_faceMap) {
281       Font face = _faceMap.get(name);
282
283       if (face == null) {
284         face = new AfmParser().parse(name);
285
286         _faceMap.put(name, face);
287       }
288
289       return face;
290     }
291   }
292
293   /**
294    * Sets the dashing
295    *
296    * @param b black length
297    * @param w which length
298    */

299   public boolean setdash(double b, double w)
300   {
301     _stream.setDash(b, w);
302
303     return true;
304   }
305
306   /**
307    * Sets the dashing
308    */

309   public boolean setdashpattern(Env env, @Optional String JavaDoc optlist)
310   {
311     env.stub("setdashpattern");
312
313     return false;
314   }
315
316   /**
317    * Sets the flatness
318    */

319   public boolean setflat(Env env, double flatness)
320   {
321     env.stub("setflat");
322
323     return false;
324   }
325
326   /**
327    * Sets the linecap style
328    */

329   public boolean setlinecap(Env env,
330                             int cap)
331   {
332     env.stub("setlinecap");
333
334     return false;
335   }
336
337   /**
338    * Sets the linejoin style
339    */

340   public boolean setlinejoin(Env env,
341                              int linejoin)
342   {
343     env.stub("setlinejoin");
344
345     return false;
346   }
347
348   /**
349    * Sets the current font
350    *
351    * @param name the font name, e.g. Helvetica
352    * @param encoding the font encoding, e.g. winansi
353    * @param opt any options
354    */

355   public boolean setfont(@NotNull PDFFont font, double size)
356     throws IOException JavaDoc
357   {
358     if (font == null)
359       return false;
360
361     _stream.setFont(font, size);
362
363     _page.addResource(font.getResource());
364
365     return true;
366   }
367
368   /**
369    * Sets the matrix style
370    */

371   public boolean setmatrix(Env env,
372                            double a,
373                            double b,
374                            double c,
375                            double d,
376                            double e,
377                            double f)
378   {
379     env.stub("setmatrix");
380
381     return false;
382   }
383
384   /**
385    * Sets the miter limit
386    */

387   public boolean setmiterlimit(Env env, double v)
388   {
389     env.stub("setmiterlimit");
390
391     return false;
392   }
393
394   /**
395    * Sets the shading pattern
396    */

397   public boolean shading_pattern(Env env,
398                                  int shading,
399                                  @Optional String JavaDoc optlist)
400   {
401     env.stub("shading_pattern");
402
403     return false;
404   }
405
406   /**
407    * Define a blend
408    */

409   public int shading(Env env,
410                      String JavaDoc type,
411                      double x1,
412                      double y1,
413                      double x2,
414                      double y2,
415                      double c1,
416                      double c2,
417                      double c3,
418                      double c4,
419                      @Optional String JavaDoc optlist)
420   {
421     env.stub("shading");
422
423     return 0;
424   }
425
426   /**
427    * Fill with a shading object.
428    */

429   public boolean shfill(Env env,
430                         int shading)
431   {
432     env.stub("shfill");
433
434     return false;
435   }
436
437   /**
438    * Returns the length of a string for a font.
439    */

440   public double stringwidth(String JavaDoc string, @NotNull PDFFont font, double size)
441   {
442     if (font == null)
443       return 0;
444
445     return size * font.stringWidth(string) / 1000.0;
446   }
447
448
449   /**
450    * Sets the text position.
451    */

452   public boolean set_text_pos(double x, double y)
453   {
454     _stream.setTextPos(x, y);
455
456     return true;
457   }
458
459   /**
460    * Fills
461    */

462   public boolean fill()
463   {
464     _stream.fill();
465
466     return true;
467   }
468
469   /**
470    * Closes the path
471    */

472   public boolean closepath()
473   {
474     _stream.closepath();
475
476     return true;
477   }
478
479   /**
480    * Appends the current path to the clipping path.
481    */

482   public boolean clip()
483   {
484     _stream.clip();
485
486     return true;
487   }
488
489   /**
490    * Closes the path strokes
491    */

492   public boolean closepath_stroke()
493   {
494     _stream.closepathStroke();
495
496     return true;
497   }
498
499   /**
500    * Closes the path strokes
501    */

502   public boolean closepath_fill_stroke()
503   {
504     _stream.closepathFillStroke();
505
506     return true;
507   }
508
509   /**
510    * Fills
511    */

512   public boolean fill_stroke()
513   {
514     _stream.fillStroke();
515
516     return true;
517   }
518
519   /**
520    * Ends the path
521    */

522   public boolean endpath()
523   {
524     _stream.endpath();
525
526     return true;
527   }
528
529   /**
530    * Draws a bezier curve
531    */

532   public boolean curveto(double x1, double y1,
533                          double x2, double y2,
534                          double x3, double y3)
535   {
536     _stream.curveTo(x1, y1, x2, y2, x3, y3);
537
538     return true;
539   }
540
541   /**
542    * Draws a bezier curve
543    */

544   public boolean curveto_b(double x1, double y1,
545                            double x2, double y2)
546   {
547     _stream.curveTo(x1, y1, x1, y1, x2, y2);
548
549     return true;
550   }
551
552   /**
553    * Draws a bezier curve
554    */

555   public boolean curveto_e(double x1, double y1,
556                            double x2, double y2)
557   {
558     _stream.curveTo(x1, y1, x2, y2, x2, y2);
559
560     return true;
561   }
562
563   /**
564    * Creates a counterclockwise arg
565    */

566   public boolean arc(double x1, double y1, double r, double a, double b)
567   {
568     a = a % 360;
569     if (a < 0)
570       a += 360;
571
572     b = b % 360;
573     if (b < 0)
574       b += 360;
575
576     if (b < a)
577       b += 360;
578
579     int aQuarter = (int) (a / 90);
580     int bQuarter = (int) (b / 90);
581
582     if (aQuarter == bQuarter) {
583       clockwiseArc(x1, y1, r, a, b);
584     }
585     else {
586       clockwiseArc(x1, y1, r, a, (aQuarter + 1) * 90);
587
588       for (int q = aQuarter + 1; q < bQuarter; q++)
589         clockwiseArc(x1, y1, r, q * 90, (q + 1) * 90);
590
591       clockwiseArc(x1, y1, r, bQuarter * 90, b);
592     }
593
594     return true;
595   }
596
597   /**
598    * Creates a clockwise arc
599    */

600   public boolean arcn(double x1, double y1, double r, double a, double b)
601   {
602     a = a % 360;
603     if (a < 0)
604       a += 360;
605
606     b = b % 360;
607     if (b < 0)
608       b += 360;
609
610     if (a < b)
611       a += 360;
612
613     int aQuarter = (int) (a / 90);
614     int bQuarter = (int) (b / 90);
615
616     if (aQuarter == bQuarter) {
617       counterClockwiseArc(x1, y1, r, a, b);
618     }
619     else {
620       counterClockwiseArc(x1, y1, r, a, aQuarter * 90);
621
622       for (int q = aQuarter - 1; bQuarter < q; q--)
623         counterClockwiseArc(x1, y1, r, (q + 1) * 90, q * 90);
624
625       counterClockwiseArc(x1, y1, r, (bQuarter + 1) * 90, b);
626     }
627
628     return true;
629   }
630
631   /**
632    * Creates an arc from 0 to pi/2
633    */

634   private boolean clockwiseArc(double x, double y, double r,
635                                double aDeg, double bDeg)
636   {
637     double a = aDeg * Math.PI / 180.0;
638     double b = bDeg * Math.PI / 180.0;
639
640     double cos_a = Math.cos(a);
641     double sin_a = Math.sin(a);
642
643     double x1 = x + r * cos_a;
644     double y1 = y + r * sin_a;
645
646     double cos_b = Math.cos(b);
647     double sin_b = Math.sin(b);
648
649     double x2 = x + r * cos_b;
650     double y2 = y + r * sin_b;
651
652     double l = KAPPA * r * 2 * (b - a) / Math.PI;
653
654     lineto(x1, y1);
655     curveto(x1 - l * sin_a, y1 + l * cos_a,
656             x2 + l * sin_b, y2 - l * cos_b,
657             x2, y2);
658
659     return true;
660   }
661
662   /**
663    * Creates an arc from 0 to pi/2
664    */

665   private boolean counterClockwiseArc(double x, double y, double r,
666                                       double aDeg, double bDeg)
667   {
668     double a = aDeg * Math.PI / 180.0;
669     double b = bDeg * Math.PI / 180.0;
670
671     double cos_a = Math.cos(a);
672     double sin_a = Math.sin(a);
673
674     double x1 = x + r * cos_a;
675     double y1 = y + r * sin_a;
676
677     double cos_b = Math.cos(b);
678     double sin_b = Math.sin(b);
679
680     double x2 = x + r * cos_b;
681     double y2 = y + r * sin_b;
682
683     double l = KAPPA * r * 2 * (a - b) / Math.PI;
684
685     lineto(x1, y1);
686     curveto(x1 + l * sin_a, y1 - l * cos_a,
687             x2 - l * sin_b, y2 + l * cos_b,
688             x2, y2);
689
690     return true;
691   }
692
693   /**
694    * Creates a circle
695    */

696   public boolean circle(double x1, double y1, double r)
697   {
698     double l = r * KAPPA;
699
700     moveto(x1, y1 + r);
701
702     curveto(x1 - l, y1 + r, x1 - r, y1 + l, x1 - r, y1);
703
704     curveto(x1 - r, y1 - l, x1 - l, y1 - r, x1, y1 - r);
705
706     curveto(x1 + l, y1 - r, x1 + r, y1 - l, x1 + r, y1);
707
708     curveto(x1 + r, y1 + l, x1 + l, y1 + r, x1, y1 + r);
709
710     return true;
711   }
712
713   /**
714    * Sets the graphics position.
715    */

716   public boolean lineto(double x, double y)
717   {
718     _stream.lineTo(x, y);
719
720     return true;
721   }
722
723   /**
724    * Sets the graphics position.
725    */

726   public boolean moveto(double x, double y)
727   {
728     _stream.moveTo(x, y);
729
730     return true;
731   }
732
733   /**
734    * Creates a rectangle
735    */

736   public boolean rect(double x, double y, double width, double height)
737   {
738     _stream.rect(x, y, width, height);
739
740     return true;
741   }
742
743   /**
744    * Sets the color to a grayscale
745    */

746   public boolean setgray_stroke(double g)
747   {
748     return _stream.setcolor("stroke", "gray", g, 0, 0, 0);
749   }
750
751   /**
752    * Sets the color to a grayscale
753    */

754   public boolean setgray_fill(double g)
755   {
756     return _stream.setcolor("fill", "gray", g, 0, 0, 0);
757   }
758
759   /**
760    * Sets the color to a grayscale
761    */

762   public boolean setgray(double g)
763   {
764     return _stream.setcolor("both", "gray", g, 0, 0, 0);
765   }
766
767   /**
768    * Sets the color to a rgb
769    */

770   public boolean setrgbcolor_stroke(double r, double g, double b)
771   {
772     return _stream.setcolor("stroke", "rgb", r, g, b, 0);
773   }
774
775   /**
776    * Sets the fill color to a rgb
777    */

778   public boolean setrgbcolor_fill(double r, double g, double b)
779   {
780     return _stream.setcolor("fill", "rgb", r, g, b, 0);
781   }
782
783   /**
784    * Sets the color to a rgb
785    */

786   public boolean setrgbcolor(double r, double g, double b)
787   {
788     return _stream.setcolor("both", "rgb", r, g, b, 0);
789   }
790
791   /**
792    * Sets the color
793    */

794   public boolean setcolor(String JavaDoc fstype, String JavaDoc colorspace,
795                           double c1,
796                           @Optional double c2,
797                           @Optional double c3,
798                           @Optional double c4)
799   {
800     return _stream.setcolor(fstype, colorspace, c1, c2, c3, c4);
801   }
802
803   /**
804    * Sets the line width
805    */

806   public boolean setlinewidth(double w)
807   {
808     return _stream.setlinewidth(w);
809   }
810
811   /**
812    * Concatenates the matrix
813    */

814   public boolean concat(double a, double b, double c,
815                         double d, double e, double f)
816   {
817     return _stream.concat(a, b, c, d, e, f);
818   }
819
820   /**
821    * open image
822    */

823   public PDFImage open_image_file(String JavaDoc type, Path file,
824                                   @Optional String JavaDoc stringParam,
825                                   @Optional int intParam)
826     throws IOException JavaDoc
827   {
828     PDFImage img = new PDFImage(file);
829
830     img.setId(_out.allocateId(1));
831
832     _out.addPendingObject(img);
833
834     return img;
835   }
836
837   /**
838    * open image
839    */

840   public PDFImage load_image(String JavaDoc type,
841                              Path file,
842                              @Optional String JavaDoc optlist)
843     throws IOException JavaDoc
844   {
845     PDFImage img = new PDFImage(file);
846
847     img.setId(_out.allocateId(1));
848
849     _out.addPendingObject(img);
850
851     return img;
852   }
853
854   public boolean fit_image(PDFImage img, double x, double y,
855                            @Optional String JavaDoc opt)
856   {
857     _page.addResource(img.getResource());
858
859     _stream.save();
860
861     concat(img.get_width(), 0, 0, img.get_height(), x, y);
862
863     _stream.fit_image(img);
864
865     _stream.restore();
866
867     return true;
868   }
869
870   /**
871    * Skews the coordinates
872    *
873    * @param a degrees to skew the x axis
874    * @param b degrees to skew the y axis
875    */

876   public boolean skew(double aDeg, double bDeg)
877   {
878     double a = aDeg * Math.PI / 180;
879     double b = bDeg * Math.PI / 180;
880
881     return _stream.concat(1, Math.tan(a), Math.tan(b), 1, 0, 0);
882   }
883
884   /**
885    * scales the coordinates
886    *
887    * @param sx amount to scale the x axis
888    * @param sy amount to scale the y axis
889    */

890   public boolean scale(double sx, double sy)
891   {
892     return _stream.concat(sx, 0, 0, sy, 0, 0);
893   }
894
895   /**
896    * translates the coordinates
897    *
898    * @param tx amount to translate the x axis
899    * @param ty amount to translate the y axis
900    */

901   public boolean translate(double tx, double ty)
902   {
903     return _stream.concat(1, 0, 0, 1, tx, ty);
904   }
905
906   /**
907    * rotates the coordinates
908    *
909    * @param p amount to rotate
910    */

911   public boolean rotate(double pDeg)
912   {
913     double p = pDeg * Math.PI / 180;
914
915     return _stream.concat(Math.cos(p), Math.sin(p),
916                           -Math.sin(p), Math.cos(p),
917                           0, 0);
918   }
919
920   /**
921    * Saves the graphics state.
922    */

923   public boolean save()
924   {
925     return _stream.save();
926   }
927
928   /**
929    * Restores the graphics state.
930    */

931   public boolean restore()
932   {
933     return _stream.restore();
934   }
935
936   /**
937    * Displays text
938    */

939   public boolean show(String JavaDoc text)
940   {
941     _stream.show(text);
942
943     return true;
944   }
945
946   /**
947    * Displays text
948    */

949   public boolean show_boxed(String JavaDoc text, double x, double y,
950                             double width, double height,
951                             String JavaDoc mode, @Optional String JavaDoc feature)
952   {
953     set_text_pos(x, y);
954     _stream.show(text);
955
956     return true;
957   }
958
959   /**
960    * Displays text
961    */

962   public boolean show_xy(String JavaDoc text, double x, double y)
963   {
964     set_text_pos(x, y);
965     _stream.show(text);
966
967     return true;
968   }
969
970   /**
971    * Draws the graph
972    */

973   public boolean stroke()
974   {
975     _stream.stroke();
976
977     return true;
978   }
979
980   /**
981    * Displays text
982    */

983   public boolean continue_text(String JavaDoc text)
984   {
985     _stream.continue_text(text);
986
987     return true;
988   }
989
990   public boolean end_page()
991   {
992     _stream.flush();
993
994     PDFProcSet procSet = _stream.getProcSet();
995
996     _page.addResource(procSet.getResource());
997
998     _page = null;
999     _stream = null;
1000
1001    return true;
1002  }
1003
1004  public boolean end_page_ext(String JavaDoc optlist)
1005  {
1006    return end_page();
1007  }
1008
1009  public boolean end_document(@Optional String JavaDoc optList)
1010    throws IOException JavaDoc
1011  {
1012    if (_pageGroup.size() > 0) {
1013      _out.writePageGroup(_pageParentId, _pageGroup);
1014      _pageGroup.clear();
1015
1016      if (_pagesGroupList.size() > 0)
1017        _pagesGroupList.add(_pageParentId);
1018    }
1019
1020    _out.writeCatalog(_catalogId, _pageParentId, _pagesGroupList, _pageCount);
1021
1022    _out.endDocument();
1023
1024    _os.close();
1025    _out = null;
1026
1027    return true;
1028  }
1029
1030  public boolean close()
1031    throws IOException JavaDoc
1032  {
1033    return end_document("");
1034  }
1035
1036  public boolean delete()
1037    throws IOException JavaDoc
1038  {
1039    return true;
1040  }
1041
1042  public String JavaDoc toString()
1043  {
1044    return "PDF[]";
1045  }
1046}
1047
Popular Tags