1 26 27 package it.stefanochizzolini.clown.documents.contents.composition; 28 29 import it.stefanochizzolini.clown.bytes.IBuffer; 30 import it.stefanochizzolini.clown.documents.Document; 31 import it.stefanochizzolini.clown.documents.contents.ContentStream; 32 import it.stefanochizzolini.clown.documents.contents.LineCapEnum; 33 import it.stefanochizzolini.clown.documents.contents.LineJoinEnum; 34 import it.stefanochizzolini.clown.documents.contents.TextRenderingModeEnum; 35 import it.stefanochizzolini.clown.documents.contents.colorSpaces.Color; 36 import it.stefanochizzolini.clown.documents.contents.colorSpaces.ColorSpace; 37 import it.stefanochizzolini.clown.documents.contents.fonts.Font; 38 import it.stefanochizzolini.clown.files.File; 39 import it.stefanochizzolini.clown.objects.IPdfNumber; 40 import it.stefanochizzolini.clown.objects.PdfDictionary; 41 import it.stefanochizzolini.clown.objects.PdfLiteral; 42 import it.stefanochizzolini.clown.objects.PdfName; 43 import it.stefanochizzolini.clown.objects.PdfReal; 44 import it.stefanochizzolini.clown.objects.PdfReference; 45 import it.stefanochizzolini.clown.util.NotImplementedException; 46 47 import java.awt.geom.Dimension2D ; 48 import java.awt.geom.Point2D ; 49 import java.awt.geom.RectangularShape ; 50 import java.util.Stack ; 51 52 55 public class ContentBuilder 56 { 57 public static class GraphicsState 60 implements Cloneable 61 { 62 66 private Font font; 67 private double fontSize; 68 69 public GraphicsState clone( 70 ) 71 { 72 try 73 {return (GraphicsState)super.clone();} 74 catch(CloneNotSupportedException e) 75 {throw new RuntimeException ("Unable to clone.",e);} 76 } 77 78 public Font getFont( 79 ) 80 {return font;} 81 82 public double getFontSize( 83 ) 84 {return fontSize;} 85 86 void setFont( 87 Font value 88 ) 89 {font = value;} 90 91 void setFontSize( 92 double value 93 ) 94 {fontSize = value;} 95 } 96 98 103 private GraphicsState state = new GraphicsState(); 104 private IBuffer buffer; 105 private ContentStream context; 106 110 private Stack <GraphicsState> stateStack = new Stack <GraphicsState>(); 111 113 public ContentBuilder( 115 ContentStream context, 116 IBuffer buffer 117 ) 118 { 119 this.context = context; 120 this.buffer = buffer; 121 } 122 124 129 public IBuffer getBuffer( 130 ) 131 {return buffer;} 132 133 136 public ContentStream getContext( 137 ) 138 {return context;} 139 140 145 public void beginLocalState( 146 ) 147 { 148 stateStack.push(state); 149 state = state.clone(); 150 151 buffer.append("q\r"); 152 } 153 154 157 public void beginText( 158 ) 159 {buffer.append("BT\r");} 160 161 164 public void drawRectangle( 165 RectangularShape location 166 ) 167 { 168 buffer.append( 169 PdfReal.toPdf(location.getX()) + " " 170 + PdfReal.toPdf(((IPdfNumber)context.getStreamContext().getContextBox().get(3)).getNumberValue() - location.getY() - location.getHeight()) + " " 171 + PdfReal.toPdf(location.getWidth()) + " " 172 + PdfReal.toPdf(location.getHeight()) + " " 173 + "re\r" 174 ); 175 } 176 177 182 public void endLocalState( 183 ) 184 { 185 buffer.append("Q\r"); 186 187 state = stateStack.pop(); 188 } 189 190 193 public void endText( 194 ) 195 {buffer.append("ET\r");} 196 197 200 public void fill( 201 ) 202 {buffer.append("f\r");} 203 204 207 public void fillStroke( 208 ) 209 {buffer.append("B\r");} 210 211 public GraphicsState getState( 212 ) 213 {return state;} 214 215 220 public void rotate( 221 double angle 222 ) 223 { 224 double rad = angle * Math.PI / 180; 225 double cos = Math.cos(rad); 226 double sin = Math.sin(rad); 227 228 setMatrix(cos, sin, -sin, cos, 0, 0); 229 } 230 231 236 public void rotateText( 237 double angle 238 ) 239 { 240 double rad = angle * Math.PI / 180; 241 double cos = Math.cos(rad); 242 double sin = Math.sin(rad); 243 244 setTextMatrix(cos, sin, -sin, cos, 0, 0); 245 } 246 247 253 public void scale( 254 double ratioX, 255 double ratioY 256 ) 257 {setMatrix(ratioX, 0, 0, ratioY, 0, 0);} 258 259 265 public void scaleText( 266 double ratioX, 267 double ratioY 268 ) 269 {setTextMatrix(ratioX, 0, 0, ratioY, 0, 0);} 270 271 274 public void setCharacterSpacing( 275 double value 276 ) 277 {buffer.append(PdfReal.toPdf(value) + " Tc\r");} 278 279 282 public void setFillColor( 283 Color value 284 ) 285 {buffer.append(value.toPdf() + " " + value.getFillOperator() + "\r");} 286 287 291 public void setFillColorSpace( 292 PdfName name 293 ) 294 { buffer.append(name.toPdf() + " cs\r"); 297 } 298 299 307 public void setFillColorSpace( 308 ColorSpace value 309 ) 310 { 311 throw new NotImplementedException("colorSpace MUST be converted to its associated name; you need to implement a method in PdfDictionary that, given a PdfDirectObject, returns its associated key."); 312 } 313 314 317 public void setFlatness( 318 double value 319 ) 320 { 321 if(value < 0 || value > 100) 323 throw new IllegalArgumentException ("'value' MUST be between 0 and 100."); 324 326 buffer.append(PdfReal.toPdf(value) + " i\r"); 327 } 328 329 334 public void setFont( 335 PdfName name, 336 double size 337 ) 338 { 339 state.font = Font.wrap((PdfReference)((PdfDictionary)File.resolve(context.getStreamContext().getContextResources().get(PdfName.Font))).get(name)); 341 if(state.font == null) 342 {throw new IllegalArgumentException ("No font resource associated to the given argument (name:'name'; value:'" + name + "';)");} 343 state.fontSize = size; 344 345 buffer.append(name.toPdf() + " " + PdfReal.toPdf(size) + " Tf\r"); 346 } 347 348 357 public void setFont( 358 Font value, 359 double size 360 ) 361 { 362 throw new NotImplementedException("font MUST be converted to its associated name; you need to implement a method in PdfDictionary that, given a PdfDirectObject, returns its associated key."); 363 367 } 368 369 372 public void setHorizontalScaling( 373 double value 374 ) 375 {buffer.append(PdfReal.toPdf(value) + " Tz\r");} 376 377 380 public void setLeading( 381 double value 382 ) 383 {buffer.append(PdfReal.toPdf(value) + " TL\r");} 384 385 388 public void setLineCap( 389 LineCapEnum value 390 ) 391 {buffer.append(Integer.toString(value.getCode()) + " J\r");} 392 393 397 public void setLineDash( 398 int phase 399 ) 400 {buffer.append("[] " + phase + " d\r");} 401 402 407 public void setLineDash( 408 int phase, 409 int unitsOn 410 ) 411 {buffer.append("[" + unitsOn + "] " + phase + " d\r");} 412 413 419 public void setLineDash( 420 int phase, 421 int unitsOn, 422 int unitsOff 423 ) 424 {buffer.append("[" + unitsOn + " " + unitsOff + "] " + phase + " d\r");} 425 426 429 public void setLineJoin( 430 LineJoinEnum value 431 ) 432 {buffer.append(Integer.toString(value.getCode()) + " j\r");} 433 434 437 public void setLineWidth( 438 double value 439 ) 440 {buffer.append(PdfReal.toPdf(value) + " w\r");} 441 442 452 public void setMatrix( 453 double a, 454 double b, 455 double c, 456 double d, 457 double e, 458 double f 459 ) 460 { 461 buffer.append( 462 PdfReal.toPdf(a) + " " 463 + PdfReal.toPdf(b) + " " 464 + PdfReal.toPdf(c) + " " 465 + PdfReal.toPdf(d) + " " 466 + PdfReal.toPdf(e) + " " 467 + PdfReal.toPdf(f) + " " 468 + "cm\r" 469 ); 470 } 471 472 475 public void setMiterLimit( 476 double value 477 ) 478 {buffer.append(PdfReal.toPdf(value) + " M\r");} 479 480 483 public void setStrokeColor( 484 Color value 485 ) 486 {buffer.append(value.toPdf() + " " + value.getStrokeOperator() + "\r");} 487 488 492 public void setStrokeColorSpace( 493 PdfName name 494 ) 495 { buffer.append(name.toPdf() + " CS\r"); 498 } 499 500 508 public void setStrokeColorSpace( 509 ColorSpace value 510 ) 511 { 512 throw new NotImplementedException("colorSpace MUST be converted to its associated name; you need to implement a method in PdfDictionary that, given a PdfDirectObject, returns its associated key."); 513 } 514 515 525 public void setTextMatrix( 526 double a, 527 double b, 528 double c, 529 double d, 530 double e, 531 double f 532 ) 533 { 534 buffer.append( 535 PdfReal.toPdf(a) + " " 536 + PdfReal.toPdf(b) + " " 537 + PdfReal.toPdf(c) + " " 538 + PdfReal.toPdf(d) + " " 539 + PdfReal.toPdf(e) + " " 540 + PdfReal.toPdf(f) + " " 541 + "Tm\r" 542 ); 543 } 544 545 548 public void setTextRenderingMode( 549 TextRenderingModeEnum value 550 ) 551 {buffer.append(Integer.toString(value.getCode()) + " Tr\r");} 552 553 556 public void setTextRise( 557 double value 558 ) 559 {buffer.append(value + " Ts\r");} 560 561 564 public void setWordSpacing( 565 double value 566 ) 567 {buffer.append(value + " Tw\r");} 568 569 573 public void showText( 574 String value 575 ) 576 {buffer.append(PdfLiteral.toPdf(value) + " Tj\r");} 577 578 583 public void showText( 584 String value, 585 Point2D location 586 ) 587 { 588 showText( 589 value, 590 location, 591 AlignmentXEnum.Left, 592 AlignmentYEnum.Top, 593 0 594 ); 595 } 596 597 605 public void showText( 606 String value, 607 Point2D location, 608 AlignmentXEnum alignmentX, 609 AlignmentYEnum alignmentY, 610 double rotation 611 ) 612 { 613 double width = state.font.getKernedWidth(value,state.fontSize); 614 double x = location.getX(); 615 double y = location.getY(); 616 switch(alignmentX) 617 { 618 case Left: 619 case Justify: 620 break; 622 case Right: 623 x -= width; 624 break; 625 case Center: 626 x -= width / 2; 627 break; 628 } 629 switch(alignmentY) 630 { 631 case Top: 632 break; 634 case Bottom: 635 y -= state.font.getLineHeight(state.fontSize); 636 break; 637 case Middle: 638 y -= state.font.getLineHeight(state.fontSize) / 2; 639 break; 640 } 641 642 if(rotation == 0) 643 { 644 translateText( 645 x, 646 ((IPdfNumber)context.getStreamContext().getContextBox().get(3)).getNumberValue() - y - state.font.getAscent(state.fontSize) 647 ); 648 } 649 else 650 { 651 double rad = rotation * Math.PI / 180.0; 652 double cos = Math.cos(rad); 653 double sin = Math.sin(rad); 654 655 setTextMatrix( 656 cos, 657 sin, 658 -sin, 659 cos, 660 x, 661 ((IPdfNumber)context.getStreamContext().getContextBox().get(3)).getNumberValue() - y - state.font.getAscent(state.fontSize) 662 ); 663 } 664 buffer.append(PdfLiteral.toPdf(value) + " Tj\r"); 665 } 666 667 671 public void showXObject( 672 PdfName name 673 ) 674 {buffer.append(name.toPdf() + " Do\r");} 675 676 681 public void showXObject( 682 PdfName name, 683 RectangularShape location 684 ) 685 { 686 showXObject( 687 name, 688 location, 689 0 690 ); 691 } 692 693 699 public void showXObject( 700 PdfName name, 701 RectangularShape location, 702 double rotation 703 ) 704 { 705 beginLocalState(); 709 setMatrix( 710 location.getWidth(), 711 0, 712 0, 713 location.getHeight(), 714 location.getX(), 715 ((IPdfNumber)context.getStreamContext().getContextBox().get(3)).getNumberValue() - location.getY() - location.getHeight() 716 ); 717 showXObject(name); 718 endLocalState(); 719 } 720 721 724 public void stroke( 725 ) 726 {buffer.append("S\r");} 727 728 734 public void translate( 735 double distanceX, 736 double distanceY 737 ) 738 {setMatrix(1, 0, 0, 1, distanceX, distanceY);} 739 740 746 public void translateText( 747 double distanceX, 748 double distanceY 749 ) 750 {setTextMatrix(1, 0, 0, 1, distanceX, distanceY);} 751 752 758 public void translateTextRelative( 759 double offsetX, 760 double offsetY 761 ) 762 { 763 buffer.append( 764 PdfReal.toPdf(offsetX) + " " 765 + PdfReal.toPdf(-offsetY) + " " 766 + "Td\r" 767 ); 768 } 769 770 774 public void translateTextToNextLine( 775 ) 776 {buffer.append("T*\r");} 777 } | Popular Tags |