1 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 ; 44 import java.util.ArrayList ; 45 import java.util.HashMap ; 46 import java.util.logging.Logger ; 47 48 51 public class PDF { 52 private static final Logger 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 <String ,Font> _faceMap = new HashMap <String ,Font>(); 60 61 private HashMap <PDFFont,PDFFont> _fontMap 62 = new HashMap <PDFFont,PDFFont>(); 63 64 private HashMap <PDFProcSet,PDFProcSet> _procSetMap 65 = new HashMap <PDFProcSet,PDFProcSet>(); 66 67 private TempStream _tempStream; 68 private WriteStream _os; 69 private PDFWriter _out; 70 71 private ArrayList <PDFPage> _pageGroup = new ArrayList <PDFPage>(); 72 private ArrayList <Integer > _pagesGroupList = new ArrayList <Integer >(); 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 fileName, 88 @Optional String optList) 89 throws IOException 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 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 opt) 126 throws IOException 127 { 128 return begin_page(width, height); 129 } 130 131 public boolean set_info(String key, String 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 key, String value) 150 { 151 return false; 152 } 153 154 public boolean set_value(String key, double value) 155 { 156 return false; 157 } 158 159 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 176 public String get_errmsg() 177 { 178 return ""; 179 } 180 181 184 public int get_errnum() 185 { 186 return 0; 187 } 188 189 192 public String get_parameter(String 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 209 public double get_value(String 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 256 public PDFFont load_font(String name, String encoding, String opt) 257 throws IOException 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 name) 278 throws IOException 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 299 public boolean setdash(double b, double w) 300 { 301 _stream.setDash(b, w); 302 303 return true; 304 } 305 306 309 public boolean setdashpattern(Env env, @Optional String optlist) 310 { 311 env.stub("setdashpattern"); 312 313 return false; 314 } 315 316 319 public boolean setflat(Env env, double flatness) 320 { 321 env.stub("setflat"); 322 323 return false; 324 } 325 326 329 public boolean setlinecap(Env env, 330 int cap) 331 { 332 env.stub("setlinecap"); 333 334 return false; 335 } 336 337 340 public boolean setlinejoin(Env env, 341 int linejoin) 342 { 343 env.stub("setlinejoin"); 344 345 return false; 346 } 347 348 355 public boolean setfont(@NotNull PDFFont font, double size) 356 throws IOException 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 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 387 public boolean setmiterlimit(Env env, double v) 388 { 389 env.stub("setmiterlimit"); 390 391 return false; 392 } 393 394 397 public boolean shading_pattern(Env env, 398 int shading, 399 @Optional String optlist) 400 { 401 env.stub("shading_pattern"); 402 403 return false; 404 } 405 406 409 public int shading(Env env, 410 String 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 optlist) 420 { 421 env.stub("shading"); 422 423 return 0; 424 } 425 426 429 public boolean shfill(Env env, 430 int shading) 431 { 432 env.stub("shfill"); 433 434 return false; 435 } 436 437 440 public double stringwidth(String 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 452 public boolean set_text_pos(double x, double y) 453 { 454 _stream.setTextPos(x, y); 455 456 return true; 457 } 458 459 462 public boolean fill() 463 { 464 _stream.fill(); 465 466 return true; 467 } 468 469 472 public boolean closepath() 473 { 474 _stream.closepath(); 475 476 return true; 477 } 478 479 482 public boolean clip() 483 { 484 _stream.clip(); 485 486 return true; 487 } 488 489 492 public boolean closepath_stroke() 493 { 494 _stream.closepathStroke(); 495 496 return true; 497 } 498 499 502 public boolean closepath_fill_stroke() 503 { 504 _stream.closepathFillStroke(); 505 506 return true; 507 } 508 509 512 public boolean fill_stroke() 513 { 514 _stream.fillStroke(); 515 516 return true; 517 } 518 519 522 public boolean endpath() 523 { 524 _stream.endpath(); 525 526 return true; 527 } 528 529 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 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 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 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 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 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 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 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 716 public boolean lineto(double x, double y) 717 { 718 _stream.lineTo(x, y); 719 720 return true; 721 } 722 723 726 public boolean moveto(double x, double y) 727 { 728 _stream.moveTo(x, y); 729 730 return true; 731 } 732 733 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 746 public boolean setgray_stroke(double g) 747 { 748 return _stream.setcolor("stroke", "gray", g, 0, 0, 0); 749 } 750 751 754 public boolean setgray_fill(double g) 755 { 756 return _stream.setcolor("fill", "gray", g, 0, 0, 0); 757 } 758 759 762 public boolean setgray(double g) 763 { 764 return _stream.setcolor("both", "gray", g, 0, 0, 0); 765 } 766 767 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 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 786 public boolean setrgbcolor(double r, double g, double b) 787 { 788 return _stream.setcolor("both", "rgb", r, g, b, 0); 789 } 790 791 794 public boolean setcolor(String fstype, String 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 806 public boolean setlinewidth(double w) 807 { 808 return _stream.setlinewidth(w); 809 } 810 811 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 823 public PDFImage open_image_file(String type, Path file, 824 @Optional String stringParam, 825 @Optional int intParam) 826 throws IOException 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 840 public PDFImage load_image(String type, 841 Path file, 842 @Optional String optlist) 843 throws IOException 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 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 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 890 public boolean scale(double sx, double sy) 891 { 892 return _stream.concat(sx, 0, 0, sy, 0, 0); 893 } 894 895 901 public boolean translate(double tx, double ty) 902 { 903 return _stream.concat(1, 0, 0, 1, tx, ty); 904 } 905 906 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 923 public boolean save() 924 { 925 return _stream.save(); 926 } 927 928 931 public boolean restore() 932 { 933 return _stream.restore(); 934 } 935 936 939 public boolean show(String text) 940 { 941 _stream.show(text); 942 943 return true; 944 } 945 946 949 public boolean show_boxed(String text, double x, double y, 950 double width, double height, 951 String mode, @Optional String feature) 952 { 953 set_text_pos(x, y); 954 _stream.show(text); 955 956 return true; 957 } 958 959 962 public boolean show_xy(String text, double x, double y) 963 { 964 set_text_pos(x, y); 965 _stream.show(text); 966 967 return true; 968 } 969 970 973 public boolean stroke() 974 { 975 _stream.stroke(); 976 977 return true; 978 } 979 980 983 public boolean continue_text(String 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 optlist) 1005 { 1006 return end_page(); 1007 } 1008 1009 public boolean end_document(@Optional String optList) 1010 throws IOException 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 1032 { 1033 return end_document(""); 1034 } 1035 1036 public boolean delete() 1037 throws IOException 1038 { 1039 return true; 1040 } 1041 1042 public String toString() 1043 { 1044 return "PDF[]"; 1045 } 1046} 1047 | Popular Tags |