1
49
50 package com.lowagie.text.pdf;
51
52 import java.awt.Color;
53 import java.io.IOException;
54 import java.util.ArrayList;
55 import java.util.HashMap;
56 import java.util.HashSet;
57 import java.util.Iterator;
58 import java.util.Map;
59 import java.util.Set;
60 import java.util.TreeMap;
61
62 import com.lowagie.text.Anchor;
63 import com.lowagie.text.Annotation;
64 import com.lowagie.text.BadElementException;
65 import com.lowagie.text.Chunk;
66 import com.lowagie.text.Document;
67 import com.lowagie.text.DocumentException;
68 import com.lowagie.text.Element;
69 import com.lowagie.text.ExceptionConverter;
70 import com.lowagie.text.Font;
71 import com.lowagie.text.HeaderFooter;
72 import com.lowagie.text.Image;
73 import com.lowagie.text.List;
74 import com.lowagie.text.ListItem;
75 import com.lowagie.text.MarkedObject;
76 import com.lowagie.text.MarkedSection;
77 import com.lowagie.text.Meta;
78 import com.lowagie.text.Paragraph;
79 import com.lowagie.text.Phrase;
80 import com.lowagie.text.Rectangle;
81 import com.lowagie.text.Section;
82 import com.lowagie.text.SimpleTable;
83 import com.lowagie.text.Table;
84 import com.lowagie.text.pdf.collection.PdfCollection;
85 import com.lowagie.text.pdf.draw.DrawInterface;
86 import com.lowagie.text.pdf.internal.PdfAnnotationsImp;
87 import com.lowagie.text.pdf.internal.PdfViewerPreferencesImp;
88 import java.text.DecimalFormat;
89
90
103
104 public class PdfDocument extends Document {
105
106
116
117 public static class PdfInfo extends PdfDictionary {
118
119
122
123 PdfInfo() {
124 super();
125 addProducer();
126 addCreationDate();
127 }
128
129
136
137 PdfInfo(String author, String title, String subject) {
138 this();
139 addTitle(title);
140 addSubject(subject);
141 addAuthor(author);
142 }
143
144
149
150 void addTitle(String title) {
151 put(PdfName.TITLE, new PdfString(title, PdfObject.TEXT_UNICODE));
152 }
153
154
159
160 void addSubject(String subject) {
161 put(PdfName.SUBJECT, new PdfString(subject, PdfObject.TEXT_UNICODE));
162 }
163
164
169
170 void addKeywords(String keywords) {
171 put(PdfName.KEYWORDS, new PdfString(keywords, PdfObject.TEXT_UNICODE));
172 }
173
174
179
180 void addAuthor(String author) {
181 put(PdfName.AUTHOR, new PdfString(author, PdfObject.TEXT_UNICODE));
182 }
183
184
189
190 void addCreator(String creator) {
191 put(PdfName.CREATOR, new PdfString(creator, PdfObject.TEXT_UNICODE));
192 }
193
194
197
198 void addProducer() {
199 put(PdfName.PRODUCER, new PdfString(getVersion()));
200 }
201
202
205
206 void addCreationDate() {
207 PdfString date = new PdfDate();
208 put(PdfName.CREATIONDATE, date);
209 put(PdfName.MODDATE, date);
210 }
211
212 void addkey(String key, String value) {
213 if (key.equals("Producer") || key.equals("CreationDate"))
214 return;
215 put(new PdfName(key), new PdfString(value, PdfObject.TEXT_UNICODE));
216 }
217 }
218
219
232
233 static class PdfCatalog extends PdfDictionary {
234
235
236 PdfWriter writer;
237
238
244
245 PdfCatalog(PdfIndirectReference pages, PdfWriter writer) {
246 super(CATALOG);
247 this.writer = writer;
248 put(PdfName.PAGES, pages);
249 }
250
251
258 void addNames(TreeMap localDestinations, HashMap documentLevelJS, HashMap documentFileAttachment, PdfWriter writer) {
259 if (localDestinations.isEmpty() && documentLevelJS.isEmpty() && documentFileAttachment.isEmpty())
260 return;
261 try {
262 PdfDictionary names = new PdfDictionary();
263 if (!localDestinations.isEmpty()) {
264 PdfArray ar = new PdfArray();
265 for (Iterator i = localDestinations.entrySet().iterator(); i.hasNext();) {
266 Map.Entry entry = (Map.Entry) i.next();
267 String name = (String) entry.getKey();
268 Object obj[] = (Object[]) entry.getValue();
269 if (obj[2] == null)
270 continue;
271 PdfIndirectReference ref = (PdfIndirectReference)obj[1];
272 ar.add(new PdfString(name, null));
273 ar.add(ref);
274 }
275 if (ar.size() > 0) {
276 PdfDictionary dests = new PdfDictionary();
277 dests.put(PdfName.NAMES, ar);
278 names.put(PdfName.DESTS, writer.addToBody(dests).getIndirectReference());
279 }
280 }
281 if (!documentLevelJS.isEmpty()) {
282 PdfDictionary tree = PdfNameTree.writeTree(documentLevelJS, writer);
283 names.put(PdfName.JAVASCRIPT, writer.addToBody(tree).getIndirectReference());
284 }
285 if (!documentFileAttachment.isEmpty()) {
286 names.put(PdfName.EMBEDDEDFILES, writer.addToBody(PdfNameTree.writeTree(documentFileAttachment, writer)).getIndirectReference());
287 }
288 if (names.size() > 0)
289 put(PdfName.NAMES, writer.addToBody(names).getIndirectReference());
290 }
291 catch (IOException e) {
292 throw new ExceptionConverter(e);
293 }
294 }
295
296
300 void setOpenAction(PdfAction action) {
301 put(PdfName.OPENACTION, action);
302 }
303
304
305
309 void setAdditionalActions(PdfDictionary actions) {
310 try {
311 put(PdfName.AA, writer.addToBody(actions).getIndirectReference());
312 } catch (Exception e) {
313 throw new ExceptionConverter(e);
314 }
315 }
316 }
317
318
319
320
323 public PdfDocument() {
324 super();
325 addProducer();
326 addCreationDate();
327 }
328
329
330 protected PdfWriter writer;
331
332
339 public void addWriter(PdfWriter writer) throws DocumentException {
340 if (this.writer == null) {
341 this.writer = writer;
342 annotationsImp = new PdfAnnotationsImp(writer);
343 return;
344 }
345 throw new DocumentException("You can only add a writer to a PdfDocument once.");
346 }
347
348
349
350
351
352
353 protected PdfContentByte text;
354
355
356 protected PdfContentByte graphics;
357
358
359 protected float leading = 0;
360
361
366 public float getLeading() {
367 return leading;
368 }
369
370
375 void setLeading(float leading) {
376 this.leading = leading;
377 }
378
379
380 protected int alignment = Element.ALIGN_LEFT;
381
382
383 protected float currentHeight = 0;
384
385
389 protected boolean isSectionTitle = false;
390
391
395 protected int leadingCount = 0;
396
397
398 protected PdfAction anchorAction = null;
399
400
407 public boolean add(Element element) throws DocumentException {
408 if (writer != null && writer.isPaused()) {
409 return false;
410 }
411 try {
412 switch(element.type()) {
413
414 case Element.HEADER:
415 info.addkey(((Meta)element).getName(), ((Meta)element).getContent());
416 break;
417 case Element.TITLE:
418 info.addTitle(((Meta)element).getContent());
419 break;
420 case Element.SUBJECT:
421 info.addSubject(((Meta)element).getContent());
422 break;
423 case Element.KEYWORDS:
424 info.addKeywords(((Meta)element).getContent());
425 break;
426 case Element.AUTHOR:
427 info.addAuthor(((Meta)element).getContent());
428 break;
429 case Element.CREATOR:
430 info.addCreator(((Meta)element).getContent());
431 break;
432 case Element.PRODUCER:
433
434 info.addProducer();
435 break;
436 case Element.CREATIONDATE:
437
438 info.addCreationDate();
439 break;
440
441
442 case Element.CHUNK: {
443
444 if (line == null) {
445 carriageReturn();
446 }
447
448
449 PdfChunk chunk = new PdfChunk((Chunk) element, anchorAction);
450
451 {
452 PdfChunk overflow;
453 while ((overflow = line.add(chunk)) != null) {
454 carriageReturn();
455 chunk = overflow;
456 chunk.trimFirstSpace();
457 }
458 }
459 pageEmpty = false;
460 if (chunk.isAttribute(Chunk.NEWPAGE)) {
461 newPage();
462 }
463 break;
464 }
465 case Element.ANCHOR: {
466 leadingCount++;
467 Anchor anchor = (Anchor) element;
468 String url = anchor.getReference();
469 leading = anchor.getLeading();
470 if (url != null) {
471 anchorAction = new PdfAction(url);
472 }
473
474 element.process(this);
475 anchorAction = null;
476 leadingCount--;
477 break;
478 }
479 case Element.ANNOTATION: {
480 if (line == null) {
481 carriageReturn();
482 }
483 Annotation annot = (Annotation) element;
484 Rectangle rect = new Rectangle(0, 0);
485 if (line != null)
486 rect = new Rectangle(annot.llx(indentRight() - line.widthLeft()), annot.lly(indentTop() - currentHeight), annot.urx(indentRight() - line.widthLeft() + 20), annot.ury(indentTop() - currentHeight - 20));
487 PdfAnnotation an = PdfAnnotationsImp.convertAnnotation(writer, annot, rect);
488 annotationsImp.addPlainAnnotation(an);
489 pageEmpty = false;
490 break;
491 }
492 case Element.PHRASE: {
493 leadingCount++;
494
495 leading = ((Phrase) element).getLeading();
496
497 element.process(this);
498 leadingCount--;
499 break;
500 }
501 case Element.PARAGRAPH: {
502 leadingCount++;
503
504 Paragraph paragraph = (Paragraph) element;
505 addSpacing(paragraph.getSpacingBefore(), leading, paragraph.getFont());
506
507
508 alignment = paragraph.getAlignment();
509 leading = paragraph.getTotalLeading();
510 carriageReturn();
511
512
513 if (currentHeight + line.height() + leading > indentTop() - indentBottom()) {
514 newPage();
515 }
516 indentation.indentLeft += paragraph.getIndentationLeft();
517 indentation.indentRight += paragraph.getIndentationRight();
518 carriageReturn();
519
520 PdfPageEvent pageEvent = writer.getPageEvent();
521 if (pageEvent != null && !isSectionTitle)
522 pageEvent.onParagraph(writer, this, indentTop() - currentHeight);
523
524
525 if (paragraph.getKeepTogether()) {
526 carriageReturn();
527 PdfPTable table = new PdfPTable(1);
528 table.setWidthPercentage(100f);
529 PdfPCell cell = new PdfPCell();
530 cell.addElement(paragraph);
531 cell.setBorder(Table.NO_BORDER);
532 cell.setPadding(0);
533 table.addCell(cell);
534 indentation.indentLeft -= paragraph.getIndentationLeft();
535 indentation.indentRight -= paragraph.getIndentationRight();
536 this.add(table);
537 indentation.indentLeft += paragraph.getIndentationLeft();
538 indentation.indentRight += paragraph.getIndentationRight();
539 }
540 else {
541 line.setExtraIndent(paragraph.getFirstLineIndent());
542 element.process(this);
543 carriageReturn();
544 addSpacing(paragraph.getSpacingAfter(), paragraph.getTotalLeading(), paragraph.getFont());
545 }
546
547 if (pageEvent != null && !isSectionTitle)
548 pageEvent.onParagraphEnd(writer, this, indentTop() - currentHeight);
549
550 alignment = Element.ALIGN_LEFT;
551 indentation.indentLeft -= paragraph.getIndentationLeft();
552 indentation.indentRight -= paragraph.getIndentationRight();
553 carriageReturn();
554 leadingCount--;
555 break;
556 }
557 case Element.SECTION:
558 case Element.CHAPTER: {
559
560
561 Section section = (Section) element;
562 PdfPageEvent pageEvent = writer.getPageEvent();
563
564 boolean hasTitle = section.isNotAddedYet()
565 && section.getTitle() != null;
566
567
568 if (section.isTriggerNewPage()) {
569 newPage();
570 }
571
572 if (hasTitle) {
573 float fith = indentTop() - currentHeight;
574 int rotation = pageSize.getRotation();
575 if (rotation == 90 || rotation == 180)
576 fith = pageSize.getHeight() - fith;
577 PdfDestination destination = new PdfDestination(PdfDestination.FITH, fith);
578 while (currentOutline.level() >= section.getDepth()) {
579 currentOutline = currentOutline.parent();
580 }
581 PdfOutline outline = new PdfOutline(currentOutline, destination, section.getBookmarkTitle(), section.isBookmarkOpen());
582 currentOutline = outline;
583 }
584
585
586 carriageReturn();
587 indentation.sectionIndentLeft += section.getIndentationLeft();
588 indentation.sectionIndentRight += section.getIndentationRight();
589
590 if (section.isNotAddedYet() && pageEvent != null)
591 if (element.type() == Element.CHAPTER)
592 pageEvent.onChapter(writer, this, indentTop() - currentHeight, section.getTitle());
593 else
594 pageEvent.onSection(writer, this, indentTop() - currentHeight, section.getDepth(), section.getTitle());
595
596
597 if (hasTitle) {
598 isSectionTitle = true;
599 add(section.getTitle());
600 isSectionTitle = false;
601 }
602 indentation.sectionIndentLeft += section.getIndentation();
603
604 element.process(this);
605 flushLines();
606
607 indentation.sectionIndentLeft -= (section.getIndentationLeft() + section.getIndentation());
608 indentation.sectionIndentRight -= section.getIndentationRight();
609
610 if (section.isComplete() && pageEvent != null)
611 if (element.type() == Element.CHAPTER)
612 pageEvent.onChapterEnd(writer, this, indentTop() - currentHeight);
613 else
614 pageEvent.onSectionEnd(writer, this, indentTop() - currentHeight);
615
616 break;
617 }
618 case Element.LIST: {
619
620 List list = (List) element;
621 if (list.isAlignindent()) {
622 list.normalizeIndentation();
623 }
624
625 indentation.listIndentLeft += list.getIndentationLeft();
626 indentation.indentRight += list.getIndentationRight();
627
628 element.process(this);
629
630 indentation.listIndentLeft -= list.getIndentationLeft();
631 indentation.indentRight -= list.getIndentationRight();
632 carriageReturn();
633 break;
634 }
635 case Element.LISTITEM: {
636 leadingCount++;
637
638 ListItem listItem = (ListItem) element;
639
640 addSpacing(listItem.getSpacingBefore(), leading, listItem.getFont());
641
642
643 alignment = listItem.getAlignment();
644 indentation.listIndentLeft += listItem.getIndentationLeft();
645 indentation.indentRight += listItem.getIndentationRight();
646 leading = listItem.getTotalLeading();
647 carriageReturn();
648
649
650 line.setListItem(listItem);
651
652 element.process(this);
653
654 addSpacing(listItem.getSpacingAfter(), listItem.getTotalLeading(), listItem.getFont());
655
656
657 if (line.hasToBeJustified()) {
658 line.resetAlignment();
659 }
660
661 carriageReturn();
662 indentation.listIndentLeft -= listItem.getIndentationLeft();
663 indentation.indentRight -= listItem.getIndentationRight();
664 leadingCount--;
665 break;
666 }
667 case Element.RECTANGLE: {
668 Rectangle rectangle = (Rectangle) element;
669 graphics.rectangle(rectangle);
670 pageEmpty = false;
671 break;
672 }
673 case Element.PTABLE: {
674 PdfPTable ptable = (PdfPTable)element;
675 if (ptable.size() <= ptable.getHeaderRows())
676 break;
677
678
679 ensureNewLine();
680 flushLines();
681
682 addPTable(ptable);
683 pageEmpty = false;
684 newLine();
685 break;
686 }
687 case Element.MULTI_COLUMN_TEXT: {
688 ensureNewLine();
689 flushLines();
690 MultiColumnText multiText = (MultiColumnText) element;
691 float height = multiText.write(writer.getDirectContent(), this, indentTop() - currentHeight);
692 currentHeight += height;
693 text.moveText(0, -1f* height);
694 pageEmpty = false;
695 break;
696 }
697 case Element.TABLE : {
698 if (element instanceof SimpleTable) {
699 PdfPTable ptable = ((SimpleTable)element).createPdfPTable();
700 if (ptable.size() <= ptable.getHeaderRows())
701 break;
702
703
704 ensureNewLine();
705 flushLines();
706 addPTable(ptable);
707 pageEmpty = false;
708 break;
709 } else if (element instanceof Table) {
710 try {
711 PdfPTable ptable = ((Table)element).createPdfPTable();
712 if (ptable.size() <= ptable.getHeaderRows())
713 break;
714
715 ensureNewLine();
716 flushLines();
717 addPTable(ptable);
718 pageEmpty = false;
719 break;
720 }
721 catch(BadElementException bee) {
722
723
724 float offset = ((Table)element).getOffset();
725 if (Float.isNaN(offset))
726 offset = leading;
727 carriageReturn();
728 lines.add(new PdfLine(indentLeft(), indentRight(), alignment, offset));
729 currentHeight += offset;
730 addPdfTable((Table)element);
731 }
732 } else {
733 return false;
734 }
735 break;
736 }
737 case Element.JPEG:
738 case Element.JPEG2000:
739 case Element.JBIG2:
740 case Element.IMGRAW:
741 case Element.IMGTEMPLATE: {
742
743 add((Image) element);
744 break;
745 }
746 case Element.YMARK: {
747 DrawInterface zh = (DrawInterface)element;
748 zh.draw(graphics, indentLeft(), indentBottom(), indentRight(), indentTop(), indentTop() - currentHeight - (leadingCount > 0 ? leading : 0));
749 pageEmpty = false;
750 break;
751 }
752 case Element.MARKED: {
753 MarkedObject mo;
754 if (element instanceof MarkedSection) {
755 mo = ((MarkedSection)element).getTitle();
756 if (mo != null) {
757 mo.process(this);
758 }
759 }
760 mo = (MarkedObject)element;
761 mo.process(this);
762 break;
763 }
764 default:
765 return false;
766 }
767 lastElementType = element.type();
768 return true;
769 }
770 catch(Exception e) {
771 throw new DocumentException(e);
772 }
773 }
774
775
776
777
783 public void open() {
784 if (!open) {
785 super.open();
786 writer.open();
787 rootOutline = new PdfOutline(writer);
788 currentOutline = rootOutline;
789 }
790 try {
791 initPage();
792 }
793 catch(DocumentException de) {
794 throw new ExceptionConverter(de);
795 }
796 }
797
798
799
800
806 public void close() {
807 if (close) {
808 return;
809 }
810 try {
811 boolean wasImage = (imageWait != null);
812 newPage();
813 if (imageWait != null || wasImage) newPage();
814 if (annotationsImp.hasUnusedAnnotations())
815 throw new RuntimeException("Not all annotations could be added to the document (the document doesn't have enough pages).");
816 PdfPageEvent pageEvent = writer.getPageEvent();
817 if (pageEvent != null)
818 pageEvent.onCloseDocument(writer, this);
819 super.close();
820
821 writer.addLocalDestinations(localDestinations);
822 calculateOutlineCount();
823 writeOutlines();
824 }
825 catch(Exception e) {
826 throw ExceptionConverter.convertException(e);
827 }
828
829 writer.close();
830 }
831
832
833 protected int textEmptySize;
834
835
836
837 protected byte[] xmpMetadata = null;
838
842 public void setXmpMetadata(byte[] xmpMetadata) {
843 this.xmpMetadata = xmpMetadata;
844 }
845
846
851 public boolean newPage() {
852 lastElementType = -1;
853 if (writer == null || (writer.getDirectContent().size() == 0 && writer.getDirectContentUnder().size() == 0 && (pageEmpty || writer.isPaused()))) {
854 setNewPageSizeAndMargins();
855 return false;
856 }
857 if (!open || close) {
858 throw new RuntimeException("The document isn't open.");
859 }
860 PdfPageEvent pageEvent = writer.getPageEvent();
861 if (pageEvent != null)
862 pageEvent.onEndPage(writer, this);
863
864
865 super.newPage();
866
867
868 indentation.imageIndentLeft = 0;
869 indentation.imageIndentRight = 0;
870
871 try {
872
873 flushLines();
874
875
876
877
878 int rotation = pageSize.getRotation();
879
880
881 if (writer.isPdfX()) {
882 if (thisBoxSize.containsKey("art") && thisBoxSize.containsKey("trim"))
883 throw new PdfXConformanceException("Only one of ArtBox or TrimBox can exist in the page.");
884 if (!thisBoxSize.containsKey("art") && !thisBoxSize.containsKey("trim")) {
885 if (thisBoxSize.containsKey("crop"))
886 thisBoxSize.put("trim", thisBoxSize.get("crop"));
887 else
888 thisBoxSize.put("trim", new PdfRectangle(pageSize, pageSize.getRotation()));
889 }
890 }
891
892
893 pageResources.addDefaultColorDiff(writer.getDefaultColorspace());
894 if (writer.isRgbTransparencyBlending()) {
895 PdfDictionary dcs = new PdfDictionary();
896 dcs.put(PdfName.CS, PdfName.DEVICERGB);
897 pageResources.addDefaultColorDiff(dcs);
898 }
899 PdfDictionary resources = pageResources.getResources();
900
901
902
903 PdfPage page = new PdfPage(new PdfRectangle(pageSize, rotation), thisBoxSize, resources, rotation);
904 page.put(PdfName.TABS, writer.getTabs());
905
906
907
908
909 if (xmpMetadata != null) {
910 PdfStream xmp = new PdfStream(xmpMetadata);
911 xmp.put(PdfName.TYPE, PdfName.METADATA);
912 xmp.put(PdfName.SUBTYPE, PdfName.XML);
913 PdfEncryption crypto = writer.getEncryption();
914 if (crypto != null && !crypto.isMetadataEncrypted()) {
915 PdfArray ar = new PdfArray();
916 ar.add(PdfName.CRYPT);
917 xmp.put(PdfName.FILTER, ar);
918 }
919 page.put(PdfName.METADATA, writer.addToBody(xmp).getIndirectReference());
920 }
921
922
923 if (this.transition!=null) {
924 page.put(PdfName.TRANS, this.transition.getTransitionDictionary());
925 transition = null;
926 }
927 if (this.duration>0) {
928 page.put(PdfName.DUR,new PdfNumber(this.duration));
929 duration = 0;
930 }
931 if (pageAA != null) {
932 page.put(PdfName.AA, writer.addToBody(pageAA).getIndirectReference());
933 pageAA = null;
934 }
935
936
937 if (thumb != null) {
938 page.put(PdfName.THUMB, thumb);
939 thumb = null;
940 }
941
942
943 if (writer.getUserunit() > 0f) {
944 page.put(PdfName.USERUNIT, new PdfNumber(writer.getUserunit()));
945 }
946
947
948 if (annotationsImp.hasUnusedAnnotations()) {
949 PdfArray array = annotationsImp.rotateAnnotations(writer, pageSize);
950 if (array.size() != 0)
951 page.put(PdfName.ANNOTS, array);
952 }
953
954
955 if (writer.isTagged())
956 page.put(PdfName.STRUCTPARENTS, new PdfNumber(writer.getCurrentPageNumber() - 1));
957
958 if (text.size() > textEmptySize)
959 text.endText();
960 else
961 text = null;
962 writer.add(page, new PdfContents(writer.getDirectContentUnder(), graphics, text, writer.getDirectContent(), pageSize));
963
964 initPage();
965 }
966 catch(DocumentException de) {
967
968 throw new ExceptionConverter(de);
969 }
970 catch (IOException ioe) {
971 throw new ExceptionConverter(ioe);
972 }
973 return true;
974 }
975
976
977
978
984 public boolean setPageSize(Rectangle pageSize) {
985 if (writer != null && writer.isPaused()) {
986 return false;
987 }
988 nextPageSize = new Rectangle(pageSize);
989 return true;
990 }
991
992
993
994
995 protected float nextMarginLeft;
996
997
998 protected float nextMarginRight;
999
1000
1001 protected float nextMarginTop;
1002
1003
1004 protected float nextMarginBottom;
1005
1006
1015 public boolean setMargins(float marginLeft, float marginRight, float marginTop, float marginBottom) {
1016 if (writer != null && writer.isPaused()) {
1017 return false;
1018 }
1019 nextMarginLeft = marginLeft;
1020 nextMarginRight = marginRight;
1021 nextMarginTop = marginTop;
1022 nextMarginBottom = marginBottom;
1023 return true;
1024 }
1025
1026
1027
1028
1031 public boolean setMarginMirroring(boolean MarginMirroring) {
1032 if (writer != null && writer.isPaused()) {
1033 return false;
1034 }
1035 return super.setMarginMirroring(MarginMirroring);
1036 }
1037
1038
1042 public boolean setMarginMirroringTopBottom(boolean MarginMirroringTopBottom) {
1043 if (writer != null && writer.isPaused()) {
1044 return false;
1045 }
1046 return super.setMarginMirroringTopBottom(MarginMirroringTopBottom);
1047 }
1048
1049
1050
1051
1056 public void setPageCount(int pageN) {
1057 if (writer != null && writer.isPaused()) {
1058 return;
1059 }
1060 super.setPageCount(pageN);
1061 }
1062
1063
1064
1065
1068 public void resetPageCount() {
1069 if (writer != null && writer.isPaused()) {
1070 return;
1071 }
1072 super.resetPageCount();
1073 }
1074
1075
1076
1077
1082 public void setHeader(HeaderFooter header) {
1083 if (writer != null && writer.isPaused()) {
1084 return;
1085 }
1086 super.setHeader(header);
1087 }
1088
1089
1090
1091
1094 public void resetHeader() {
1095 if (writer != null && writer.isPaused()) {
1096 return;
1097 }
1098 super.resetHeader();
1099 }
1100
1101
1102
1103
1108 public void setFooter(HeaderFooter footer) {
1109 if (writer != null && writer.isPaused()) {
1110 return;
1111 }
1112 super.setFooter(footer);
1113 }
1114
1115
1116
1117
1120 public void resetFooter() {
1121 if (writer != null && writer.isPaused()) {
1122 return;
1123 }
1124 super.resetFooter();
1125 }
1126
1127
1128
1129
1130 protected boolean firstPageEvent = true;
1131
1132
1138 protected void initPage() throws DocumentException {
1139
1140 pageN++;
1141
1142
1143 annotationsImp.resetAnnotations();
1144 pageResources = new PageResources();
1145
1146 writer.resetContent();
1147 graphics = new PdfContentByte(writer);
1148 text = new PdfContentByte(writer);
1149 text.reset();
1150 text.beginText();
1151 textEmptySize = text.size();
1152
1153 markPoint = 0;
1154 setNewPageSizeAndMargins();
1155 imageEnd = -1;
1156 indentation.imageIndentRight = 0;
1157 indentation.imageIndentLeft = 0;
1158 indentation.indentBottom = 0;
1159 indentation.indentTop = 0;
1160 currentHeight = 0;
1161
1162
1163 thisBoxSize = new HashMap(boxSize);
1164 if (pageSize.getBackgroundColor() != null
1165 || pageSize.hasBorders()
1166 || pageSize.getBorderColor() != null) {
1167 add(pageSize);
1168 }
1169
1170 float oldleading = leading;
1171 int oldAlignment = alignment;
1172
1173 doFooter();
1174
1175 text.moveText(left(), top());
1176 doHeader();
1177 pageEmpty = true;
1178
1179 try {
1180 if (imageWait != null) {
1181 add(imageWait);
1182 imageWait = null;
1183 }
1184 }
1185 catch(Exception e) {
1186 throw new ExceptionConverter(e);
1187 }
1188 leading = oldleading;
1189 alignment = oldAlignment;
1190 carriageReturn();
1191
1192 PdfPageEvent pageEvent = writer.getPageEvent();
1193 if (pageEvent != null) {
1194 if (firstPageEvent) {
1195 pageEvent.onOpenDocument(writer, this);
1196 }
1197 pageEvent.onStartPage(writer, this);
1198 }
1199 firstPageEvent = false;
1200 }
1201
1202
1203 protected PdfLine line = null;
1204
1205 protected ArrayList lines = new ArrayList();
1206
1207
1211 protected void newLine() throws DocumentException {
1212 lastElementType = -1;
1213 carriageReturn();
1214 if (lines != null && !lines.isEmpty()) {
1215 lines.add(line);
1216 currentHeight += line.height();
1217 }
1218 line = new PdfLine(indentLeft(), indentRight(), alignment, leading);
1219 }
1220
1221
1225 protected void carriageReturn() {
1226
1227 if (lines == null) {
1228 lines = new ArrayList();
1229 }
1230
1231 if (line != null) {
1232
1233 if (currentHeight + line.height() + leading < indentTop() - indentBottom()) {
1234
1235 if (line.size() > 0) {
1236 currentHeight += line.height();
1237 lines.add(line);
1238 pageEmpty = false;
1239 }
1240 }
1241
1242 else {
1243 newPage();
1244 }
1245 }
1246 if (imageEnd > -1 && currentHeight > imageEnd) {
1247 imageEnd = -1;
1248 indentation.imageIndentRight = 0;
1249 indentation.imageIndentLeft = 0;
1250 }
1251
1252 line = new PdfLine(indentLeft(), indentRight(), alignment, leading);
1253 }
1254
1255
1262 public float getVerticalPosition(boolean ensureNewLine) {
1263
1264 if (ensureNewLine) {
1265 ensureNewLine();
1266 }
1267 return top() - currentHeight - indentation.indentTop;
1268 }
1269
1270
1271 protected int lastElementType = -1;
1272
1273
1276 protected void ensureNewLine() {
1277 try {
1278 if ((lastElementType == Element.PHRASE) ||
1279 (lastElementType == Element.CHUNK)) {
1280 newLine();
1281 flushLines();
1282 }
1283 } catch (DocumentException ex) {
1284 throw new ExceptionConverter(ex);
1285 }
1286 }
1287
1288
1294 protected float flushLines() throws DocumentException {
1295
1296 if (lines == null) {
1297 return 0;
1298 }
1299
1300 if (line != null && line.size() > 0) {
1301 lines.add(line);
1302 line = new PdfLine(indentLeft(), indentRight(), alignment, leading);
1303 }
1304
1305
1306 if (lines.isEmpty()) {
1307 return 0;
1308 }
1309
1310
1311 Object currentValues[] = new Object[2];
1312 PdfFont currentFont = null;
1313 float displacement = 0;
1314 PdfLine l;
1315 Float lastBaseFactor = new Float(0);
1316 currentValues[1] = lastBaseFactor;
1317
1318 for (Iterator i = lines.iterator(); i.hasNext(); ) {
1319
1320
1321 l = (PdfLine) i.next();
1322
1323 float moveTextX = l.indentLeft() - indentLeft() + indentation.indentLeft + indentation.listIndentLeft + indentation.sectionIndentLeft;
1324 text.moveText(moveTextX, -l.height());
1325
1326 if (l.listSymbol() != null) {
1327 ColumnText.showTextAligned(graphics, Element.ALIGN_LEFT, new Phrase(l.listSymbol()), text.getXTLM() - l.listIndent(), text.getYTLM(), 0);
1328 }
1329
1330 currentValues[0] = currentFont;
1331
1332 writeLineToContent(l, text, graphics, currentValues, writer.getSpaceCharRatio());
1333
1334 currentFont = (PdfFont)currentValues[0];
1335 displacement += l.height();
1336 text.moveText(-moveTextX, 0);
1337
1338 }
1339 lines = new ArrayList();
1340 return displacement;
1341 }
1342
1343
1344 static final String hangingPunctuation = ".,;:'";
1345
1346
1358 void writeLineToContent(PdfLine line, PdfContentByte text, PdfContentByte graphics, Object currentValues[], float ratio) throws DocumentException {
1359 PdfFont currentFont = (PdfFont)(currentValues[0]);
1360 float lastBaseFactor = ((Float)(currentValues[1])).floatValue();
1361 PdfChunk chunk;
1362 int numberOfSpaces;
1363 int lineLen;
1364 boolean isJustified;
1365 float hangingCorrection = 0;
1366 float hScale = 1;
1367 float lastHScale = Float.NaN;
1368 float baseWordSpacing = 0;
1369 float baseCharacterSpacing = 0;
1370 float glueWidth = 0;
1371
1372 numberOfSpaces = line.numberOfSpaces();
1373 lineLen = line.GetLineLengthUtf32();
1374
1375 isJustified = line.hasToBeJustified() && (numberOfSpaces != 0 || lineLen > 1);
1376 int separatorCount = line.getSeparatorCount();
1377 if (separatorCount > 0) {
1378 glueWidth = line.widthLeft() / separatorCount;
1379 }
1380 else if (isJustified) {
1381 if (line.isNewlineSplit() && line.widthLeft() >= (lastBaseFactor * (ratio * numberOfSpaces + lineLen - 1))) {
1382 if (line.isRTL()) {
1383 text.moveText(line.widthLeft() - lastBaseFactor * (ratio * numberOfSpaces + lineLen - 1), 0);
1384 }
1385 baseWordSpacing = ratio * lastBaseFactor;
1386 baseCharacterSpacing = lastBaseFactor;
1387 }
1388 else {
1389 float width = line.widthLeft();
1390 PdfChunk last = line.getChunk(line.size() - 1);
1391 if (last != null) {
1392 String s = last.toString();
1393 char c;
1394 if (s.length() > 0 && hangingPunctuation.indexOf((c = s.charAt(s.length() - 1))) >= 0) {
1395 float oldWidth = width;
1396 width += last.font().width(c) * 0.4f;
1397 hangingCorrection = width - oldWidth;
1398 }
1399 }
1400 float baseFactor = width / (ratio * numberOfSpaces + lineLen - 1);
1401 baseWordSpacing = ratio * baseFactor;
1402 baseCharacterSpacing = baseFactor;
1403 lastBaseFactor = baseFactor;
1404 }
1405 }
1406
1407 int lastChunkStroke = line.getLastStrokeChunk();
1408 int chunkStrokeIdx = 0;
1409 float xMarker = text.getXTLM();
1410 float baseXMarker = xMarker;
1411 float yMarker = text.getYTLM();
1412 boolean adjustMatrix = false;
1413 float tabPosition = 0;
1414
1415
1416 for (Iterator j = line.iterator(); j.hasNext(); ) {
1417 chunk = (PdfChunk) j.next();
1418 Color color = chunk.color();
1419 hScale = 1;
1420
1421 if (chunkStrokeIdx <= lastChunkStroke) {
1422 float width;
1423 if (isJustified) {
1424 width = chunk.getWidthCorrected(baseCharacterSpacing, baseWordSpacing);
1425 }
1426 else {
1427 width = chunk.width();
1428 }
1429 if (chunk.isStroked()) {
1430 PdfChunk nextChunk = line.getChunk(chunkStrokeIdx + 1);
1431 if (chunk.isSeparator()) {
1432 width = glueWidth;
1433 Object[] sep = (Object[])chunk.getAttribute(Chunk.SEPARATOR);
1434 DrawInterface di = (DrawInterface)sep[0];
1435 Boolean vertical = (Boolean)sep[1];
1436 float fontSize = chunk.font().size();
1437 float ascender = chunk.font().getFont().getFontDescriptor(BaseFont.ASCENT, fontSize);
1438 float descender = chunk.font().getFont().getFontDescriptor(BaseFont.DESCENT, fontSize);
1439 if (vertical.booleanValue()) {
1440 di.draw(graphics, baseXMarker, yMarker + descender, baseXMarker + line.getOriginalWidth(), ascender - descender, yMarker);
1441 }
1442 else {
1443 di.draw(graphics, xMarker, yMarker + descender, xMarker + width, ascender - descender, yMarker);
1444 }
1445 }
1446 if (chunk.isTab()) {
1447 Object[] tab = (Object[])chunk.getAttribute(Chunk.TAB);
1448 DrawInterface di = (DrawInterface)tab[0];
1449 tabPosition = ((Float)tab[1]).floatValue() + ((Float)tab[3]).floatValue();
1450 float fontSize = chunk.font().size();
1451 float ascender = chunk.font().getFont().getFontDescriptor(BaseFont.ASCENT, fontSize);
1452 float descender = chunk.font().getFont().getFontDescriptor(BaseFont.DESCENT, fontSize);
1453 if (tabPosition > xMarker) {
1454 di.draw(graphics, xMarker, yMarker + descender, tabPosition, ascender - descender, yMarker);
1455 }
1456 float tmp = xMarker;
1457 xMarker = tabPosition;
1458 tabPosition = tmp;
1459 }
1460 if (chunk.isAttribute(Chunk.BACKGROUND)) {
1461 float subtract = lastBaseFactor;
1462 if (nextChunk != null && nextChunk.isAttribute(Chunk.BACKGROUND))
1463 subtract = 0;
1464 if (nextChunk == null)
1465 subtract += hangingCorrection;
1466 float fontSize = chunk.font().size();
1467 float ascender = chunk.font().getFont().getFontDescriptor(BaseFont.ASCENT, fontSize);
1468 float descender = chunk.font().getFont().getFontDescriptor(BaseFont.DESCENT, fontSize);
1469 Object bgr[] = (Object[])chunk.getAttribute(Chunk.BACKGROUND);
1470 graphics.setColorFill((Color)bgr[0]);
1471 float extra[] = (float[])bgr[1];
1472 graphics.rectangle(xMarker - extra[0],
1473 yMarker + descender - extra[1] + chunk.getTextRise(),
1474 width - subtract + extra[0] + extra[2],
1475 ascender - descender + extra[1] + extra[3]);
1476 graphics.fill();
1477 graphics.setGrayFill(0);
1478 }
1479 if (chunk.isAttribute(Chunk.UNDERLINE)) {
1480 float subtract = lastBaseFactor;
1481 if (nextChunk != null && nextChunk.isAttribute(Chunk.UNDERLINE))
1482 subtract = 0;
1483 if (nextChunk == null)
1484 subtract += hangingCorrection;
1485 Object unders[][] = (Object[][])chunk.getAttribute(Chunk.UNDERLINE);
1486 Color scolor = null;
1487 for (int k = 0; k < unders.length; ++k) {
1488 Object obj[] = unders[k];
1489 scolor = (Color)obj[0];
1490 float ps[] = (float[])obj[1];
1491 if (scolor == null)
1492 scolor = color;
1493 if (scolor != null)
1494 graphics.setColorStroke(scolor);
1495 float fsize = chunk.font().size();
1496 graphics.setLineWidth(ps[0] + fsize * ps[1]);
1497 float shift = ps[2] + fsize * ps[3];
1498 int cap2 = (int)ps[4];
1499 if (cap2 != 0)
1500 graphics.setLineCap(cap2);
1501 graphics.moveTo(xMarker, yMarker + shift);
1502 graphics.lineTo(xMarker + width - subtract, yMarker + shift);
1503 graphics.stroke();
1504 if (scolor != null)
1505 graphics.resetGrayStroke();
1506 if (cap2 != 0)
1507 graphics.setLineCap(0);
1508 }
1509 graphics.setLineWidth(1);
1510 }
1511 if (chunk.isAttribute(Chunk.ACTION)) {
1512 float subtract = lastBaseFactor;
1513 if (nextChunk != null && nextChunk.isAttribute(Chunk.ACTION))
1514 subtract = 0;
1515 if (nextChunk == null)
1516 subtract += hangingCorrection;
1517 text.addAnnotation(new PdfAnnotation(writer, xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.font().size(), (PdfAction)chunk.getAttribute(Chunk.ACTION)));
1518 }
1519 if (chunk.isAttribute(Chunk.REMOTEGOTO)) {
1520 float subtract = lastBaseFactor;
1521 if (nextChunk != null && nextChunk.isAttribute(Chunk.REMOTEGOTO))
1522 subtract = 0;
1523 if (nextChunk == null)
1524 subtract += hangingCorrection;
1525 Object obj[] = (Object[])chunk.getAttribute(Chunk.REMOTEGOTO);
1526 String filename = (String)obj[0];
1527 if (obj[1] instanceof String)
1528 remoteGoto(filename, (String)obj[1], xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.font().size());
1529 else
1530 remoteGoto(filename, ((Integer)obj[1]).intValue(), xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.font().size());
1531 }
1532 if (chunk.isAttribute(Chunk.LOCALGOTO)) {
1533 float subtract = lastBaseFactor;
1534 if (nextChunk != null && nextChunk.isAttribute(Chunk.LOCALGOTO))
1535 subtract = 0;
1536 if (nextChunk == null)
1537 subtract += hangingCorrection;
1538 localGoto((String)chunk.getAttribute(Chunk.LOCALGOTO), xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.font().size());
1539 }
1540 if (chunk.isAttribute(Chunk.LOCALDESTINATION)) {
1541 float subtract = lastBaseFactor;
1542 if (nextChunk != null && nextChunk.isAttribute(Chunk.LOCALDESTINATION))
1543 subtract = 0;
1544 if (nextChunk == null)
1545 subtract += hangingCorrection;
1546 localDestination((String)chunk.getAttribute(Chunk.LOCALDESTINATION), new PdfDestination(PdfDestination.XYZ, xMarker, yMarker + chunk.font().size(), 0));
1547 }
1548 if (chunk.isAttribute(Chunk.GENERICTAG)) {
1549 float subtract = lastBaseFactor;
1550 if (nextChunk != null && nextChunk.isAttribute(Chunk.GENERICTAG))
1551 subtract = 0;
1552 if (nextChunk == null)
1553 subtract += hangingCorrection;
1554 Rectangle rect = new Rectangle(xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.font().size());
1555 PdfPageEvent pev = writer.getPageEvent();
1556 if (pev != null)
1557 pev.onGenericTag(writer, this, rect, (String)chunk.getAttribute(Chunk.GENERICTAG));
1558 }
1559 if (chunk.isAttribute(Chunk.PDFANNOTATION)) {
1560 float subtract = lastBaseFactor;
1561 if (nextChunk != null && nextChunk.isAttribute(Chunk.PDFANNOTATION))
1562 subtract = 0;
1563 if (nextChunk == null)
1564 subtract += hangingCorrection;
1565 float fontSize = chunk.font().size();
1566 float ascender = chunk.font().getFont().getFontDescriptor(BaseFont.ASCENT, fontSize);
1567 float descender = chunk.font().getFont().getFontDescriptor(BaseFont.DESCENT, fontSize);
1568 PdfAnnotation annot = PdfFormField.shallowDuplicate((PdfAnnotation)chunk.getAttribute(Chunk.PDFANNOTATION));
1569 annot.put(PdfName.RECT, new PdfRectangle(xMarker, yMarker + descender, xMarker + width - subtract, yMarker + ascender));
1570 text.addAnnotation(annot);
1571 }
1572 float params[] = (float[])chunk.getAttribute(Chunk.SKEW);
1573 Float hs = (Float)chunk.getAttribute(Chunk.HSCALE);
1574 if (params != null || hs != null) {
1575 float b = 0, c = 0;
1576 if (params != null) {
1577 b = params[0];
1578 c = params[1];
1579 }
1580 if (hs != null)
1581 hScale = hs.floatValue();
1582 text.setTextMatrix(hScale, b, c, 1, xMarker, yMarker);
1583 }
1584 if (chunk.isImage()) {
1585 Image image = chunk.getImage();
1586 float matrix[] = image.matrix();
1587 matrix[Image.CX] = xMarker + chunk.getImageOffsetX() - matrix[Image.CX];
1588 matrix[Image.CY] = yMarker + chunk.getImageOffsetY() - matrix[Image.CY];
1589 graphics.addImage(image, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
1590 text.moveText(xMarker + lastBaseFactor + image.getScaledWidth() - text.getXTLM(), 0);
1591 }
1592 }
1593 xMarker += width;
1594 ++chunkStrokeIdx;
1595 }
1596
1597 if (chunk.font().compareTo(currentFont) != 0) {
1598 currentFont = chunk.font();
1599 text.setFontAndSize(currentFont.getFont(), currentFont.size());
1600 }
1601 float rise = 0;
1602 Object textRender[] = (Object[])chunk.getAttribute(Chunk.TEXTRENDERMODE);
1603 int tr = 0;
1604 float strokeWidth = 1;
1605 Color strokeColor = null;
1606 Float fr = (Float)chunk.getAttribute(Chunk.SUBSUPSCRIPT);
1607 if (textRender != null) {
1608 tr = ((Integer)textRender[0]).intValue() & 3;
1609 if (tr != PdfContentByte.TEXT_RENDER_MODE_FILL)
1610 text.setTextRenderingMode(tr);
1611 if (tr == PdfContentByte.TEXT_RENDER_MODE_STROKE || tr == PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE) {
1612 strokeWidth = ((Float)textRender[1]).floatValue();
1613 if (strokeWidth != 1)
1614 text.setLineWidth(strokeWidth);
1615 strokeColor = (Color)textRender[2];
1616 if (strokeColor == null)
1617 strokeColor = color;
1618 if (strokeColor != null)
1619 text.setColorStroke(strokeColor);
1620 }
1621 }
1622 if (fr != null)
1623 rise = fr.floatValue();
1624 if (color != null)
1625 text.setColorFill(color);
1626 if (rise != 0)
1627 text.setTextRise(rise);
1628 if (chunk.isImage()) {
1629 adjustMatrix = true;
1630 }
1631 else if (chunk.isHorizontalSeparator()) {
1632 PdfTextArray array = new PdfTextArray();
1633 array.add(-glueWidth * 1000f / chunk.font.size() / hScale);
1634 text.showText(array);
1635 }
1636 else if (chunk.isTab()) {
1637 PdfTextArray array = new PdfTextArray();
1638 array.add((tabPosition - xMarker) * 1000f / chunk.font.size() / hScale);
1639 text.showText(array);
1640 }
1641
1642
1643 else if (isJustified && numberOfSpaces > 0 && chunk.isSpecialEncoding()) {
1644 if (hScale != lastHScale) {
1645 lastHScale = hScale;
1646 text.setWordSpacing(baseWordSpacing / hScale);
1647 text.setCharacterSpacing(baseCharacterSpacing / hScale);
1648 }
1649 String s = chunk.toString();
1650 int idx = s.indexOf(' ');
1651 if (idx < 0)
1652 text.showText(s);
1653 else {
1654 float spaceCorrection = - baseWordSpacing * 1000f / chunk.font.size() / hScale;
1655 PdfTextArray textArray = new PdfTextArray(s.substring(0, idx));
1656 int lastIdx = idx;
1657 while ((idx = s.indexOf(' ', lastIdx + 1)) >= 0) {
1658 textArray.add(spaceCorrection);
1659 textArray.add(s.substring(lastIdx, idx));
1660 lastIdx = idx;
1661 }
1662 textArray.add(spaceCorrection);
1663 textArray.add(s.substring(lastIdx));
1664 text.showText(textArray);
1665 }
1666 }
1667 else {
1668 if (isJustified && hScale != lastHScale) {
1669 lastHScale = hScale;
1670 text.setWordSpacing(baseWordSpacing / hScale);
1671 text.setCharacterSpacing(baseCharacterSpacing / hScale);
1672 }
1673 text.showText(chunk.toString());
1674 }
1675
1676 if (rise != 0)
1677 text.setTextRise(0);
1678 if (color != null)
1679 text.resetRGBColorFill();
1680 if (tr != PdfContentByte.TEXT_RENDER_MODE_FILL)
1681 text.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL);
1682 if (strokeColor != null)
1683 text.resetRGBColorStroke();
1684 if (strokeWidth != 1)
1685 text.setLineWidth(1);
1686 if (chunk.isAttribute(Chunk.SKEW) || chunk.isAttribute(Chunk.HSCALE)) {
1687 adjustMatrix = true;
1688 text.setTextMatrix(xMarker, yMarker);
1689 }
1690 }
1691 if (isJustified) {
1692 text.setWordSpacing(0);
1693 text.setCharacterSpacing(0);
1694 if (line.isNewlineSplit())
1695 lastBaseFactor = 0;
1696 }
1697 if (adjustMatrix)
1698 text.moveText(baseXMarker - text.getXTLM(), 0);
1699 currentValues[0] = currentFont;
1700 currentValues[1] = new Float(lastBaseFactor);
1701 }
1702
1703 protected Indentation indentation = new Indentation();
1704
1705
1708 public static class Indentation {
1709
1710
1711 float indentLeft = 0;
1712
1713
1714 float sectionIndentLeft = 0;
1715
1716
1717 float listIndentLeft = 0;
1718
1719
1720 float imageIndentLeft = 0;
1721
1722
1723 float indentRight = 0;
1724
1725
1726 float sectionIndentRight = 0;
1727
1728
1729 float imageIndentRight = 0;
1730
1731
1732 float indentTop = 0;
1733
1734
1735 float indentBottom = 0;
1736 }
1737
1738
1743
1744 protected float indentLeft() {
1745 return left(indentation.indentLeft + indentation.listIndentLeft + indentation.imageIndentLeft + indentation.sectionIndentLeft);
1746 }
1747
1748
1753
1754 protected float indentRight() {
1755 return right(indentation.indentRight + indentation.sectionIndentRight + indentation.imageIndentRight);
1756 }
1757
1758
1763
1764 protected float indentTop() {
1765 return top(indentation.indentTop);
1766 }
1767
1768
1773
1774 float indentBottom() {
1775 return bottom(indentation.indentBottom);
1776 }
1777
1778
1782 protected void addSpacing(float extraspace, float oldleading, Font f) {
1783 if (extraspace == 0) return;
1784 if (pageEmpty) return;
1785 if (currentHeight + line.height() + leading > indentTop() - indentBottom()) return;
1786 leading = extraspace;
1787 carriageReturn();
1788 if (f.isUnderlined() || f.isStrikethru()) {
1789 f = new Font(f);
1790 int style = f.getStyle();
1791 style &= ~Font.UNDERLINE;
1792 style &= ~Font.STRIKETHRU;
1793 f.setStyle(style);
1794 }
1795 Chunk space = new Chunk(" ", f);
1796 space.process(this);
1797 carriageReturn();
1798 leading = oldleading;
1799 }
1800
1801
1802
1803
1804 protected PdfInfo info = new PdfInfo();
1805
1806
1811
1812 PdfInfo getInfo() {
1813 return info;
1814 }
1815
1816
1822
1823 PdfCatalog getCatalog(PdfIndirectReference pages) {
1824 PdfCatalog catalog = new PdfCatalog(pages, writer);
1825
1826
1827 if (rootOutline.getKids().size() > 0) {
1828 catalog.put(PdfName.PAGEMODE, PdfName.USEOUTLINES);
1829 catalog.put(PdfName.OUTLINES, rootOutline.indirectReference());
1830 }
1831
1832
1833 writer.getPdfVersion().addToCatalog(catalog);
1834
1835
1836 viewerPreferences.addToCatalog(catalog);
1837
1838
1839 if (pageLabels != null) {
1840 catalog.put(PdfName.PAGELABELS, pageLabels.getDictionary(writer));
1841 }
1842
1843
1844 catalog.addNames(localDestinations, getDocumentLevelJS(), documentFileAttachment, writer);
1845
1846
1847 if (openActionName != null) {
1848 PdfAction action = getLocalGotoAction(openActionName);
1849 catalog.setOpenAction(action);
1850 }
1851 else if (openActionAction != null)
1852 catalog.setOpenAction(openActionAction);
1853 if (additionalActions != null) {
1854 catalog.setAdditionalActions(additionalActions);
1855 }
1856
1857
1858 if (collection != null) {
1859 catalog.put(PdfName.COLLECTION, collection);
1860 }
1861
1862
1863 if (annotationsImp.hasValidAcroForm()) {
1864 try {
1865 catalog.put(PdfName.ACROFORM, writer.addToBody(annotationsImp.getAcroForm()).getIndirectReference());
1866 }
1867 catch (IOException e) {
1868 throw new ExceptionConverter(e);
1869 }
1870 }
1871
1872 return catalog;
1873 }
1874
1875
1876
1877
1878 protected PdfOutline rootOutline;
1879
1880
1881 protected PdfOutline currentOutline;
1882
1883
1888 void addOutline(PdfOutline outline, String name) {
1889 localDestination(name, outline.getPdfDestination());
1890 }
1891
1892
1897 public PdfOutline getRootOutline() {
1898 return rootOutline;
1899 }
1900
1901
1902
1905 void calculateOutlineCount() {
1906 if (rootOutline.getKids().size() == 0)
1907 return;
1908 traverseOutlineCount(rootOutline);
1909 }
1910
1911
1914 void traverseOutlineCount(PdfOutline outline) {
1915 ArrayList kids = outline.getKids();
1916 PdfOutline parent = outline.parent();
1917 if (kids.isEmpty()) {
1918 if (parent != null) {
1919 parent.setCount(parent.getCount() + 1);
1920 }
1921 }
1922 else {
1923 for (int k = 0; k < kids.size(); ++k) {
1924 traverseOutlineCount((PdfOutline)kids.get(k));
1925 }
1926 if (parent != null) {
1927 if (outline.isOpen()) {
1928 parent.setCount(outline.getCount() + parent.getCount() + 1);
1929 }
1930 else {
1931 parent.setCount(parent.getCount() + 1);
1932 outline.setCount(-outline.getCount());
1933 }
1934 }
1935 }
1936 }
1937
1938
1941 void writeOutlines() throws IOException {
1942 if (rootOutline.getKids().size() == 0)
1943 return;
1944 outlineTree(rootOutline);
1945 writer.addToBody(rootOutline, rootOutline.indirectReference());
1946 }
1947
1948
1951 void outlineTree(PdfOutline outline) throws IOException {
1952 outline.setIndirectReference(writer.getPdfIndirectReference());
1953 if (outline.parent() != null)
1954 outline.put(PdfName.PARENT, outline.parent().indirectReference());
1955 ArrayList kids = outline.getKids();
1956 int size = kids.size();
1957 for (int k = 0; k < size; ++k)
1958 outlineTree((PdfOutline)kids.get(k));
1959 for (int k = 0; k < size; ++k) {
1960 if (k > 0)
1961 ((PdfOutline)kids.get(k)).put(PdfName.PREV, ((PdfOutline)kids.get(k - 1)).indirectReference());
1962 if (k < size - 1)
1963 ((PdfOutline)kids.get(k)).put(PdfName.NEXT, ((PdfOutline)kids.get(k + 1)).indirectReference());
1964 }
1965 if (size > 0) {
1966 outline.put(PdfName.FIRST, ((PdfOutline)kids.get(0)).indirectReference());
1967 outline.put(PdfName.LAST, ((PdfOutline)kids.get(size - 1)).indirectReference());
1968 }
1969 for (int k = 0; k < size; ++k) {
1970 PdfOutline kid = (PdfOutline)kids.get(k);
1971 writer.addToBody(kid, kid.indirectReference());
1972 }
1973 }
1974
1975
1976
1977
1978 protected PdfViewerPreferencesImp viewerPreferences = new PdfViewerPreferencesImp();
1979
1980 void setViewerPreferences(int preferences) {
1981 this.viewerPreferences.setViewerPreferences(preferences);
1982 }
1983
1984
1985 void addViewerPreference(PdfName key, PdfObject value) {
1986 this.viewerPreferences.addViewerPreference(key, value);
1987 }
1988
1989
1990
1991 protected PdfPageLabels pageLabels;
1992
1996 void setPageLabels(PdfPageLabels pageLabels) {
1997 this.pageLabels = pageLabels;
1998 }
1999
2000
2001
2002
2011 void localGoto(String name, float llx, float lly, float urx, float ury) {
2012 PdfAction action = getLocalGotoAction(name);
2013 annotationsImp.addPlainAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, action));
2014 }
2015
2016
2025 void remoteGoto(String filename, String name, float llx, float lly, float urx, float ury) {
2026 annotationsImp.addPlainAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, new PdfAction(filename, name)));
2027 }
2028
2029
2038 void remoteGoto(String filename, int page, float llx, float lly, float urx, float ury) {
2039 addAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, new PdfAction(filename, page)));
2040 }
2041
2042
2049 void setAction(PdfAction action, float llx, float lly, float urx, float ury) {
2050 addAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, action));
2051 }
2052
2053
2057 protected TreeMap localDestinations = new TreeMap();
2058
2059 PdfAction getLocalGotoAction(String name) {
2060 PdfAction action;
2061 Object obj[] = (Object[])localDestinations.get(name);
2062 if (obj == null)
2063 obj = new Object[3];
2064 if (obj[0] == null) {
2065 if (obj[1] == null) {
2066 obj[1] = writer.getPdfIndirectReference();
2067 }
2068 action = new PdfAction((PdfIndirectReference)obj[1]);
2069 obj[0] = action;
2070 localDestinations.put(name, obj);
2071 }
2072 else {
2073 action = (PdfAction)obj[0];
2074 }
2075 return action;
2076 }
2077
2078
2087 boolean localDestination(String name, PdfDestination destination) {
2088 Object obj[] = (Object[])localDestinations.get(name);
2089 if (obj == null)
2090 obj = new Object[3];
2091 if (obj[2] != null)
2092 return false;
2093 obj[2] = destination;
2094 localDestinations.put(name, obj);
2095 destination.addPage(writer.getCurrentPage());
2096 return true;
2097 }
2098
2099
2102 int jsCounter;
2103 protected HashMap documentLevelJS = new HashMap();
2104 protected static final DecimalFormat SIXTEEN_DIGITS = new DecimalFormat("0000000000000000");
2105 void addJavaScript(PdfAction js) {
2106 if (js.get(PdfName.JS) == null)
2107 throw new RuntimeException("Only JavaScript actions are allowed.");
2108 try {
2109 documentLevelJS.put(SIXTEEN_DIGITS.format(jsCounter++), writer.addToBody(js).getIndirectReference());
2110 }
2111 catch (IOException e) {
2112 throw new ExceptionConverter(e);
2113 }
2114 }
2115 void addJavaScript(String name, PdfAction js) {
2116 if (js.get(PdfName.JS) == null)
2117 throw new RuntimeException("Only JavaScript actions are allowed.");
2118 try {
2119 documentLevelJS.put(name, writer.addToBody(js).getIndirectReference());
2120 }
2121 catch (IOException e) {
2122 throw new ExceptionConverter(e);
2123 }
2124 }
2125
2126 HashMap getDocumentLevelJS() {
2127 return documentLevelJS;
2128 }
2129
2130 protected HashMap documentFileAttachment = new HashMap();
2131
2132 void addFileAttachment(String description, PdfFileSpecification fs) throws IOException {
2133 if (description == null) {
2134 PdfString desc = (PdfString)fs.get(PdfName.DESC);
2135 if (desc == null) {
2136 description = "";
2137 }
2138 else {
2139 description = PdfEncodings.convertToString(desc.getBytes(), null);
2140 }
2141 }
2142 fs.addDescription(description, true);
2143 if (description.length() == 0)
2144 description = "Unnamed";
2145 String fn = PdfEncodings.convertToString(new PdfString(description, PdfObject.TEXT_UNICODE).getBytes(), null);
2146 int k = 0;
2147 while (documentFileAttachment.containsKey(fn)) {
2148 ++k;
2149 fn = PdfEncodings.convertToString(new PdfString(description + " " + k, PdfObject.TEXT_UNICODE).getBytes(), null);
2150 }
2151 documentFileAttachment.put(fn, fs.getReference());
2152 }
2153
2154 HashMap getDocumentFileAttachment() {
2155 return documentFileAttachment;
2156 }
2157
2158
2159
2160 protected String openActionName;
2161
2162 void setOpenAction(String name) {
2163 openActionName = name;
2164 openActionAction = null;
2165 }
2166
2167 protected PdfAction openActionAction;
2168 void setOpenAction(PdfAction action) {
2169 openActionAction = action;
2170 openActionName = null;
2171 }
2172
2173 protected PdfDictionary additionalActions;
2174 void addAdditionalAction(PdfName actionType, PdfAction action) {
2175 if (additionalActions == null) {
2176 additionalActions = new PdfDictionary();
2177 }
2178 if (action == null)
2179 additionalActions.remove(actionType);
2180 else
2181 additionalActions.put(actionType, action);
2182 if (additionalActions.size() == 0)
2183 additionalActions = null;
2184 }
2185
2186
2187
2188 protected PdfCollection collection;
2189
2190
2194 public void setCollection(PdfCollection collection) {
2195 this.collection = collection;
2196 }
2197
2198
2199
2200 PdfAnnotationsImp annotationsImp;
2201
2202
2206 PdfAcroForm getAcroForm() {
2207 return annotationsImp.getAcroForm();
2208 }
2209
2210 void setSigFlags(int f) {
2211 annotationsImp.setSigFlags(f);
2212 }
2213
2214 void addCalculationOrder(PdfFormField formField) {
2215 annotationsImp.addCalculationOrder(formField);
2216 }
2217
2218 void addAnnotation(PdfAnnotation annot) {
2219 pageEmpty = false;
2220 annotationsImp.addAnnotation(annot);
2221 }
2222
2223
2224
2225 protected int markPoint;
2226
2227 int getMarkPoint() {
2228 return markPoint;
2229 }
2230
2231 void incMarkPoint() {
2232 ++markPoint;
2233 }
2234
2235
2236
2237
2238 protected Rectangle nextPageSize = null;
2239
2240
2241 protected HashMap thisBoxSize = new HashMap();
2242
2243
2245 protected HashMap boxSize = new HashMap();
2246
2247 void setCropBoxSize(Rectangle crop) {
2248 setBoxSize("crop", crop);
2249 }
2250
2251 void setBoxSize(String boxName, Rectangle size) {
2252 if (size == null)
2253 boxSize.remove(boxName);
2254 else
2255 boxSize.put(boxName, new PdfRectangle(size));
2256 }
2257
2258 protected void setNewPageSizeAndMargins() {
2259 pageSize = nextPageSize;
2260 if (marginMirroring && (getPageNumber() & 1) == 0) {
2261 marginRight = nextMarginLeft;
2262 marginLeft = nextMarginRight;
2263 }
2264 else {
2265 marginLeft = nextMarginLeft;
2266 marginRight = nextMarginRight;
2267 }
2268 if (marginMirroringTopBottom && (getPageNumber() & 1) == 0) {
2269 marginTop = nextMarginBottom;
2270 marginBottom = nextMarginTop;
2271 }
2272 else {
2273 marginTop = nextMarginTop;
2274 marginBottom = nextMarginBottom;
2275 }
2276 }
2277
2278
2282 Rectangle getBoxSize(String boxName) {
2283 PdfRectangle r = (PdfRectangle)thisBoxSize.get(boxName);
2284 if (r != null) return r.getRectangle();
2285 return null;
2286 }
2287
2288
2289
2290
2291 protected boolean pageEmpty = true;
2292
2293 void setPageEmpty(boolean pageEmpty) {
2294 this.pageEmpty = pageEmpty;
2295 }
2296
2297
2298
2299
2300 protected int duration=-1;
2301
2302
2303 protected PdfTransition transition=null;
2304
2305
2309 void setDuration(int seconds) {
2310 if (seconds > 0)
2311 this.duration=seconds;
2312 else
2313 this.duration=-1;
2314 }
2315
2316
2320 void setTransition(PdfTransition transition) {
2321 this.transition=transition;
2322 }
2323
2324 protected PdfDictionary pageAA = null;
2325 void setPageAction(PdfName actionType, PdfAction action) {
2326 if (pageAA == null) {
2327 pageAA = new PdfDictionary();
2328 }
2329 pageAA.put(actionType, action);
2330 }
2331
2332
2333
2334 protected PdfIndirectReference thumb;
2335 void setThumbnail(Image image) throws PdfException, DocumentException {
2336 thumb = writer.getImageReference(writer.addDirectImageSimple(image));
2337 }
2338
2339
2340
2341
2342 protected PageResources pageResources;
2343
2344 PageResources getPageResources() {
2345 return pageResources;
2346 }
2347
2348
2349
2350
2351 protected boolean strictImageSequence = false;
2352
2353
2357 boolean isStrictImageSequence() {
2358 return this.strictImageSequence;
2359 }
2360
2361
2365 void setStrictImageSequence(boolean strictImageSequence) {
2366 this.strictImageSequence = strictImageSequence;
2367 }
2368
2369
2370 protected float imageEnd = -1;
2371
2372
2375 public void clearTextWrap() {
2376 float tmpHeight = imageEnd - currentHeight;
2377 if (line != null) {
2378 tmpHeight += line.height();
2379 }
2380 if ((imageEnd > -1) && (tmpHeight > 0)) {
2381 carriageReturn();
2382 currentHeight += tmpHeight;
2383 }
2384 }
2385
2386
2387 protected Image imageWait = null;
2388
2389
2395
2396 protected void add(Image image) throws PdfException, DocumentException {
2397
2398 if (image.hasAbsoluteY()) {
2399 graphics.addImage(image);
2400 pageEmpty = false;
2401 return;
2402 }
2403
2404
2405 if (currentHeight != 0 && indentTop() - currentHeight - image.getScaledHeight() < indentBottom()) {
2406 if (!strictImageSequence && imageWait == null) {
2407 imageWait = image;
2408 return;
2409 }
2410 newPage();
2411 if (currentHeight != 0 && indentTop() - currentHeight - image.getScaledHeight() < indentBottom()) {
2412 imageWait = image;
2413 return;
2414 }
2415 }
2416 pageEmpty = false;
2417
2418 if (image == imageWait)
2419 imageWait = null;
2420 boolean textwrap = (image.getAlignment() & Image.TEXTWRAP) == Image.TEXTWRAP
2421 && !((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE);
2422 boolean underlying = (image.getAlignment() & Image.UNDERLYING) == Image.UNDERLYING;
2423 float diff = leading / 2;
2424 if (textwrap) {
2425 diff += leading;
2426 }
2427 float lowerleft = indentTop() - currentHeight - image.getScaledHeight() -diff;
2428 float mt[] = image.matrix();
2429 float startPosition = indentLeft() - mt[4];
2430 if ((image.getAlignment() & Image.RIGHT) == Image.RIGHT) startPosition = indentRight() - image.getScaledWidth() - mt[4];
2431 if ((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE) startPosition = indentLeft() + ((indentRight() - indentLeft() - image.getScaledWidth()) / 2) - mt[4];
2432 if (image.hasAbsoluteX()) startPosition = image.getAbsoluteX();
2433 if (textwrap) {
2434 if (imageEnd < 0 || imageEnd < currentHeight + image.getScaledHeight() + diff) {
2435 imageEnd = currentHeight + image.getScaledHeight() + diff;
2436 }
2437 if ((image.getAlignment() & Image.RIGHT) == Image.RIGHT) {
2438
2439 indentation.imageIndentRight += image.getScaledWidth() + image.getIndentationLeft();
2440 }
2441 else {
2442
2443 indentation.imageIndentLeft += image.getScaledWidth() + image.getIndentationRight();
2444 }
2445 }
2446 else {
2447 if ((image.getAlignment() & Image.RIGHT) == Image.RIGHT) startPosition -= image.getIndentationRight();
2448 else if ((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE) startPosition += image.getIndentationLeft() - image.getIndentationRight();
2449 else startPosition += image.getIndentationLeft();
2450 }
2451 graphics.addImage(image, mt[0], mt[1], mt[2], mt[3], startPosition, lowerleft - mt[5]);
2452 if (!(textwrap || underlying)) {
2453 currentHeight += image.getScaledHeight() + diff;
2454 flushLines();
2455 text.moveText(0, - (image.getScaledHeight() + diff));
2456 newLine();
2457 }
2458 }
2459
2460
2461
2462
2466 void addPTable(PdfPTable ptable) throws DocumentException {
2467 ColumnText ct = new ColumnText(writer.getDirectContent());
2468
2469
2470 if (ptable.getKeepTogether() && !fitsPage(ptable, 0f) && currentHeight > 0) {
2471 newPage();
2472 }
2473
2474
2475 if (currentHeight > 0) {
2476 Paragraph p = new Paragraph();
2477 p.setLeading(0);
2478 ct.addElement(p);
2479 }
2480 ct.addElement(ptable);
2481 boolean he = ptable.isHeadersInEvent();
2482 ptable.setHeadersInEvent(true);
2483 int loop = 0;
2484 while (true) {
2485 ct.setSimpleColumn(indentLeft(), indentBottom(), indentRight(), indentTop() - currentHeight);
2486 int status = ct.go();
2487 if ((status & ColumnText.NO_MORE_TEXT) != 0) {
2488 text.moveText(0, ct.getYLine() - indentTop() + currentHeight);
2489 currentHeight = indentTop() - ct.getYLine();
2490 break;
2491 }
2492 if (indentTop() - currentHeight == ct.getYLine())
2493 ++loop;
2494 else
2495 loop = 0;
2496 if (loop == 3) {
2497 add(new Paragraph("ERROR: Infinite table loop"));
2498 break;
2499 }
2500 newPage();
2501 }
2502 ptable.setHeadersInEvent(he);
2503 }
2504
2505
2512
2513 boolean fitsPage(PdfPTable table, float margin) {
2514 if (!table.isLockedWidth()) {
2515 float totalWidth = (indentRight() - indentLeft()) * table.getWidthPercentage() / 100;
2516 table.setTotalWidth(totalWidth);
2517 }
2518
2519 ensureNewLine();
2520 return table.getTotalHeight() + ((currentHeight > 0) ? table.spacingBefore() : 0f)
2521 <= indentTop() - currentHeight - indentBottom() - margin;
2522 }
2523
2524
2525
2526
2530 protected static class RenderingContext {
2531 float pagetop = -1;
2532 float oldHeight = -1;
2533
2534 PdfContentByte cellGraphics = null;
2535
2536 float lostTableBottom;
2537
2538 float maxCellBottom;
2539 float maxCellHeight;
2540
2541 Map rowspanMap;
2542 Map pageMap = new HashMap();
2543
2546 public PdfTable table;
2547
2548
2553 public int consumeRowspan(PdfCell c) {
2554 if (c.rowspan() == 1) {
2555 return 1;
2556 }
2557
2558 Integer i = (Integer) rowspanMap.get(c);
2559 if (i == null) {
2560 i = new Integer(c.rowspan());
2561 }
2562
2563 i = new Integer(i.intValue() - 1);
2564 rowspanMap.put(c, i);
2565
2566 if (i.intValue() < 1) {
2567 return 1;
2568 }
2569 return i.intValue();
2570 }
2571
2572
2577 public int currentRowspan(PdfCell c) {
2578 Integer i = (Integer) rowspanMap.get(c);
2579 if (i == null) {
2580 return c.rowspan();
2581 } else {
2582 return i.intValue();
2583 }
2584 }
2585
2586 public int cellRendered(PdfCell cell, int pageNumber) {
2587 Integer i = (Integer) pageMap.get(cell);
2588 if (i == null) {
2589 i = new Integer(1);
2590 } else {
2591 i = new Integer(i.intValue() + 1);
2592 }
2593 pageMap.put(cell, i);
2594
2595 Integer pageInteger = new Integer(pageNumber);
2596 Set set = (Set) pageMap.get(pageInteger);
2597
2598 if (set == null) {
2599 set = new HashSet();
2600 pageMap.put(pageInteger, set);
2601 }
2602
2603 set.add(cell);
2604
2605 return i.intValue();
2606 }
2607
2608 public int numCellRendered(PdfCell cell) {
2609 Integer i = (Integer) pageMap.get(cell);
2610 if (i == null) {
2611 i = new Integer(0);
2612 }
2613 return i.intValue();
2614 }
2615
2616 public boolean isCellRenderedOnPage(PdfCell cell, int pageNumber) {
2617 Integer pageInteger = new Integer(pageNumber);
2618 Set set = (Set) pageMap.get(pageInteger);
2619
2620 if (set != null) {
2621 return set.contains(cell);
2622 }
2623
2624 return false;
2625 }
2626 };
2627
2628
2634 private void addPdfTable(Table t) throws DocumentException {
2635
2636 flushLines();
2637
2638 PdfTable table = new PdfTable(t, indentLeft(), indentRight(), indentTop() - currentHeight);
2639 RenderingContext ctx = new RenderingContext();
2640 ctx.pagetop = indentTop();
2641 ctx.oldHeight = currentHeight;
2642 ctx.cellGraphics = new PdfContentByte(writer);
2643 ctx.rowspanMap = new HashMap();
2644 ctx.table = table;
2645
2646
2647 PdfCell cell;
2648
2649
2650 ArrayList headercells = table.getHeaderCells();
2651 ArrayList cells = table.getCells();
2652 ArrayList rows = extractRows(cells, ctx);
2653 boolean isContinue = false;
2654 while (!cells.isEmpty()) {
2655
2656 ctx.lostTableBottom = 0;
2657
2658
2659 boolean cellsShown = false;
2660
2661
2662 Iterator iterator = rows.iterator();
2663
2664 boolean atLeastOneFits = false;
2665 while (iterator.hasNext()) {
2666 ArrayList row = (ArrayList) iterator.next();
2667 analyzeRow(rows, ctx);
2668 renderCells(ctx, row, table.hasToFitPageCells() & atLeastOneFits);
2669
2670 if (!mayBeRemoved(row)) {
2671 break;
2672 }
2673 consumeRowspan(row, ctx);
2674 iterator.remove();
2675 atLeastOneFits = true;
2676 }
2677
2678
2679 cells.clear();
2680 Set opt = new HashSet();
2681 iterator = rows.iterator();
2682 while (iterator.hasNext()) {
2683 ArrayList row = (ArrayList) iterator.next();
2684
2685 Iterator cellIterator = row.iterator();
2686 while (cellIterator.hasNext()) {
2687 cell = (PdfCell) cellIterator.next();
2688
2689 if (!opt.contains(cell)) {
2690 cells.add(cell);
2691 opt.add(cell);
2692 }
2693 }
2694 }
2695
2696
2697 Rectangle tablerec = new Rectangle(table);
2698 tablerec.setBorder(table.getBorder());
2699 tablerec.setBorderWidth(table.getBorderWidth());
2700 tablerec.setBorderColor(table.getBorderColor());
2701 tablerec.setBackgroundColor(table.getBackgroundColor());
2702 PdfContentByte under = writer.getDirectContentUnder();
2703 under.rectangle(tablerec.rectangle(top(), indentBottom()));
2704 under.add(ctx.cellGraphics);
2705
2706
2707 tablerec.setBackgroundColor(null);
2708 tablerec = tablerec.rectangle(top(), indentBottom());
2709 tablerec.setBorder(table.getBorder());
2710 under.rectangle(tablerec);
2711
2712
2713 ctx.cellGraphics = new PdfContentByte(null);
2714
2715
2716 if (!rows.isEmpty()) {
2717 isContinue = true;
2718 graphics.setLineWidth(table.getBorderWidth());
2719 if (cellsShown && (table.getBorder() & Rectangle.BOTTOM) == Rectangle.BOTTOM) {
2720
2721
2722
2723 Color tColor = table.getBorderColor();
2724 if (tColor != null) {
2725 graphics.setColorStroke(tColor);
2726 }
2727 graphics.moveTo(table.getLeft(), Math.max(table.getBottom(), indentBottom()));
2728 graphics.lineTo(table.getRight(), Math.max(table.getBottom(), indentBottom()));
2729 graphics.stroke();
2730 if (tColor != null) {
2731 graphics.resetRGBColorStroke();
2732 }
2733 }
2734
2735
2736 pageEmpty = false;
2737 float difference = ctx.lostTableBottom;
2738
2739
2740 newPage();
2741
2742
2743 float heightCorrection = 0;
2744 boolean somethingAdded = false;
2745 if (currentHeight > 0) {
2746 heightCorrection = 6;
2747 currentHeight += heightCorrection;
2748 somethingAdded = true;
2749 newLine();
2750 flushLines();
2751 indentation.indentTop = currentHeight - leading;
2752 currentHeight = 0;
2753 }
2754 else {
2755 flushLines();
2756 }
2757
2758
2759 int size = headercells.size();
2760 if (size > 0) {
2761
2762 cell = (PdfCell) headercells.get(0);
2763 float oldTop = cell.getTop(0);
2764
2765 for (int i = 0; i < size; i++) {
2766 cell = (PdfCell) headercells.get(i);
2767
2768 cell.setTop(indentTop() - oldTop + cell.getTop(0));
2769 cell.setBottom(indentTop() - oldTop + cell.getBottom(0));
2770 ctx.pagetop = cell.getBottom();
2771
2772 ctx.cellGraphics.rectangle(cell.rectangle(indentTop(), indentBottom()));
2773
2774 ArrayList images = cell.getImages(indentTop(), indentBottom());
2775 for (Iterator im = images.iterator(); im.hasNext();) {
2776 cellsShown = true;
2777 Image image = (Image) im.next();
2778 graphics.addImage(image);
2779 }
2780 lines = cell.getLines(indentTop(), indentBottom());
2781 float cellTop = cell.getTop(indentTop());
2782 text.moveText(0, cellTop-heightCorrection);
2783 float cellDisplacement = flushLines() - cellTop+heightCorrection;
2784 text.moveText(0, cellDisplacement);
2785 }
2786
2787 currentHeight = indentTop() - ctx.pagetop + table.cellspacing();
2788 text.moveText(0, ctx.pagetop - indentTop() - currentHeight);
2789 }
2790 else {
2791 if (somethingAdded) {
2792 ctx.pagetop = indentTop();
2793 text.moveText(0, -table.cellspacing());
2794 }
2795 }
2796 ctx.oldHeight = currentHeight - heightCorrection;
2797
2798
2799 size = Math.min(cells.size(), table.columns());
2800 int i = 0;
2801 while (i < size) {
2802 cell = (PdfCell) cells.get(i);
2803 if (cell.getTop(-table.cellspacing()) > ctx.lostTableBottom) {
2804 float newBottom = ctx.pagetop - difference + cell.getBottom();
2805 float neededHeight = cell.remainingHeight();
2806 if (newBottom > ctx.pagetop - neededHeight) {
2807 difference += newBottom - (ctx.pagetop - neededHeight);
2808 }
2809 }
2810 i++;
2811 }
2812 size = cells.size();
2813 table.setTop(indentTop());
2814 table.setBottom(ctx.pagetop - difference + table.getBottom(table.cellspacing()));
2815 for (i = 0; i < size; i++) {
2816 cell = (PdfCell) cells.get(i);
2817 float newBottom = ctx.pagetop - difference + cell.getBottom();
2818 float newTop = ctx.pagetop - difference + cell.getTop(-table.cellspacing());
2819 if (newTop > indentTop() - currentHeight) {
2820 newTop = indentTop() - currentHeight;
2821 }
2822
2823 cell.setTop(newTop );
2824 cell.setBottom(newBottom );
2825 }
2826 }
2827 }
2828
2829 float tableHeight = table.getTop() - table.getBottom();
2830
2831
2832 if (isContinue) {
2833 currentHeight = tableHeight;
2834 text.moveText(0, -(tableHeight - (ctx.oldHeight * 2)));
2835 } else {
2836 currentHeight = ctx.oldHeight + tableHeight;
2837 text.moveText(0, -tableHeight);
2838 }
2839
2840 pageEmpty = false;
2841 }
2842
2843 protected void analyzeRow(ArrayList rows, RenderingContext ctx) {
2844 ctx.maxCellBottom = indentBottom();
2845
2846
2847 int rowIndex = 0;
2848
2849 ArrayList row = (ArrayList) rows.get(rowIndex);
2850 int maxRowspan = 1;
2851 Iterator iterator = row.iterator();
2852 while (iterator.hasNext()) {
2853 PdfCell cell = (PdfCell) iterator.next();
2854 maxRowspan = Math.max(ctx.currentRowspan(cell), maxRowspan);
2855 }
2856 rowIndex += maxRowspan;
2857
2858 boolean useTop = true;
2859 if (rowIndex == rows.size()) {
2860 rowIndex = rows.size() - 1;
2861 useTop = false;
2862 }
2863
2864 if (rowIndex < 0 || rowIndex >= rows.size()) return;
2865
2866 row = (ArrayList) rows.get(rowIndex);
2867 iterator = row.iterator();
2868 while (iterator.hasNext()) {
2869 PdfCell cell = (PdfCell) iterator.next();
2870 Rectangle cellRect = cell.rectangle(ctx.pagetop, indentBottom());
2871 if (useTop) {
2872 ctx.maxCellBottom = Math.max(ctx.maxCellBottom, cellRect.getTop());
2873 } else {
2874 if (ctx.currentRowspan(cell) == 1) {
2875 ctx.maxCellBottom = Math.max(ctx.maxCellBottom, cellRect.getBottom());
2876 }
2877 }
2878 }
2879 }
2880
2881 protected boolean mayBeRemoved(ArrayList row) {
2882 Iterator iterator = row.iterator();
2883 boolean mayBeRemoved = true;
2884 while (iterator.hasNext()) {
2885 PdfCell cell = (PdfCell) iterator.next();
2886
2887 mayBeRemoved &= cell.mayBeRemoved();
2888 }
2889 return mayBeRemoved;
2890 }
2891
2892 protected void consumeRowspan(ArrayList row, RenderingContext ctx) {
2893 Iterator iterator = row.iterator();
2894 while (iterator.hasNext()) {
2895 PdfCell c = (PdfCell) iterator.next();
2896 ctx.consumeRowspan(c);
2897 }
2898 }
2899
2900 protected ArrayList extractRows(ArrayList cells, RenderingContext ctx) {
2901 PdfCell cell;
2902 PdfCell previousCell = null;
2903 ArrayList rows = new ArrayList();
2904 java.util.List rowCells = new ArrayList();
2905
2906 Iterator iterator = cells.iterator();
2907 while (iterator.hasNext()) {
2908 cell = (PdfCell) iterator.next();
2909
2910 boolean isAdded = false;
2911
2912 boolean isEndOfRow = !iterator.hasNext();
2913 boolean isCurrentCellPartOfRow = !iterator.hasNext();
2914
2915 if (previousCell != null) {
2916 if (cell.getLeft() <= previousCell.getLeft()) {
2917 isEndOfRow = true;
2918 isCurrentCellPartOfRow = false;
2919 }
2920 }
2921
2922 if (isCurrentCellPartOfRow) {
2923 rowCells.add(cell);
2924 isAdded = true;
2925 }
2926
2927 if (isEndOfRow) {
2928 if (!rowCells.isEmpty()) {
2929
2930 rows.add(rowCells);
2931 }
2932
2933
2934 rowCells = new ArrayList();
2935 }
2936
2937 if (!isAdded) {
2938 rowCells.add(cell);
2939 }
2940
2941 previousCell = cell;
2942 }
2943
2944 if (!rowCells.isEmpty()) {
2945 rows.add(rowCells);
2946 }
2947
2948
2949 for (int i = rows.size() - 1; i >= 0; i--) {
2950 ArrayList row = (ArrayList) rows.get(i);
2951
2952 for (int j = 0; j < row.size(); j++) {
2953 PdfCell c = (PdfCell) row.get(j);
2954 int rowspan = c.rowspan();
2955
2956 for (int k = 1; k < rowspan && rows.size() < i+k; k++) {
2957 ArrayList spannedRow = ((ArrayList) rows.get(i + k));
2958 if (spannedRow.size() > j)
2959 spannedRow.add(j, c);
2960 }
2961 }
2962 }
2963
2964 return rows;
2965 }
2966
2967 protected void renderCells(RenderingContext ctx, java.util.List cells, boolean hasToFit) throws DocumentException {
2968 PdfCell cell;
2969 Iterator iterator;
2970 if (hasToFit) {
2971 iterator = cells.iterator();
2972 while (iterator.hasNext()) {
2973 cell = (PdfCell) iterator.next();
2974 if (!cell.isHeader()) {
2975 if (cell.getBottom() < indentBottom()) return;
2976 }
2977 }
2978 }
2979 iterator = cells.iterator();
2980
2981 while (iterator.hasNext()) {
2982 cell = (PdfCell) iterator.next();
2983 if (!ctx.isCellRenderedOnPage(cell, getPageNumber())) {
2984
2985 float correction = 0;
2986 if (ctx.numCellRendered(cell) >= 1) {
2987 correction = 1.0f;
2988 }
2989
2990 lines = cell.getLines(ctx.pagetop, indentBottom() - correction);
2991
2992
2993 if (lines != null && !lines.isEmpty()) {
2994
2995 float cellTop = cell.getTop(ctx.pagetop - ctx.oldHeight);
2996 text.moveText(0, cellTop);
2997 float cellDisplacement = flushLines() - cellTop;
2998
2999 text.moveText(0, cellDisplacement);
3000 if (ctx.oldHeight + cellDisplacement > currentHeight) {
3001 currentHeight = ctx.oldHeight + cellDisplacement;
3002 }
3003
3004 ctx.cellRendered(cell, getPageNumber());
3005 }
3006 float indentBottom = Math.max(cell.getBottom(), indentBottom());
3007 Rectangle tableRect = ctx.table.rectangle(ctx.pagetop, indentBottom());
3008 indentBottom = Math.max(tableRect.getBottom(), indentBottom);
3009
3010
3011 Rectangle cellRect = cell.rectangle(tableRect.getTop(), indentBottom);
3012
3013 if (cellRect.getHeight() > 0) {
3014 ctx.lostTableBottom = indentBottom;
3015 ctx.cellGraphics.rectangle(cellRect);
3016 }
3017
3018
3019 ArrayList images = cell.getImages(ctx.pagetop, indentBottom());
3020 for (Iterator i = images.iterator(); i.hasNext();) {
3021 Image image = (Image) i.next();
3022 graphics.addImage(image);
3023 }
3024
3025 }
3026 }
3027 }
3028
3029
3035 float bottom(Table table) {
3036
3037 PdfTable tmp = new PdfTable(table, indentLeft(), indentRight(), indentTop() - currentHeight);
3038 return tmp.getBottom();
3039 }
3040
3041
3042 protected void doFooter() throws DocumentException {
3043 if (footer == null) return;
3044
3045
3046 float tmpIndentLeft = indentation.indentLeft;
3047 float tmpIndentRight = indentation.indentRight;
3048
3049 float tmpListIndentLeft = indentation.listIndentLeft;
3050 float tmpImageIndentLeft = indentation.imageIndentLeft;
3051 float tmpImageIndentRight = indentation.imageIndentRight;
3052
3053
3054 indentation.indentLeft = indentation.indentRight = 0;
3055
3056 indentation.listIndentLeft = 0;
3057 indentation.imageIndentLeft = 0;
3058 indentation.imageIndentRight = 0;
3059
3060
3061 footer.setPageNumber(pageN);
3062 leading = footer.paragraph().getTotalLeading();
3063 add(footer.paragraph());
3064
3065 indentation.indentBottom = currentHeight;
3066 text.moveText(left(), indentBottom());
3067 flushLines();
3068 text.moveText(-left(), -bottom());
3069 footer.setTop(bottom(currentHeight));
3070 footer.setBottom(bottom() - (0.75f * leading));
3071 footer.setLeft(left());
3072 footer.setRight(right());
3073 graphics.rectangle(footer);
3074 indentation.indentBottom = currentHeight + leading * 2;
3075 currentHeight = 0;
3076
3077 indentation.indentLeft = tmpIndentLeft;
3078 indentation.indentRight = tmpIndentRight;
3079
3080 indentation.listIndentLeft = tmpListIndentLeft;
3081 indentation.imageIndentLeft = tmpImageIndentLeft;
3082 indentation.imageIndentRight = tmpImageIndentRight;
3083
3084
3085 }
3086
3087 protected void doHeader() throws DocumentException {
3088
3089 if (header == null) return;
3090
3091
3092 float tmpIndentLeft = indentation.indentLeft;
3093 float tmpIndentRight = indentation.indentRight;
3094
3095 float tmpListIndentLeft = indentation.listIndentLeft;
3096 float tmpImageIndentLeft = indentation.imageIndentLeft;
3097 float tmpImageIndentRight = indentation.imageIndentRight;
3098
3099 indentation.indentLeft = indentation.indentRight = 0;
3100
3101 indentation.listIndentLeft = 0;
3102 indentation.imageIndentLeft = 0;
3103 indentation.imageIndentRight = 0;
3104
3105
3106 header.setPageNumber(pageN);
3107 leading = header.paragraph().getTotalLeading();
3108 text.moveText(0, leading);
3109 add(header.paragraph());
3110 newLine();
3111 indentation.indentTop = currentHeight - leading;
3112 header.setTop(top() + leading);
3113 header.setBottom(indentTop() + leading * 2 / 3);
3114 header.setLeft(left());
3115 header.setRight(right());
3116 graphics.rectangle(header);
3117 flushLines();
3118 currentHeight = 0;
3119
3120
3121 indentation.indentLeft = tmpIndentLeft;
3122 indentation.indentRight = tmpIndentRight;
3123
3124 indentation.listIndentLeft = tmpListIndentLeft;
3125 indentation.imageIndentLeft = tmpImageIndentLeft;
3126 indentation.imageIndentRight = tmpImageIndentRight;
3127
3128
3129 }
3130 }