1
24
25
33 package net.sf.jasperreports.engine.export;
34
35 import java.awt.Color;
36 import java.awt.Graphics2D;
37 import java.awt.font.TextAttribute;
38 import java.awt.geom.AffineTransform;
39 import java.awt.geom.Dimension2D;
40 import java.awt.image.BufferedImage;
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.io.OutputStream;
44 import java.text.AttributedCharacterIterator;
45 import java.text.AttributedCharacterIterator.Attribute;
46 import java.text.AttributedString;
47 import java.util.ArrayList;
48 import java.util.Collection;
49 import java.util.HashMap;
50 import java.util.Iterator;
51 import java.util.LinkedList;
52 import java.util.List;
53 import java.util.Locale;
54 import java.util.Map;
55
56 import org.apache.commons.logging.Log;
57 import org.apache.commons.logging.LogFactory;
58
59 import com.ibm.icu.util.StringTokenizer;
60 import com.lowagie.text.FontFactory;
61 import com.lowagie.text.pdf.PdfWriter;
62
63 import net.sf.jasperreports.annotations.properties.Property;
64 import net.sf.jasperreports.annotations.properties.PropertyScope;
65 import net.sf.jasperreports.engine.DefaultJasperReportsContext;
66 import net.sf.jasperreports.engine.JRAbstractExporter;
67 import net.sf.jasperreports.engine.JRAnchor;
68 import net.sf.jasperreports.engine.JRBoxContainer;
69 import net.sf.jasperreports.engine.JRCommonGraphicElement;
70 import net.sf.jasperreports.engine.JRException;
71 import net.sf.jasperreports.engine.JRFont;
72 import net.sf.jasperreports.engine.JRGenericElementType;
73 import net.sf.jasperreports.engine.JRGenericPrintElement;
74 import net.sf.jasperreports.engine.JRLineBox;
75 import net.sf.jasperreports.engine.JRPen;
76 import net.sf.jasperreports.engine.JRPrintAnchor;
77 import net.sf.jasperreports.engine.JRPrintElement;
78 import net.sf.jasperreports.engine.JRPrintEllipse;
79 import net.sf.jasperreports.engine.JRPrintFrame;
80 import net.sf.jasperreports.engine.JRPrintHyperlink;
81 import net.sf.jasperreports.engine.JRPrintImage;
82 import net.sf.jasperreports.engine.JRPrintLine;
83 import net.sf.jasperreports.engine.JRPrintPage;
84 import net.sf.jasperreports.engine.JRPrintRectangle;
85 import net.sf.jasperreports.engine.JRPrintText;
86 import net.sf.jasperreports.engine.JRPropertiesUtil;
87 import net.sf.jasperreports.engine.JRPropertiesUtil.PropertySuffix;
88 import net.sf.jasperreports.engine.JRRuntimeException;
89 import net.sf.jasperreports.engine.JasperPrint;
90 import net.sf.jasperreports.engine.JasperReportsContext;
91 import net.sf.jasperreports.engine.PrintPageFormat;
92 import net.sf.jasperreports.engine.base.JRBaseFont;
93 import net.sf.jasperreports.engine.base.JRBasePen;
94 import net.sf.jasperreports.engine.base.JRBasePrintText;
95 import net.sf.jasperreports.engine.export.type.PdfFieldBorderStyleEnum;
96 import net.sf.jasperreports.engine.export.type.PdfFieldCheckTypeEnum;
97 import net.sf.jasperreports.engine.export.type.PdfFieldTypeEnum;
98 import net.sf.jasperreports.engine.fonts.FontFace;
99 import net.sf.jasperreports.engine.fonts.FontFamily;
100 import net.sf.jasperreports.engine.fonts.FontInfo;
101 import net.sf.jasperreports.engine.fonts.FontUtil;
102 import net.sf.jasperreports.engine.type.HyperlinkTypeEnum;
103 import net.sf.jasperreports.engine.type.LineDirectionEnum;
104 import net.sf.jasperreports.engine.type.LineStyleEnum;
105 import net.sf.jasperreports.engine.type.ModeEnum;
106 import net.sf.jasperreports.engine.type.OrientationEnum;
107 import net.sf.jasperreports.engine.util.ImageUtil;
108 import net.sf.jasperreports.engine.util.JRImageLoader;
109 import net.sf.jasperreports.engine.util.JRLoader;
110 import net.sf.jasperreports.engine.util.JRPdfaIccProfileNotFoundException;
111 import net.sf.jasperreports.engine.util.JRSingletonCache;
112 import net.sf.jasperreports.engine.util.JRStyledText;
113 import net.sf.jasperreports.engine.util.JRStyledTextUtil;
114 import net.sf.jasperreports.engine.util.JRTextAttribute;
115 import net.sf.jasperreports.export.ExportInterruptedException;
116 import net.sf.jasperreports.export.ExporterInputItem;
117 import net.sf.jasperreports.export.OutputStreamExporterOutput;
118 import net.sf.jasperreports.export.PdfExporterConfiguration;
119 import net.sf.jasperreports.export.PdfReportConfiguration;
120 import net.sf.jasperreports.export.pdf.FontRecipient;
121 import net.sf.jasperreports.export.pdf.LineCapStyle;
122 import net.sf.jasperreports.export.pdf.PdfChunk;
123 import net.sf.jasperreports.export.pdf.PdfContent;
124 import net.sf.jasperreports.export.pdf.PdfDocument;
125 import net.sf.jasperreports.export.pdf.PdfDocumentWriter;
126 import net.sf.jasperreports.export.pdf.PdfFontStyle;
127 import net.sf.jasperreports.export.pdf.PdfImage;
128 import net.sf.jasperreports.export.pdf.PdfOutlineEntry;
129 import net.sf.jasperreports.export.pdf.PdfPhrase;
130 import net.sf.jasperreports.export.pdf.PdfProducer;
131 import net.sf.jasperreports.export.pdf.PdfProducerContext;
132 import net.sf.jasperreports.export.pdf.PdfProducerFactory;
133 import net.sf.jasperreports.export.pdf.PdfRadioCheck;
134 import net.sf.jasperreports.export.pdf.PdfTextAlignment;
135 import net.sf.jasperreports.export.pdf.PdfTextChunk;
136 import net.sf.jasperreports.export.pdf.PdfTextField;
137 import net.sf.jasperreports.export.pdf.TextDirection;
138 import net.sf.jasperreports.export.pdf.classic.ClassicPdfProducer;
139 import net.sf.jasperreports.export.type.PdfPermissionsEnum;
140 import net.sf.jasperreports.export.type.PdfPrintScalingEnum;
141 import net.sf.jasperreports.export.type.PdfVersionEnum;
142 import net.sf.jasperreports.export.type.PdfaConformanceEnum;
143 import net.sf.jasperreports.properties.PropertyConstants;
144 import net.sf.jasperreports.renderers.DataRenderable;
145 import net.sf.jasperreports.renderers.DimensionRenderable;
146 import net.sf.jasperreports.renderers.Graphics2DRenderable;
147 import net.sf.jasperreports.renderers.Renderable;
148 import net.sf.jasperreports.renderers.RenderersCache;
149 import net.sf.jasperreports.renderers.ResourceRenderer;
150 import net.sf.jasperreports.renderers.WrappingImageDataToGraphics2DRenderer;
151 import net.sf.jasperreports.renderers.WrappingSvgDataToGraphics2DRenderer;
152 import net.sf.jasperreports.renderers.util.RendererUtil;
153 import net.sf.jasperreports.repo.RepositoryUtil;
154
155
156
358 public class JRPdfExporter extends JRAbstractExporter<PdfReportConfiguration, PdfExporterConfiguration, OutputStreamExporterOutput, JRPdfExporterContext>
359 {
360
361 private static final Log log = LogFactory.getLog(JRPdfExporter.class);
362
363 public static final String PDF_EXPORTER_PROPERTIES_PREFIX = JRPropertiesUtil.PROPERTY_PREFIX + "export.pdf.";
364
365 public static final String EXCEPTION_MESSAGE_KEY_DOCUMENT_ERROR = "export.pdf.document.error";
366 public static final String EXCEPTION_MESSAGE_KEY_FONT_LOADING_ERROR = "export.pdf.font.loading.error";
367 public static final String EXCEPTION_MESSAGE_KEY_REPORT_GENERATION_ERROR = "export.pdf.report.generation.error";
368
369
372 @Property(
373 name = "net.sf.jasperreports.export.pdf.font.{arbitrary_name}",
374 category = PropertyConstants.CATEGORY_EXPORT,
375 scopes = {PropertyScope.GLOBAL},
376 sinceVersion = PropertyConstants.VERSION_1_0_0
377 )
378 public static final String PDF_FONT_FILES_PREFIX = PDF_EXPORTER_PROPERTIES_PREFIX + "font.";
379
380
383 @Property(
384 name = "net.sf.jasperreports.export.pdf.fontdir.{arbitrary_name}",
385 category = PropertyConstants.CATEGORY_EXPORT,
386 scopes = {PropertyScope.GLOBAL},
387 sinceVersion = PropertyConstants.VERSION_1_0_0
388 )
389 public static final String PDF_FONT_DIRS_PREFIX = PDF_EXPORTER_PROPERTIES_PREFIX + "fontdir.";
390
391
394 @Property(
395 category = PropertyConstants.CATEGORY_EXPORT,
396 scopes = {PropertyScope.ELEMENT},
397 sinceVersion = PropertyConstants.VERSION_6_12_0,
398 valueType = PdfFieldTypeEnum.class
399 )
400 public static final String PDF_FIELD_TYPE = PDF_EXPORTER_PROPERTIES_PREFIX + "field.type";
401
402
405 @Property(
406 category = PropertyConstants.CATEGORY_EXPORT,
407 scopes = {PropertyScope.ELEMENT},
408 sinceVersion = PropertyConstants.VERSION_6_12_0,
409 valueType = Boolean.class,
410 defaultValue = PropertyConstants.BOOLEAN_FALSE
411 )
412 public static final String PDF_FIELD_TEXT_MULTILINE = PDF_EXPORTER_PROPERTIES_PREFIX + "field.text.multiline";
413
414
417 @Property(
418 category = PropertyConstants.CATEGORY_EXPORT,
419 scopes = {PropertyScope.ELEMENT},
420 sinceVersion = PropertyConstants.VERSION_6_12_0
421 )
422 public static final String PDF_FIELD_VALUE = PDF_EXPORTER_PROPERTIES_PREFIX + "field.value";
423
424
427 @Property(
428 category = PropertyConstants.CATEGORY_EXPORT,
429 scopes = {PropertyScope.ELEMENT},
430 sinceVersion = PropertyConstants.VERSION_6_12_0,
431 valueType = PdfFieldCheckTypeEnum.class
432 )
433 public static final String PDF_FIELD_CHECK_TYPE = PDF_EXPORTER_PROPERTIES_PREFIX + "field.check.type";
434
435
438 @Property(
439 category = PropertyConstants.CATEGORY_EXPORT,
440 scopes = {PropertyScope.ELEMENT},
441 sinceVersion = PropertyConstants.VERSION_6_12_0
442 )
443 public static final String PDF_FIELD_NAME = PDF_EXPORTER_PROPERTIES_PREFIX + "field.name";
444
445
448 @Property(
449 category = PropertyConstants.CATEGORY_EXPORT,
450 scopes = {PropertyScope.ELEMENT},
451 sinceVersion = PropertyConstants.VERSION_6_12_0,
452 valueType = Boolean.class
453 )
454 public static final String PDF_FIELD_CHECKED = PDF_EXPORTER_PROPERTIES_PREFIX + "field.checked";
455
456
459 @Property(
460 category = PropertyConstants.CATEGORY_EXPORT,
461 scopes = {PropertyScope.ELEMENT},
462 sinceVersion = PropertyConstants.VERSION_6_12_0,
463 valueType = Boolean.class
464 )
465 public static final String PDF_FIELD_READ_ONLY = PDF_EXPORTER_PROPERTIES_PREFIX + "field.read.only";
466
467
470 @Property(
471 category = PropertyConstants.CATEGORY_EXPORT,
472 scopes = {PropertyScope.GLOBAL, PropertyScope.CONTEXT, PropertyScope.REPORT, PropertyScope.ELEMENT},
473 sinceVersion = PropertyConstants.VERSION_6_12_0,
474 valueType = PdfFieldBorderStyleEnum.class
475 )
476 public static final String PDF_FIELD_BORDER_STYLE = PDF_EXPORTER_PROPERTIES_PREFIX + "field.border.style";
477
478
481 @Property(
482 category = PropertyConstants.CATEGORY_EXPORT,
483 defaultValue = "|",
484 scopes = {PropertyScope.GLOBAL, PropertyScope.CONTEXT, PropertyScope.REPORT, PropertyScope.ELEMENT},
485 sinceVersion = PropertyConstants.VERSION_6_12_0
486 )
487 public static final String PDF_FIELD_CHOICE_SEPARATORS = PDF_EXPORTER_PROPERTIES_PREFIX + "field.choice.separators";
488
489
492 @Property(
493 category = PropertyConstants.CATEGORY_EXPORT,
494 scopes = {PropertyScope.ELEMENT},
495 sinceVersion = PropertyConstants.VERSION_6_12_0
496 )
497 public static final String PDF_FIELD_CHOICES = PDF_EXPORTER_PROPERTIES_PREFIX + "field.choices";
498
499
502 @Property(
503 category = PropertyConstants.CATEGORY_EXPORT,
504 scopes = {PropertyScope.GLOBAL, PropertyScope.CONTEXT, PropertyScope.REPORT, PropertyScope.ELEMENT},
505 sinceVersion = PropertyConstants.VERSION_6_12_0,
506 valueType = Boolean.class,
507 defaultValue = PropertyConstants.BOOLEAN_FALSE
508 )
509 public static final String PDF_FIELD_COMBO_EDIT = PDF_EXPORTER_PROPERTIES_PREFIX + "field.combo.edit";
510
511
515 public static final String PDF_EXPORTER_KEY = JRPropertiesUtil.PROPERTY_PREFIX + "pdf";
516
517 public static final String PDF_PRODUCER_FACTORY_PROPERTY = PDF_EXPORTER_PROPERTIES_PREFIX + "producer.factory";
518
519 private static final String EMPTY_BOOKMARK_TITLE = "";
520
521
524 protected static final String JR_PAGE_ANCHOR_PREFIX = "JR_PAGE_ANCHOR_";
525
526 protected static boolean fontsRegistered;
527
528 private static final JRSingletonCache<PdfProducerFactory> pdfProducerCache =
529 new JRSingletonCache<>(PdfProducerFactory.class);
530
531 protected class ExporterContext extends BaseExporterContext implements JRPdfExporterContext
532 {
533 @Override
534 public PdfWriter getPdfWriter()
535 {
536 if (pdfProducer instanceof ClassicPdfProducer)
537 {
538 return ((ClassicPdfProducer) pdfProducer).getPdfWriter();
539 }
540
541 throw new JRRuntimeException("Not using the classic PDF producer");
542 }
543
544 @Override
545 public PdfProducer getPdfProducer()
546 {
547 return pdfProducer;
548 }
549 }
550
551
554 protected PdfProducer pdfProducer;
555 protected PdfContent pdfContent;
556
557 protected JRPdfExporterTagHelper tagHelper = new JRPdfExporterTagHelper(this);
558
559 protected int reportIndex;
560 protected PrintPageFormat pageFormat;
561 protected int crtDocumentPageNumber;
562
563 protected int permissions;
564
565
568 protected RenderersCache renderersCache;
569 protected Map<String,PdfImage> loadedImagesMap;
570 protected PdfImage pxImage;
571
572 private BookmarkStack bookmarkStack;
573
574 private int crtOddPageOffsetX;
575 private int crtOddPageOffsetY;
576 private int crtEvenPageOffsetX;
577 private int crtEvenPageOffsetY;
578
579 private boolean awtIgnoreMissingFont;
580 private boolean defaultIndentFirstLine;
581 private boolean defaultJustifyLastLine;
582
583 private PdfVersionEnum minimalVersion;
584
585
588 public JRPdfExporter()
589 {
590 this(DefaultJasperReportsContext.getInstance());
591 }
592
593
594
597 public JRPdfExporter(JasperReportsContext jasperReportsContext)
598 {
599 super(jasperReportsContext);
600
601 exporterContext = new ExporterContext();
602 }
603
604
605 @Override
606 protected Class<PdfExporterConfiguration> getConfigurationInterface()
607 {
608 return PdfExporterConfiguration.class;
609 }
610
611
612 @Override
613 protected Class<PdfReportConfiguration> getItemConfigurationInterface()
614 {
615 return PdfReportConfiguration.class;
616 }
617
618
619 @Override
620 @SuppressWarnings("deprecation")
621 protected void ensureOutput()
622 {
623 if (exporterOutput == null)
624 {
625 exporterOutput =
626 new net.sf.jasperreports.export.parameters.ParametersOutputStreamExporterOutput(
627 getJasperReportsContext(),
628 getParameters(),
629 getCurrentJasperPrint()
630 );
631 }
632 }
633
634
635
638 protected PdfImage getPxImage()
639 {
640 if (pxImage == null)
641 {
642 try
643 {
644 pxImage = pdfProducer.createImage(JRLoader.loadBytesFromResource(JRImageLoader.PIXEL_IMAGE_RESOURCE), false);
645 }
646 catch(Exception e)
647 {
648 throw new JRRuntimeException(e);
649 }
650 }
651
652 return pxImage;
653 }
654
655
656 @Override
657 public void exportReport() throws JRException
658 {
659 registerFonts();
660
661
662 ensureJasperReportsContext();
663 ensureInput();
664
665 initExport();
666
667 ensureOutput();
668
669 OutputStream outputStream = getExporterOutput().getOutputStream();
670
671 try
672 {
673 exportReportToStream(outputStream);
674 }
675 finally
676 {
677 getExporterOutput().close();
678 resetExportContext();
679 }
680 }
681
682
683 @Override
684 protected void initExport()
685 {
686 super.initExport();
687
688 PdfExporterConfiguration configuration = getCurrentConfiguration();
689
690 Boolean isTagged = configuration.isTagged();
691 if (isTagged != null)
692 {
693 tagHelper.setTagged(isTagged);
694 }
695
696 tagHelper.setLanguage(configuration.getTagLanguage());
697
698 this.permissions = getIntegerPermissions(configuration.getAllowedPermissions()) & (~getIntegerPermissions(configuration.getDeniedPermissions()));
699 crtDocumentPageNumber = 0;
700
701 awtIgnoreMissingFont = getPropertiesUtil().getBooleanProperty(
702 JRStyledText.PROPERTY_AWT_IGNORE_MISSING_FONT);
703
704 pdfProducer = createPdfProducer();
705 }
706
707 @Override
708 protected void initReport()
709 {
710 super.initReport();
711
712 PdfReportConfiguration configuration = getCurrentItemConfiguration();
713
714 pdfProducer.setForceLineBreakPolicy(configuration.isForceLineBreakPolicy());
715
716 defaultIndentFirstLine = propertiesUtil.getBooleanProperty(jasperPrint, JRPrintText.PROPERTY_AWT_INDENT_FIRST_LINE, true);
717 defaultJustifyLastLine = propertiesUtil.getBooleanProperty(jasperPrint, JRPrintText.PROPERTY_AWT_JUSTIFY_LAST_LINE, false);
718
719 crtOddPageOffsetX = configuration.getOddPageOffsetX();
720 crtOddPageOffsetY = configuration.getOddPageOffsetY();
721 crtEvenPageOffsetX = configuration.getEvenPageOffsetX();
722 crtEvenPageOffsetY = configuration.getEvenPageOffsetY();
723
724 pdfProducer.initReport();
725
726 renderersCache = new RenderersCache(getJasperReportsContext());
727 loadedImagesMap = new HashMap<String,PdfImage>();
728 }
729
730 protected PdfProducerFactory getPdfProducerFactory()
731 {
732 String producerFactory = propertiesUtil.getProperty(PDF_PRODUCER_FACTORY_PROPERTY);
733 try
734 {
735 return pdfProducerCache.getCachedInstance(producerFactory);
736 }
737 catch (JRException e)
738 {
739 throw new JRRuntimeException(e);
740 }
741 }
742
743 protected PdfProducerContext createPdfProducerContext()
744 {
745 return new PdfProducerContext()
746 {
747 @Override
748 public JasperReportsContext getJasperReportsContext()
749 {
750 return jasperReportsContext;
751 }
752
753 @Override
754 public JRPropertiesUtil getProperties()
755 {
756 return propertiesUtil;
757 }
758
759 @Override
760 public FontUtil getFontUtil()
761 {
762 return fontUtil;
763 }
764
765 @Override
766 public JRStyledTextUtil getStyledTextUtil()
767 {
768 return styledTextUtil;
769 }
770
771 @Override
772 public boolean isTagged()
773 {
774 return tagHelper.isTagged;
775 }
776
777 @Override
778 public void setMinimalVersion(PdfVersionEnum version)
779 {
780 minimalVersion = version;
781 }
782
783 @Override
784 public JasperPrint getCurrentJasperPrint()
785 {
786 return JRPdfExporter.this.getCurrentJasperPrint();
787 }
788
789 @Override
790 public void setFont(Map<Attribute, Object> attributes, Locale locale, boolean setFontLines, FontRecipient recipient)
791 {
792 JRPdfExporter.this.setFont(attributes, locale, setFontLines, recipient);
793 }
794
795 @Override
796 public JRException handleDocumentException(Exception e)
797 {
798 return new JRException(EXCEPTION_MESSAGE_KEY_DOCUMENT_ERROR,
799 new Object[]{jasperPrint.getName()}, e);
800 }
801 };
802 }
803
804 protected PdfProducer createPdfProducer()
805 {
806 PdfProducerFactory producerFactory = getPdfProducerFactory();
807 PdfProducerContext producerContext = createPdfProducerContext();
808 return producerFactory.createProducer(producerContext);
809 }
810
811
814 protected void exportReportToStream(OutputStream os) throws JRException
815 {
816
817
818 PdfExporterConfiguration configuration = getCurrentConfiguration();
819
820 pageFormat = jasperPrint.getPageFormat(0);
821
822 PdfDocument document = pdfProducer.createDocument(pageFormat);
823
824 boolean closeDocuments = true;
825 try
826 {
827 PdfDocumentWriter pdfWriter = pdfProducer.createWriter(os);
828
829 tagHelper.setPdfProducer(pdfProducer);
830
831 PdfVersionEnum pdfVersion = configuration.getPdfVersion();
832 if (pdfVersion != null)
833 {
834 pdfWriter.setPdfVersion(pdfVersion);
835 }
836
837 if (minimalVersion != null)
838 {
839 pdfWriter.setMinimalPdfVersion(minimalVersion);
840 }
841
842 if (configuration.isCompressed())
843 {
844 pdfWriter.setFullCompression();
845 }
846 if (configuration.isEncrypted())
847 {
848 int perms = configuration.isOverrideHints() == null || configuration.isOverrideHints()
849 ? (configuration.getPermissions() != null
850 ? (Integer)configuration.getPermissions()
851 : permissions)
852 : (permissions != 0
853 ? permissions
854 :(configuration.getPermissions() != null
855 ? (Integer)configuration.getPermissions()
856 : 0));
857
858 pdfWriter.setEncryption(configuration.getUserPassword(), configuration.getOwnerPassword(),
859 perms, configuration.is128BitKey());
860 }
861
862
863 PdfPrintScalingEnum printScaling = configuration.getPrintScaling();
864 pdfWriter.setPrintScaling(printScaling);
865
866 boolean justifiedLetterSpacing = propertiesUtil.getBooleanProperty(jasperPrint,
867 PdfExporterConfiguration.PROPERTY_JUSTIFIED_LETTER_SPACING, false);
868 if (!justifiedLetterSpacing)
869 {
870 pdfWriter.setNoSpaceCharRatio();
871 }
872
873
874
875 String title = configuration.getMetadataTitle();
876 if( title != null )
877 {
878 document.addTitle(title);
879 if(configuration.isDisplayMetadataTitle()){
880 pdfWriter.setDisplayMetadataTitle();
881 }
882 }
883 String author = configuration.getMetadataAuthor();
884 if( author != null )
885 {
886 document.addAuthor(author);
887 }
888 String subject = configuration.getMetadataSubject();
889 if( subject != null )
890 {
891 document.addSubject(subject);
892 }
893 String keywords = configuration.getMetadataKeywords();
894 if( keywords != null )
895 {
896 document.addKeywords(keywords);
897 }
898 String creator = configuration.getMetadataCreator();
899 if( creator == null )
900 {
901 creator = "JasperReports Library version " + Package.getPackage("net.sf.jasperreports.engine").getImplementationVersion();
902 }
903 document.addCreator(creator);
904
905
906 pdfWriter.setTabOrderStructure();
907
908
909 String language = configuration.getTagLanguage();
910 if(language != null){
911 pdfWriter.setLanguage(language);
912 }
913
914
915 PdfaConformanceEnum pdfaConformance = configuration.getPdfaConformance();
916 boolean gotPdfa = false;
917 if (pdfaConformance != null && pdfaConformance != PdfaConformanceEnum.NONE)
918 {
919 pdfWriter.setPdfaConformance(pdfaConformance);
920 gotPdfa = true;
921 }
922
923 if (gotPdfa)
924 {
925 pdfWriter.createXmpMetadata(title, subject, keywords);
926 } else
927 {
928 pdfWriter.setRgbTransparencyBlending(true);
929 }
930
931
932 document.open();
933
934 if (gotPdfa) {
935 String iccProfilePath = configuration.getIccProfilePath();
936 if (iccProfilePath != null) {
937 InputStream iccIs = RepositoryUtil.getInstance(jasperReportsContext).getInputStreamFromLocation(iccProfilePath);
938 pdfWriter.setIccProfilePath(iccProfilePath, iccIs);
939 } else {
940 throw new JRPdfaIccProfileNotFoundException();
941 }
942 }
943
944
945 String pdfJavaScript = configuration.getPdfJavaScript();
946 if(pdfJavaScript != null)
947 {
948 pdfWriter.addJavaScript(pdfJavaScript);
949 }
950
951 pdfContent = pdfProducer.createPdfContent();
952
953 tagHelper.init();
954
955 List<ExporterInputItem> items = exporterInput.getItems();
956
957 initBookmarks(items);
958
959 boolean isCreatingBatchModeBookmarks = configuration.isCreatingBatchModeBookmarks();
960
961 for (reportIndex = 0; reportIndex < items.size(); reportIndex++)
962 {
963 ExporterInputItem item = items.get(reportIndex);
964
965 setCurrentExporterInputItem(item);
966
967 pageFormat = jasperPrint.getPageFormat(0);
968
969 setPageSize(null);
970
971 List<JRPrintPage> pages = jasperPrint.getPages();
972 if (pages != null && pages.size() > 0)
973 {
974 if (items.size() > 1)
975 {
976 pdfProducer.newPage();
977
978 if( isCreatingBatchModeBookmarks )
979 {
980
981 addBookmark(0, jasperPrint.getName(), 0, 0);
982 }
983 }
984
985 PdfReportConfiguration lcItemConfiguration = getCurrentItemConfiguration();
986
987 boolean sizePageToContent = lcItemConfiguration.isSizePageToContent();
988
989 PrintPageFormat oldPageFormat = null;
990
991 PageRange pageRange = getPageRange();
992 int startPageIndex = (pageRange == null || pageRange.getStartPageIndex() == null) ? 0 : pageRange.getStartPageIndex();
993 int endPageIndex = (pageRange == null || pageRange.getEndPageIndex() == null) ? (pages.size() - 1) : pageRange.getEndPageIndex();
994
995 for (int pageIndex = startPageIndex; pageIndex <= endPageIndex; pageIndex++)
996 {
997 if (Thread.interrupted())
998 {
999 throw new ExportInterruptedException();
1000 }
1001
1002 JRPrintPage page = pages.get(pageIndex);
1003
1004 pageFormat = jasperPrint.getPageFormat(pageIndex);
1005
1006 if (sizePageToContent || oldPageFormat != pageFormat)
1007 {
1008 setPageSize(sizePageToContent ? page : null);
1009 }
1010
1011 pdfProducer.newPage();
1012
1013 pdfProducer.getPdfContent().setLineCap(LineCapStyle.PROJECTING_SQUARE);
1014
1015 writePageAnchor(pageIndex);
1016
1017 crtDocumentPageNumber++;
1018
1019
1020 exportPage(page);
1021
1022 oldPageFormat = pageFormat;
1023 }
1024 }
1025 else
1026 {
1027 pdfProducer.newPage();
1028 pdfContent.setLiteral("\n");
1029 }
1030 }
1031
1032 closeDocuments = false;
1033 pdfProducer.close();
1034 }
1035 catch(IOException e)
1036 {
1037 throw
1038 new JRException(
1039 EXCEPTION_MESSAGE_KEY_REPORT_GENERATION_ERROR,
1040 new Object[]{jasperPrint.getName()},
1041 e);
1042 }
1043 finally
1044 {
1045 if (closeDocuments)
1046 {
1047 try
1048 {
1049 pdfProducer.close();
1050 }
1051 catch (Exception e)
1052 {
1053
1054 }
1055 }
1056 }
1057
1058
1059 }
1060
1061
1062 protected void writePageAnchor(int pageIndex)
1063 {
1064 Map<Attribute,Object> attributes = new HashMap<Attribute,Object>();
1065 fontUtil.getAttributesWithoutAwtFont(attributes, new JRBasePrintText(jasperPrint.getDefaultStyleProvider()));
1066 PdfTextChunk chunk = pdfProducer.createChunk(" ", attributes, getLocale());
1067
1068 chunk.setLocalDestination(JR_PAGE_ANCHOR_PREFIX + reportIndex + "_" + (pageIndex + 1));
1069
1070 tagHelper.startPageAnchor();
1071
1072 PdfPhrase phrase = pdfProducer.createPhrase(chunk);
1073
1074 phrase.go(
1075 0,
1076 pageFormat.getPageHeight(),
1077 1,
1078 1,
1079 0,
1080 0,
1081 PdfTextAlignment.LEFT,
1082 TextDirection.DEFAULT
1083 );
1084
1085 tagHelper.endPageAnchor();
1086 }
1087
1088
1091 protected void setPageSize(JRPrintPage page) throws JRException, IOException
1092 {
1093 int pageWidth = 0;
1094 int pageHeight = 0;
1095
1096 if (page != null)
1097 {
1098 Collection<JRPrintElement> elements = page.getElements();
1099 for (JRPrintElement element : elements)
1100 {
1101 int elementRight = element.getX() + element.getWidth();
1102 int elementBottom = element.getY() + element.getHeight();
1103 pageWidth = pageWidth < elementRight ? elementRight : pageWidth;
1104 pageHeight = pageHeight < elementBottom ? elementBottom : pageHeight;
1105 }
1106
1107 pageWidth += pageFormat.getRightMargin();
1108 pageHeight += pageFormat.getBottomMargin();
1109 }
1110
1111 pageWidth = pageWidth < pageFormat.getPageWidth() ? pageFormat.getPageWidth() : pageWidth;
1112 pageHeight = pageHeight < pageFormat.getPageHeight() ? pageFormat.getPageHeight() : pageHeight;
1113
1114 pdfProducer.setPageSize(pageFormat, pageWidth, pageHeight);
1115 }
1116
1117
1120 protected void exportPage(JRPrintPage page) throws JRException, IOException
1121 {
1122 tagHelper.startPage();
1123
1124 Collection<JRPrintElement> elements = page.getElements();
1125 exportElements(elements);
1126
1127 pdfProducer.endPage();
1128
1129 tagHelper.endPage();
1130
1131 JRExportProgressMonitor progressMonitor = getCurrentItemConfiguration().getProgressMonitor();
1132 if (progressMonitor != null)
1133 {
1134 progressMonitor.afterPageExport();
1135 }
1136 }
1137
1138 protected void exportElements(Collection<JRPrintElement> elements) throws IOException, JRException
1139 {
1140 if (elements != null && elements.size() > 0)
1141 {
1142 for(Iterator<JRPrintElement> it = elements.iterator(); it.hasNext();)
1143 {
1144 JRPrintElement element = it.next();
1145
1146 if (filter == null || filter.isToExport(element))
1147 {
1148 tagHelper.startElement(element);
1149
1150 String strFieldType = element.getPropertiesMap().getProperty(PDF_FIELD_TYPE);
1151 PdfFieldTypeEnum fieldType = PdfFieldTypeEnum.getByName(strFieldType);
1152 if (fieldType == PdfFieldTypeEnum.CHECK)
1153 {
1154 exportFieldCheck(element);
1155 }
1156 else if (fieldType == PdfFieldTypeEnum.RADIO)
1157 {
1158 exportFieldRadio(element);
1159 }
1160 else if (element instanceof JRPrintLine)
1161 {
1162 exportLine((JRPrintLine)element);
1163 }
1164 else if (element instanceof JRPrintRectangle)
1165 {
1166 exportRectangle((JRPrintRectangle)element);
1167 }
1168 else if (element instanceof JRPrintEllipse)
1169 {
1170 exportEllipse((JRPrintEllipse)element);
1171 }
1172 else if (element instanceof JRPrintImage)
1173 {
1174 exportImage((JRPrintImage)element);
1175 }
1176 else if (element instanceof JRPrintText)
1177 {
1178 if (
1179 fieldType == PdfFieldTypeEnum.TEXT
1180 || fieldType == PdfFieldTypeEnum.COMBO
1181 || fieldType == PdfFieldTypeEnum.LIST
1182 )
1183 {
1184 exportFieldText((JRPrintText)element, fieldType);
1185 }
1186 else
1187 {
1188 exportText((JRPrintText)element);
1189 }
1190 }
1191 else if (element instanceof JRPrintFrame)
1192 {
1193 exportFrame((JRPrintFrame)element);
1194 }
1195 else if (element instanceof JRGenericPrintElement)
1196 {
1197 exportGenericElement((JRGenericPrintElement) element);
1198 }
1199
1200 tagHelper.endElement(element);
1201 }
1202 }
1203 }
1204 }
1205
1206
1207
1210 protected void exportLine(JRPrintLine line)
1211 {
1212 int lcOffsetX = getOffsetX();
1213 int lcOffsetY = getOffsetY();
1214
1215 float lineWidth = line.getLinePen().getLineWidth();
1216 if (lineWidth > 0f)
1217 {
1218 preparePen(line.getLinePen(), LineCapStyle.BUTT);
1219
1220 if (line.getWidth() == 1)
1221 {
1222 if (line.getHeight() != 1)
1223 {
1224
1225 if (line.getLinePen().getLineStyleValue() == LineStyleEnum.DOUBLE)
1226 {
1227 pdfContent.strokeLine(
1228 line.getX() + lcOffsetX + 0.5f - lineWidth / 3,
1229 pageFormat.getPageHeight() - line.getY() - lcOffsetY,
1230 line.getX() + lcOffsetX + 0.5f - lineWidth / 3,
1231 pageFormat.getPageHeight() - line.getY() - lcOffsetY - line.getHeight()
1232 );
1233
1234 pdfContent.strokeLine(
1235 line.getX() + lcOffsetX + 0.5f + lineWidth / 3,
1236 pageFormat.getPageHeight() - line.getY() - lcOffsetY,
1237 line.getX() + lcOffsetX + 0.5f + lineWidth / 3,
1238 pageFormat.getPageHeight() - line.getY() - lcOffsetY - line.getHeight()
1239 );
1240 }
1241 else
1242 {
1243 pdfContent.strokeLine(
1244 line.getX() + lcOffsetX + 0.5f,
1245 pageFormat.getPageHeight() - line.getY() - lcOffsetY,
1246 line.getX() + lcOffsetX + 0.5f,
1247 pageFormat.getPageHeight() - line.getY() - lcOffsetY - line.getHeight()
1248 );
1249 }
1250 }
1251 }
1252 else
1253 {
1254 if (line.getHeight() == 1)
1255 {
1256
1257 if (line.getLinePen().getLineStyleValue() == LineStyleEnum.DOUBLE)
1258 {
1259 pdfContent.strokeLine(
1260 line.getX() + lcOffsetX,
1261 pageFormat.getPageHeight() - line.getY() - lcOffsetY - 0.5f + lineWidth / 3,
1262 line.getX() + lcOffsetX + line.getWidth(),
1263 pageFormat.getPageHeight() - line.getY() - lcOffsetY - 0.5f + lineWidth / 3
1264 );
1265
1266 pdfContent.strokeLine(
1267 line.getX() + lcOffsetX,
1268 pageFormat.getPageHeight() - line.getY() - lcOffsetY - 0.5f - lineWidth / 3,
1269 line.getX() + lcOffsetX + line.getWidth(),
1270 pageFormat.getPageHeight() - line.getY() - lcOffsetY - 0.5f - lineWidth / 3
1271 );
1272 }
1273 else
1274 {
1275 pdfContent.strokeLine(
1276 line.getX() + lcOffsetX,
1277 pageFormat.getPageHeight() - line.getY() - lcOffsetY - 0.5f,
1278 line.getX() + lcOffsetX + line.getWidth(),
1279 pageFormat.getPageHeight() - line.getY() - lcOffsetY - 0.5f
1280 );
1281 }
1282 }
1283 else
1284 {
1285
1286 if (line.getDirectionValue() == LineDirectionEnum.TOP_DOWN)
1287 {
1288 if (line.getLinePen().getLineStyleValue() == LineStyleEnum.DOUBLE)
1289 {
1290 double xtrans = lineWidth / (3 * Math.sqrt(1 + Math.pow(line.getWidth(), 2) / Math.pow(line.getHeight(), 2)));
1291 double ytrans = lineWidth / (3 * Math.sqrt(1 + Math.pow(line.getHeight(), 2) / Math.pow(line.getWidth(), 2)));
1292
1293 pdfContent.strokeLine(
1294 line.getX() + lcOffsetX + (float)xtrans,
1295 pageFormat.getPageHeight() - line.getY() - lcOffsetY + (float)ytrans,
1296 line.getX() + lcOffsetX + line.getWidth() + (float)xtrans,
1297 pageFormat.getPageHeight() - line.getY() - lcOffsetY - line.getHeight() + (float)ytrans
1298 );
1299
1300 pdfContent.strokeLine(
1301 line.getX() + lcOffsetX - (float)xtrans,
1302 pageFormat.getPageHeight() - line.getY() - lcOffsetY - (float)ytrans,
1303 line.getX() + lcOffsetX + line.getWidth() - (float)xtrans,
1304 pageFormat.getPageHeight() - line.getY() - lcOffsetY - line.getHeight() - (float)ytrans
1305 );
1306 }
1307 else
1308 {
1309 pdfContent.strokeLine(
1310 line.getX() + lcOffsetX,
1311 pageFormat.getPageHeight() - line.getY() - lcOffsetY,
1312 line.getX() + lcOffsetX + line.getWidth(),
1313 pageFormat.getPageHeight() - line.getY() - lcOffsetY - line.getHeight()
1314 );
1315 }
1316 }
1317 else
1318 {
1319 if (line.getLinePen().getLineStyleValue() == LineStyleEnum.DOUBLE)
1320 {
1321 double xtrans = lineWidth / (3 * Math.sqrt(1 + Math.pow(line.getWidth(), 2) / Math.pow(line.getHeight(), 2)));
1322 double ytrans = lineWidth / (3 * Math.sqrt(1 + Math.pow(line.getHeight(), 2) / Math.pow(line.getWidth(), 2)));
1323
1324 pdfContent.strokeLine(
1325 line.getX() + lcOffsetX + (float)xtrans,
1326 pageFormat.getPageHeight() - line.getY() - lcOffsetY - line.getHeight() - (float)ytrans,
1327 line.getX() + lcOffsetX + line.getWidth() + (float)xtrans,
1328 pageFormat.getPageHeight() - line.getY() - lcOffsetY - (float)ytrans
1329 );
1330
1331 pdfContent.strokeLine(
1332 line.getX() + lcOffsetX - (float)xtrans,
1333 pageFormat.getPageHeight() - line.getY() - lcOffsetY - line.getHeight() + (float)ytrans,
1334 line.getX() + lcOffsetX + line.getWidth() - (float)xtrans,
1335 pageFormat.getPageHeight() - line.getY() - lcOffsetY + (float)ytrans
1336 );
1337 }
1338 else
1339 {
1340 pdfContent.strokeLine(
1341 line.getX() + lcOffsetX,
1342 pageFormat.getPageHeight() - line.getY() - lcOffsetY - line.getHeight(),
1343 line.getX() + lcOffsetX + line.getWidth(),
1344 pageFormat.getPageHeight() - line.getY() - lcOffsetY
1345 );
1346 }
1347 }
1348 }
1349 }
1350
1351 resetPen();
1352 pdfContent.setLineDash(0f);
1353 pdfContent.setLineCap(LineCapStyle.PROJECTING_SQUARE);
1354 }
1355 }
1356
1357
1358
1361 protected void exportRectangle(JRPrintRectangle rectangle)
1362 {
1363 pdfContent.setFillColor(rectangle.getBackcolor());
1364 preparePen(rectangle.getLinePen(), LineCapStyle.PROJECTING_SQUARE);
1365
1366 float lineWidth = rectangle.getLinePen().getLineWidth();
1367 int lcOffsetX = getOffsetX();
1368 int lcOffsetY = getOffsetY();
1369
1370 if (rectangle.getModeValue() == ModeEnum.OPAQUE)
1371 {
1372 pdfContent.fillRoundRectangle(
1373 rectangle.getX() + lcOffsetX,
1374 pageFormat.getPageHeight() - rectangle.getY() - lcOffsetY - rectangle.getHeight(),
1375 rectangle.getWidth(),
1376 rectangle.getHeight(),
1377 rectangle.getRadius()
1378 );
1379 }
1380
1381 if (lineWidth > 0f)
1382 {
1383 if (rectangle.getLinePen().getLineStyleValue() == LineStyleEnum.DOUBLE)
1384 {
1385 pdfContent.strokeRoundRectangle(
1386 rectangle.getX() + lcOffsetX - lineWidth / 3,
1387 pageFormat.getPageHeight() - rectangle.getY() - lcOffsetY - rectangle.getHeight() - lineWidth / 3,
1388 rectangle.getWidth() + 2 * lineWidth / 3,
1389 rectangle.getHeight() + 2 * lineWidth / 3,
1390 rectangle.getRadius()
1391 );
1392
1393 pdfContent.strokeRoundRectangle(
1394 rectangle.getX() + lcOffsetX + lineWidth / 3,
1395 pageFormat.getPageHeight() - rectangle.getY() - lcOffsetY - rectangle.getHeight() + lineWidth / 3,
1396 rectangle.getWidth() - 2 * lineWidth / 3,
1397 rectangle.getHeight() - 2 * lineWidth / 3,
1398 rectangle.getRadius()
1399 );
1400 }
1401 else
1402 {
1403 pdfContent.strokeRoundRectangle(
1404 rectangle.getX() + lcOffsetX,
1405 pageFormat.getPageHeight() - rectangle.getY() - lcOffsetY - rectangle.getHeight(),
1406 rectangle.getWidth(),
1407 rectangle.getHeight(),
1408 rectangle.getRadius()
1409 );
1410 }
1411 }
1412
1413 resetPen();
1414 pdfContent.resetFillColor();
1415 pdfContent.setLineDash(0f);
1416 }
1417
1418
1419
1422 protected void exportEllipse(JRPrintEllipse ellipse)
1423 {
1424 pdfContent.setFillColor(ellipse.getBackcolor());
1425 preparePen(ellipse.getLinePen(), LineCapStyle.PROJECTING_SQUARE);
1426
1427 float lineWidth = ellipse.getLinePen().getLineWidth();
1428 int lcOffsetX = getOffsetX();
1429 int lcOffsetY = getOffsetY();
1430
1431 if (ellipse.getModeValue() == ModeEnum.OPAQUE)
1432 {
1433 pdfContent.fillEllipse(
1434 ellipse.getX() + lcOffsetX,
1435 pageFormat.getPageHeight() - ellipse.getY() - lcOffsetY - ellipse.getHeight(),
1436 ellipse.getX() + lcOffsetX + ellipse.getWidth(),
1437 pageFormat.getPageHeight() - ellipse.getY() - lcOffsetY
1438 );
1439 }
1440
1441 if (lineWidth > 0f)
1442 {
1443 if (ellipse.getLinePen().getLineStyleValue() == LineStyleEnum.DOUBLE)
1444 {
1445 pdfContent.strokeEllipse(
1446 ellipse.getX() + lcOffsetX - lineWidth / 3,
1447 pageFormat.getPageHeight() - ellipse.getY() - lcOffsetY - ellipse.getHeight() - lineWidth / 3,
1448 ellipse.getX() + lcOffsetX + ellipse.getWidth() + lineWidth / 3,
1449 pageFormat.getPageHeight() - ellipse.getY() - lcOffsetY + lineWidth / 3
1450 );
1451
1452 pdfContent.strokeEllipse(
1453 ellipse.getX() + lcOffsetX + lineWidth / 3,
1454 pageFormat.getPageHeight() - ellipse.getY() - lcOffsetY - ellipse.getHeight() + lineWidth / 3,
1455 ellipse.getX() + lcOffsetX + ellipse.getWidth() - lineWidth / 3,
1456 pageFormat.getPageHeight() - ellipse.getY() - lcOffsetY - lineWidth / 3
1457 );
1458 }
1459 else
1460 {
1461 pdfContent.strokeEllipse(
1462 ellipse.getX() + lcOffsetX,
1463 pageFormat.getPageHeight() - ellipse.getY() - lcOffsetY - ellipse.getHeight(),
1464 ellipse.getX() + lcOffsetX + ellipse.getWidth(),
1465 pageFormat.getPageHeight() - ellipse.getY() - lcOffsetY
1466 );
1467 }
1468 }
1469
1470 resetPen();
1471 pdfContent.resetFillColor();
1472
1473 pdfContent.setLineDash(0f);
1474 }
1475
1476
1477
1480 public void exportImage(JRPrintImage printImage) throws IOException, JRException
1481 {
1482 if (printImage.getModeValue() == ModeEnum.OPAQUE)
1483 {
1484 pdfContent.setFillColor(printImage.getBackcolor());
1485 pdfContent.fillRectangle(
1486 printImage.getX() + getOffsetX(),
1487 pageFormat.getPageHeight() - printImage.getY() - getOffsetY(),
1488 printImage.getWidth(),
1489 - printImage.getHeight()
1490 );
1491 pdfContent.resetFillColor();
1492 }
1493
1494 InternalImageProcessor imageProcessor =
1495 new InternalImageProcessor(printImage);
1496
1497 Renderable renderer = printImage.getRenderer();
1498
1499 if (
1500 renderer != null
1501 && imageProcessor.availableImageWidth > 0
1502 && imageProcessor.availableImageHeight > 0
1503 )
1504 {
1505 InternalImageProcessorResult imageProcessorResult = null;
1506
1507 try
1508 {
1509 imageProcessorResult = imageProcessor.process(renderer);
1510 }
1511 catch (Exception e)
1512 {
1513 Renderable onErrorRenderer = getRendererUtil().handleImageError(e, printImage.getOnErrorTypeValue());
1514 if (onErrorRenderer != null)
1515 {
1516 imageProcessorResult = imageProcessor.process(onErrorRenderer);
1517 }
1518 }
1519
1520 if (imageProcessorResult != null)
1521 {
1522 setAnchor(imageProcessorResult.chunk, printImage, printImage);
1523 setHyperlinkInfo(imageProcessorResult.chunk, printImage);
1524
1525 tagHelper.startImage(printImage);
1526
1527 PdfPhrase phrase = pdfProducer.createPhrase(imageProcessorResult.chunk);
1528
1529 int upperY = pageFormat.getPageHeight() - printImage.getY() - imageProcessor.topPadding - getOffsetY() - imageProcessorResult.yoffset;
1530 int lowerX = printImage.getX() + imageProcessor.leftPadding + getOffsetX() + imageProcessorResult.xoffset;
1531 phrase.go(
1532 lowerX,
1533 upperY,
1534 lowerX + imageProcessorResult.scaledWidth,
1535 upperY - imageProcessorResult.scaledHeight,
1536 0,
1537 0,
1538 PdfTextAlignment.LEFT,
1539 TextDirection.DEFAULT
1540 );
1541
1542 tagHelper.endImage();
1543 }
1544 }
1545
1546
1547 if (
1548 printImage.getLineBox().getTopPen().getLineWidth() <= 0f &&
1549 printImage.getLineBox().getLeftPen().getLineWidth() <= 0f &&
1550 printImage.getLineBox().getBottomPen().getLineWidth() <= 0f &&
1551 printImage.getLineBox().getRightPen().getLineWidth() <= 0f
1552 )
1553 {
1554 if (printImage.getLinePen().getLineWidth() > 0f)
1555 {
1556 exportPen(printImage.getLinePen(), printImage);
1557 }
1558 }
1559 else
1560 {
1561
1562 exportBox(
1563 printImage.getLineBox(),
1564 printImage
1565 );
1566 }
1567 }
1568
1569 private class InternalImageProcessor
1570 {
1571 private final JRPrintImage printImage;
1572 private final RenderersCache imageRenderersCache;
1573
1574 private final int topPadding;
1575 private final int leftPadding;
1576 private final int bottomPadding;
1577 private final int rightPadding;
1578
1579 private final int availableImageWidth;
1580 private final int availableImageHeight;
1581
1582 private InternalImageProcessor(JRPrintImage printImage)
1583 {
1584 this.printImage = printImage;
1585 this.imageRenderersCache = printImage.isUsingCache() ? renderersCache : new RenderersCache(getJasperReportsContext());
1586
1587 topPadding = printImage.getLineBox().getTopPadding();
1588 leftPadding = printImage.getLineBox().getLeftPadding();
1589 bottomPadding = printImage.getLineBox().getBottomPadding();
1590 rightPadding = printImage.getLineBox().getRightPadding();
1591
1592 int tmpAvailableImageWidth = printImage.getWidth() - leftPadding - rightPadding;
1593 availableImageWidth = tmpAvailableImageWidth < 0 ? 0 : tmpAvailableImageWidth;
1594
1595 int tmpAvailableImageHeight = printImage.getHeight() - topPadding - bottomPadding;
1596 availableImageHeight = tmpAvailableImageHeight < 0 ? 0 : tmpAvailableImageHeight;
1597 }
1598
1599 private InternalImageProcessorResult process(Renderable renderer) throws JRException, IOException
1600 {
1601 InternalImageProcessorResult imageProcessorResult = null;
1602
1603 if (renderer instanceof ResourceRenderer)
1604 {
1605 renderer = imageRenderersCache.getLoadedRenderer((ResourceRenderer)renderer);
1606 }
1607
1608 if (renderer instanceof Graphics2DRenderable)
1609 {
1610 imageProcessorResult = processGraphics2D((Graphics2DRenderable)renderer);
1611 }
1612 else if (renderer instanceof DataRenderable)
1613 {
1614 boolean isSvgData = getRendererUtil().isSvgData((DataRenderable)renderer);
1615
1616 if (isSvgData)
1617 {
1618 imageProcessorResult =
1619 processGraphics2D(
1620 new WrappingSvgDataToGraphics2DRenderer((DataRenderable)renderer)
1621 );
1622 }
1623 else
1624 {
1625 switch(printImage.getScaleImageValue())
1626 {
1627 case CLIP :
1628 {
1629 imageProcessorResult =
1630 processImageClip(
1631 new WrappingImageDataToGraphics2DRenderer((DataRenderable)renderer)
1632 );
1633 break;
1634 }
1635 case FILL_FRAME :
1636 {
1637 imageProcessorResult = processImageFillFrame(renderer.getId(), (DataRenderable)renderer);
1638 break;
1639 }
1640 case RETAIN_SHAPE :
1641 default :
1642 {
1643 imageProcessorResult = processImageRetainShape(renderer.getId(), (DataRenderable)renderer);
1644 }
1645 }
1646 }
1647 }
1648 else
1649 {
1650 throw
1651 new JRException(
1652 RendererUtil.EXCEPTION_MESSAGE_KEY_RENDERABLE_MUST_IMPLEMENT_INTERFACE,
1653 new Object[]{
1654 renderer.getClass().getName(),
1655 DataRenderable.class.getName()
1656 + " or " + Graphics2DRenderable.class.getName()
1657 }
1658 );
1659 }
1660
1661 return imageProcessorResult;
1662 }
1663
1664
1665 private InternalImageProcessorResult processImageClip(Graphics2DRenderable renderer) throws JRException, IOException
1666 {
1667 int normalWidth = availableImageWidth;
1668 int normalHeight = availableImageHeight;
1669
1670 Dimension2D dimension =
1671 renderer instanceof DimensionRenderable
1672 ? ((DimensionRenderable)renderer).getDimension(jasperReportsContext)
1673 : null;
1674 if (dimension != null)
1675 {
1676 normalWidth = (int)dimension.getWidth();
1677 normalHeight = (int)dimension.getHeight();
1678 }
1679
1680 int minWidth = Math.min(normalWidth, availableImageWidth);
1681 int minHeight = Math.min(normalHeight, availableImageHeight);
1682 int xoffset = (int)(ImageUtil.getXAlignFactor(printImage) * (availableImageWidth - normalWidth));
1683 int yoffset = (int)(ImageUtil.getYAlignFactor(printImage) * (availableImageHeight - normalHeight));
1684 int translateX = xoffset;
1685 int translateY = yoffset;
1686 int angle = 0;
1687
1688 switch (printImage.getRotation())
1689 {
1690 case LEFT :
1691 {
1692 minWidth = Math.min(normalWidth, availableImageHeight);
1693 minHeight = Math.min(normalHeight, availableImageWidth);
1694 xoffset = (int)(ImageUtil.getYAlignFactor(printImage) * (availableImageWidth - normalHeight));
1695 yoffset = (int)((1f - ImageUtil.getXAlignFactor(printImage)) * (availableImageHeight - normalWidth));
1696 translateX = (int)(ImageUtil.getXAlignFactor(printImage) * (availableImageHeight - normalWidth));
1697 translateY = xoffset;
1698 angle = 90;
1699 break;
1700 }
1701 case RIGHT :
1702 {
1703 minWidth = Math.min(normalWidth, availableImageHeight);
1704 minHeight = Math.min(normalHeight, availableImageWidth);
1705 xoffset = (int)((1f - ImageUtil.getYAlignFactor(printImage)) * (availableImageWidth - normalHeight));
1706 yoffset = (int)(ImageUtil.getXAlignFactor(printImage) * (availableImageHeight - normalWidth));
1707 translateX = yoffset;
1708 translateY = (int)(ImageUtil.getYAlignFactor(printImage) * (availableImageWidth - normalHeight));
1709 angle = -90;
1710 break;
1711 }
1712 case UPSIDE_DOWN :
1713 {
1714 minWidth = Math.min(normalWidth, availableImageWidth);
1715 minHeight = Math.min(normalHeight, availableImageHeight);
1716 xoffset = (int)((1f - ImageUtil.getXAlignFactor(printImage)) * (availableImageWidth - normalWidth));
1717 yoffset = (int)((1f - ImageUtil.getYAlignFactor(printImage)) * (availableImageHeight - normalHeight));
1718 translateX = (int)(ImageUtil.getXAlignFactor(printImage) * (availableImageWidth - normalWidth));
1719 translateY = (int)(ImageUtil.getYAlignFactor(printImage) * (availableImageHeight - normalHeight));
1720 angle = 180;
1721 break;
1722 }
1723 case NONE :
1724 default :
1725 {
1726 }
1727 }
1728
1729 BufferedImage bi =
1730 new BufferedImage(minWidth, minHeight, BufferedImage.TYPE_INT_ARGB);
1731
1732 Graphics2D g = bi.createGraphics();
1733 try
1734 {
1735 if (printImage.getModeValue() == ModeEnum.OPAQUE)
1736 {
1737 g.setColor(printImage.getBackcolor());
1738 g.fillRect(0, 0, minWidth, minHeight);
1739 }
1740 renderer.render(
1741 jasperReportsContext,
1742 g,
1743 new java.awt.Rectangle(
1744 translateX > 0 ? 0 : translateX,
1745 translateY > 0 ? 0 : translateY,
1746 normalWidth,
1747 normalHeight
1748 )
1749 );
1750 }
1751 finally
1752 {
1753 g.dispose();
1754 }
1755
1756
1757
1758
1759 PdfImage image = pdfProducer.createImage(bi, angle);
1760 PdfChunk chunk = pdfProducer.createChunk(image);
1761
1762 return
1763 new InternalImageProcessorResult(
1764 chunk,
1765 image.getScaledWidth(),
1766 image.getScaledHeight(),
1767 xoffset < 0 ? 0 : xoffset,
1768 yoffset < 0 ? 0 : yoffset
1769 );
1770 }
1771
1772 private InternalImageProcessorResult processImageFillFrame(String rendererId, DataRenderable renderer) throws JRException
1773 {
1774 PdfImage image = null;
1775
1776 if (printImage.isUsingCache() && loadedImagesMap.containsKey(rendererId))
1777 {
1778 image = loadedImagesMap.get(rendererId);
1779 }
1780 else
1781 {
1782 try
1783 {
1784 image = pdfProducer.createImage(renderer.getData(jasperReportsContext), true);
1785 }
1786 catch (Exception e)
1787 {
1788 throw new JRException(e);
1789 }
1790
1791 if (printImage.isUsingCache())
1792 {
1793 loadedImagesMap.put(rendererId, image);
1794 }
1795 }
1796
1797 switch (printImage.getRotation())
1798 {
1799 case LEFT :
1800 {
1801 image.scaleAbsolute(availableImageHeight, availableImageWidth);
1802 image.setRotationDegrees(90);
1803 break;
1804 }
1805 case RIGHT :
1806 {
1807 image.scaleAbsolute(availableImageHeight, availableImageWidth);
1808 image.setRotationDegrees(-90);
1809 break;
1810 }
1811 case UPSIDE_DOWN :
1812 {
1813 image.scaleAbsolute(availableImageWidth, availableImageHeight);
1814 image.setRotationDegrees(180);
1815 break;
1816 }
1817 case NONE :
1818 default :
1819 {
1820 image.scaleAbsolute(availableImageWidth, availableImageHeight);
1821 }
1822 }
1823
1824 PdfChunk chunk = pdfProducer.createChunk(image);
1825 return
1826 new InternalImageProcessorResult(
1827 chunk,
1828 image.getScaledWidth(),
1829 image.getScaledHeight(),
1830 0,
1831 0
1832 );
1833 }
1834
1835 private InternalImageProcessorResult processImageRetainShape(String rendererId, DataRenderable renderer) throws JRException
1836 {
1837 PdfImage image = null;
1838
1839 if (printImage.isUsingCache() && loadedImagesMap.containsKey(rendererId))
1840 {
1841 image = loadedImagesMap.get(rendererId);
1842 }
1843 else
1844 {
1845 try
1846 {
1847 image = pdfProducer.createImage(renderer.getData(jasperReportsContext), true);
1848 }
1849 catch (Exception e)
1850 {
1851 throw new JRException(e);
1852 }
1853
1854 if (printImage.isUsingCache())
1855 {
1856 loadedImagesMap.put(rendererId, image);
1857 }
1858 }
1859
1860 int xoffset = 0;
1861 int yoffset = 0;
1862
1863 image.setRotationDegrees(0);
1864
1865 switch (printImage.getRotation())
1866 {
1867 case LEFT :
1868 {
1869 image.scaleToFit(availableImageHeight, availableImageWidth);
1870 image.setRotationDegrees(90);
1871 xoffset = (int)(ImageUtil.getYAlignFactor(printImage) * (availableImageWidth - image.getPlainHeight()));
1872 yoffset = (int)((1f - ImageUtil.getXAlignFactor(printImage)) * (availableImageHeight - image.getPlainWidth()));
1873 break;
1874 }
1875 case RIGHT :
1876 {
1877 image.scaleToFit(availableImageHeight, availableImageWidth);
1878 image.setRotationDegrees(-90);
1879 xoffset = (int)((1f - ImageUtil.getYAlignFactor(printImage)) * (availableImageWidth - image.getPlainHeight()));
1880 yoffset = (int)(ImageUtil.getXAlignFactor(printImage) * (availableImageHeight - image.getPlainWidth()));
1881 break;
1882 }
1883 case UPSIDE_DOWN :
1884 {
1885 image.scaleToFit(availableImageWidth, availableImageHeight);
1886 image.setRotationDegrees(180);
1887 xoffset = (int)((1f - ImageUtil.getXAlignFactor(printImage)) * (availableImageWidth - image.getPlainWidth()));
1888 yoffset = (int)((1f - ImageUtil.getYAlignFactor(printImage)) * (availableImageHeight - image.getPlainHeight()));
1889 break;
1890 }
1891 case NONE :
1892 default :
1893 {
1894 image.scaleToFit(availableImageWidth, availableImageHeight);
1895 xoffset = (int)(ImageUtil.getXAlignFactor(printImage) * (availableImageWidth - image.getPlainWidth()));
1896 yoffset = (int)(ImageUtil.getYAlignFactor(printImage) * (availableImageHeight - image.getPlainHeight()));
1897 }
1898 }
1899
1900 xoffset = (xoffset < 0 ? 0 : xoffset);
1901 yoffset = (yoffset < 0 ? 0 : yoffset);
1902
1903 PdfChunk chunk = pdfProducer.createChunk(image);
1904 return
1905 new InternalImageProcessorResult(
1906 chunk,
1907 image.getScaledWidth(),
1908 image.getScaledHeight(),
1909 xoffset,
1910 yoffset
1911 );
1912 }
1913
1914 private InternalImageProcessorResult processGraphics2D(Graphics2DRenderable renderer) throws JRException, IOException
1915 {
1916 int xoffset = 0;
1917 int yoffset = 0;
1918 int translateX = 0;
1919 int translateY = 0;
1920 double templateWidth = 0;
1921 double templateHeight = 0;
1922 double renderWidth = 0;
1923 double renderHeight = 0;
1924 double ratioX = 1f;
1925 double ratioY = 1f;
1926 double angle = 0;
1927
1928 switch (printImage.getScaleImageValue())
1929 {
1930 case CLIP:
1931 {
1932 Dimension2D dimension =
1933 renderer instanceof DimensionRenderable
1934 ? ((DimensionRenderable)renderer).getDimension(jasperReportsContext)
1935 : null;
1936 if (dimension != null)
1937 {
1938 renderWidth = dimension.getWidth();
1939 renderHeight = dimension.getHeight();
1940 }
1941
1942 templateWidth = availableImageWidth;
1943 templateHeight = availableImageHeight;
1944
1945 switch (printImage.getRotation())
1946 {
1947 case LEFT:
1948 if (dimension == null)
1949 {
1950 renderWidth = availableImageHeight;
1951 renderHeight = availableImageWidth;
1952 }
1953 translateX = (int)(ImageUtil.getYAlignFactor(printImage) * (availableImageWidth - renderHeight));
1954 translateY = availableImageHeight - (int)(ImageUtil.getXAlignFactor(printImage) * (availableImageHeight - renderWidth));
1955 angle = - Math.PI / 2;
1956 break;
1957 case RIGHT:
1958 if (dimension == null)
1959 {
1960 renderWidth = availableImageHeight;
1961 renderHeight = availableImageWidth;
1962 }
1963 translateX = availableImageWidth - (int)(ImageUtil.getYAlignFactor(printImage) * (availableImageWidth - renderHeight));
1964 translateY = (int)(ImageUtil.getXAlignFactor(printImage) * (availableImageHeight - renderWidth));
1965 angle = Math.PI / 2;
1966 break;
1967 case UPSIDE_DOWN:
1968 if (dimension == null)
1969 {
1970 renderWidth = availableImageWidth;
1971 renderHeight = availableImageHeight;
1972 }
1973 translateX = availableImageWidth - (int)(ImageUtil.getXAlignFactor(printImage) * (availableImageWidth - renderWidth));
1974 translateY = availableImageHeight - (int)(ImageUtil.getYAlignFactor(printImage) * (availableImageHeight - renderHeight));
1975 angle = Math.PI;
1976 break;
1977 case NONE:
1978 default:
1979 if (dimension == null)
1980 {
1981 renderWidth = availableImageWidth;
1982 renderHeight = availableImageHeight;
1983 }
1984 translateX = (int) (ImageUtil.getXAlignFactor(printImage) * (availableImageWidth - renderWidth));
1985 translateY = (int) (ImageUtil.getYAlignFactor(printImage) * (availableImageHeight - renderHeight));
1986 angle = 0;
1987 break;
1988 }
1989 break;
1990 }
1991 case FILL_FRAME:
1992 {
1993 templateWidth = availableImageWidth;
1994 templateHeight = availableImageHeight;
1995
1996 switch (printImage.getRotation())
1997 {
1998 case LEFT:
1999 renderWidth = availableImageHeight;
2000 renderHeight = availableImageWidth;
2001 translateX = 0;
2002 translateY = availableImageHeight;
2003 angle = - Math.PI / 2;
2004 break;
2005 case RIGHT:
2006 renderWidth = availableImageHeight;
2007 renderHeight = availableImageWidth;
2008 translateX = availableImageWidth;
2009 translateY = 0;
2010 angle = Math.PI / 2;
2011 break;
2012 case UPSIDE_DOWN:
2013 renderWidth = availableImageWidth;
2014 renderHeight = availableImageHeight;
2015 translateX = availableImageWidth;
2016 translateY = availableImageHeight;
2017 angle = Math.PI;
2018 break;
2019 case NONE:
2020 default:
2021 renderWidth = availableImageWidth;
2022 renderHeight = availableImageHeight;
2023 translateX = 0;
2024 translateY = 0;
2025 angle = 0;
2026 break;
2027 }
2028 break;
2029 }
2030 case RETAIN_SHAPE:
2031 default:
2032 {
2033 Dimension2D dimension =
2034 renderer instanceof DimensionRenderable
2035 ? ((DimensionRenderable)renderer).getDimension(jasperReportsContext)
2036 : null;
2037 if (dimension != null)
2038 {
2039 renderWidth = dimension.getWidth();
2040 renderHeight = dimension.getHeight();
2041 }
2042
2043 switch (printImage.getRotation())
2044 {
2045 case LEFT:
2046 if (dimension == null)
2047 {
2048 renderWidth = availableImageHeight;
2049 renderHeight = availableImageWidth;
2050 }
2051 ratioX = availableImageWidth / renderHeight;
2052 ratioY = availableImageHeight / renderWidth;
2053 ratioX = ratioX < ratioY ? ratioX : ratioY;
2054 ratioY = ratioX;
2055 templateWidth = renderHeight;
2056 templateHeight = renderWidth;
2057 translateX = 0;
2058 translateY = (int)renderWidth;
2059 xoffset = (int) (ImageUtil.getYAlignFactor(printImage) * (availableImageWidth - renderHeight * ratioX));
2060 yoffset = (int) (ImageUtil.getXAlignFactor(printImage) * (availableImageHeight - renderWidth * ratioY));
2061 angle = - Math.PI / 2;
2062 break;
2063 case RIGHT:
2064 if (dimension == null)
2065 {
2066 renderWidth = availableImageHeight;
2067 renderHeight = availableImageWidth;
2068 }
2069 ratioX = availableImageWidth / renderHeight;
2070 ratioY = availableImageHeight / renderWidth;
2071 ratioX = ratioX < ratioY ? ratioX : ratioY;
2072 ratioY = ratioX;
2073 templateWidth = renderHeight;
2074 templateHeight = renderWidth;
2075 translateX = (int)renderHeight;
2076 translateY = 0;
2077 xoffset = (int) ((1f - ImageUtil.getYAlignFactor(printImage)) * (availableImageWidth - renderHeight * ratioX));
2078 yoffset = (int) ((1f - ImageUtil.getXAlignFactor(printImage)) * (availableImageHeight - renderWidth * ratioY));
2079 angle = Math.PI / 2;
2080 break;
2081 case UPSIDE_DOWN:
2082 if (dimension == null)
2083 {
2084 renderWidth = availableImageWidth;
2085 renderHeight = availableImageHeight;
2086 }
2087 ratioX = availableImageWidth / renderWidth;
2088 ratioY = availableImageHeight / renderHeight;
2089 ratioX = ratioX < ratioY ? ratioX : ratioY;
2090 ratioY = ratioX;
2091 templateWidth = renderWidth;
2092 templateHeight = renderHeight;
2093 translateX = (int)renderWidth;
2094 translateY = (int)renderHeight;
2095 xoffset = (int) ((1f - ImageUtil.getXAlignFactor(printImage)) * (availableImageWidth - renderWidth * ratioX));
2096 yoffset = (int) (ImageUtil.getYAlignFactor(printImage) * (availableImageHeight - renderHeight * ratioY));
2097 angle = Math.PI;
2098 break;
2099 case NONE:
2100 default:
2101 if (dimension == null)
2102 {
2103 renderWidth = availableImageWidth;
2104 renderHeight = availableImageHeight;
2105 }
2106 ratioX = availableImageWidth / renderWidth;
2107 ratioY = availableImageHeight / renderHeight;
2108 ratioX = ratioX < ratioY ? ratioX : ratioY;
2109 ratioY = ratioX;
2110 templateWidth = renderWidth;
2111 templateHeight = renderHeight;
2112 translateX = 0;
2113 translateY = 0;
2114 xoffset = (int) (ImageUtil.getXAlignFactor(printImage) * (availableImageWidth - renderWidth * ratioX));
2115 yoffset = (int) ((1f - ImageUtil.getYAlignFactor(printImage)) * (availableImageHeight - renderHeight * ratioY));
2116 angle = 0;
2117 break;
2118 }
2119 break;
2120 }
2121 }
2122
2123 pdfProducer.drawImage(printImage, renderer, getCurrentItemConfiguration().isForceSvgShapes(),
2124 templateWidth, templateHeight,
2125 translateX, translateY, angle,
2126 renderWidth, renderHeight,
2127 (float) ratioX, (float) ratioY,
2128 printImage.getX() + leftPadding + getOffsetX()
2129 + xoffset,
2130 pageFormat.getPageHeight() - printImage.getY() - topPadding - getOffsetY()
2131 - availableImageHeight
2132 + yoffset);
2133
2134 PdfImage image = getPxImage();
2135 image.scaleAbsolute(availableImageWidth, availableImageHeight);
2136
2137 PdfChunk chunk = pdfProducer.createChunk(image);
2138 InternalImageProcessorResult result =
2139 new InternalImageProcessorResult(
2140 chunk,
2141 availableImageWidth,
2142 availableImageHeight,
2143 0,
2144 0
2145 );
2146
2147 return result;
2148 }
2149 }
2150
2151 private class InternalImageProcessorResult
2152 {
2153 private final PdfChunk chunk;
2154 private final float scaledWidth;
2155 private final float scaledHeight;
2156 private final int xoffset;
2157 private final int yoffset;
2158
2159 private InternalImageProcessorResult(
2160 PdfChunk chunk,
2161 float scaledWidth,
2162 float scaledHeight,
2163 int xoffset,
2164 int yoffset
2165 )
2166 {
2167 this.chunk = chunk;
2168 this.scaledWidth = scaledWidth;
2169 this.scaledHeight = scaledHeight;
2170 this.xoffset = xoffset;
2171 this.yoffset = yoffset;
2172 }
2173 }
2174
2175
2176
2179 protected void setHyperlinkInfo(PdfChunk chunk, JRPrintHyperlink link)
2180 {
2181 if (link != null)
2182 {
2183 Boolean ignoreHyperlink = HyperlinkUtil.getIgnoreHyperlink(PdfReportConfiguration.PROPERTY_IGNORE_HYPERLINK, link);
2184 if (ignoreHyperlink == null)
2185 {
2186 ignoreHyperlink = getCurrentItemConfiguration().isIgnoreHyperlink();
2187 }
2188
2189 if (!ignoreHyperlink)
2190 {
2191 switch(link.getHyperlinkTypeValue())
2192 {
2193 case REFERENCE :
2194 {
2195 if (link.getHyperlinkReference() != null)
2196 {
2197 switch(link.getHyperlinkTargetValue())
2198 {
2199 case BLANK :
2200 {
2201 chunk.setJavaScriptAction(
2202 "if (app.viewerVersion < 7)"
2203 + "{this.getURL(\"" + link.getHyperlinkReference() + "\");}"
2204 + "else {app.launchURL(\"" + link.getHyperlinkReference() + "\", true);};"
2205 );
2206 break;
2207 }
2208 case SELF :
2209 default :
2210 {
2211 chunk.setAnchor(link.getHyperlinkReference());
2212 break;
2213 }
2214 }
2215 }
2216 break;
2217 }
2218 case LOCAL_ANCHOR :
2219 {
2220 if (link.getHyperlinkAnchor() != null)
2221 {
2222 chunk.setLocalGoto(link.getHyperlinkAnchor());
2223 }
2224 break;
2225 }
2226 case LOCAL_PAGE :
2227 {
2228 if (link.getHyperlinkPage() != null)
2229 {
2230 chunk.setLocalGoto(JR_PAGE_ANCHOR_PREFIX + reportIndex + "_" + link.getHyperlinkPage().toString());
2231 }
2232 break;
2233 }
2234 case REMOTE_ANCHOR :
2235 {
2236 if (
2237 link.getHyperlinkReference() != null &&
2238 link.getHyperlinkAnchor() != null
2239 )
2240 {
2241 chunk.setRemoteGoto(
2242 link.getHyperlinkReference(),
2243 link.getHyperlinkAnchor()
2244 );
2245 }
2246 break;
2247 }
2248 case REMOTE_PAGE :
2249 {
2250 if (
2251 link.getHyperlinkReference() != null &&
2252 link.getHyperlinkPage() != null
2253 )
2254 {
2255 chunk.setRemoteGoto(
2256 link.getHyperlinkReference(),
2257 link.getHyperlinkPage()
2258 );
2259 }
2260 break;
2261 }
2262 case CUSTOM :
2263 {
2264 JRHyperlinkProducerFactory hyperlinkProducerFactory = getCurrentItemConfiguration().getHyperlinkProducerFactory();
2265 if (hyperlinkProducerFactory != null)
2266 {
2267 String hyperlink = hyperlinkProducerFactory.produceHyperlink(link);
2268 if (hyperlink != null)
2269 {
2270 switch(link.getHyperlinkTargetValue())
2271 {
2272 case BLANK :
2273 {
2274 chunk.setJavaScriptAction(
2275 "if (app.viewerVersion < 7)"
2276 + "{this.getURL(\"" + hyperlink + "\");}"
2277 + "else {app.launchURL(\"" + hyperlink + "\", true);};"
2278 );
2279 break;
2280 }
2281 case SELF :
2282 default :
2283 {
2284 chunk.setAnchor(hyperlink);
2285 break;
2286 }
2287 }
2288 }
2289 }
2290 }
2291 case NONE :
2292 default :
2293 {
2294 break;
2295 }
2296 }
2297 }
2298 }
2299 }
2300
2301 @Override
2302 protected Locale getTextLocale(JRPrintText text)
2303 {
2304
2305 return super.getTextLocale(text);
2306 }
2307
2308
2309
2312 protected void getPhrase(AttributedString as, String text, JRPrintText textElement,
2313 PdfPhrase phrase)
2314 {
2315 int runLimit = 0;
2316
2317 AttributedCharacterIterator iterator = as.getIterator();
2318 Locale locale = getTextLocale(textElement);
2319
2320 boolean firstChunk = true;
2321 while(runLimit < text.length() && (runLimit = iterator.getRunLimit()) <= text.length())
2322 {
2323 Map<Attribute,Object> attributes = iterator.getAttributes();
2324 PdfTextChunk chunk = getChunk(attributes, text.substring(iterator.getIndex(), runLimit), locale);
2325
2326 if (firstChunk)
2327 {
2328
2329 setAnchor(chunk, textElement, textElement);
2330 }
2331
2332 JRPrintHyperlink hyperlink = textElement;
2333 if (hyperlink.getHyperlinkTypeValue() == HyperlinkTypeEnum.NONE)
2334 {
2335 hyperlink = (JRPrintHyperlink)attributes.get(JRTextAttribute.HYPERLINK);
2336 }
2337
2338 setHyperlinkInfo(chunk, hyperlink);
2339 phrase.add(chunk);
2340
2341 iterator.setIndex(runLimit);
2342 firstChunk = false;
2343 }
2344 }
2345
2346
2347
2350 protected PdfTextChunk getChunk(Map<Attribute,Object> attributes, String text, Locale locale)
2351 {
2352
2353 PdfTextChunk chunk = pdfProducer.createChunk(text, attributes, locale);
2354
2355 if (hasUnderline(attributes))
2356 {
2357 chunk.setUnderline();
2358 }
2359
2360 if (hasStrikethrough(attributes))
2361 {
2362 chunk.setStrikethrough();
2363 }
2364
2365 Color backcolor = (Color)attributes.get(TextAttribute.BACKGROUND);
2366 if (backcolor != null)
2367 {
2368 chunk.setBackground(backcolor);
2369 }
2370
2371 Object script = attributes.get(TextAttribute.SUPERSCRIPT);
2372 if (script != null)
2373 {
2374 if (TextAttribute.SUPERSCRIPT_SUPER.equals(script))
2375 {
2376 chunk.setSuperscript();
2377 }
2378 else if (TextAttribute.SUPERSCRIPT_SUB.equals(script))
2379 {
2380 chunk.setSubscript();
2381 }
2382 }
2383
2384 return chunk;
2385 }
2386
2387 protected boolean hasUnderline(Map<Attribute,Object> textAttributes)
2388 {
2389 Integer underline = (Integer) textAttributes.get(TextAttribute.UNDERLINE);
2390 return TextAttribute.UNDERLINE_ON.equals(underline);
2391 }
2392
2393 protected boolean hasStrikethrough(Map<Attribute,Object> textAttributes)
2394 {
2395 Boolean strike = (Boolean) textAttributes.get(TextAttribute.STRIKETHROUGH);
2396 return TextAttribute.STRIKETHROUGH_ON.equals(strike);
2397 }
2398
2399
2400
2408 protected void setFont(Map<Attribute,Object> attributes, Locale locale, boolean setFontLines,
2409 FontRecipient recipient)
2410 {
2411 JRFont jrFont = new JRBaseFont(attributes);
2412
2413 Exception initialException = null;
2414
2415 Color forecolor = (Color)attributes.get(TextAttribute.FOREGROUND);
2416
2417
2418 float fontSizeScale = 1f;
2419 Integer scriptStyle = (Integer) attributes.get(TextAttribute.SUPERSCRIPT);
2420 if (scriptStyle != null && (
2421 TextAttribute.SUPERSCRIPT_SUB.equals(scriptStyle)
2422 || TextAttribute.SUPERSCRIPT_SUPER.equals(scriptStyle)))
2423 {
2424 fontSizeScale = 2f / 3;
2425 }
2426
2427 String pdfFontName = null;
2428 String pdfEncoding = null;
2429 boolean isPdfEmbedded = false;
2430 boolean isPdfSimulatedBold = false;
2431 boolean isPdfSimulatedItalic = false;
2432
2433 FontInfo fontInfo = (FontInfo) attributes.get(JRTextAttribute.FONT_INFO);
2434 if (fontInfo == null)
2435 {
2436 fontInfo = fontUtil.getFontInfo(jrFont.getFontName(), locale);
2437 }
2438
2439 if (fontInfo == null)
2440 {
2441
2442 pdfFontName = jrFont.getPdfFontName();
2443 pdfEncoding = jrFont.getPdfEncoding();
2444 isPdfEmbedded = jrFont.isPdfEmbedded();
2445 }
2446 else
2447 {
2448
2449 FontFamily family = fontInfo.getFontFamily();
2450
2451 int pdfFontStyle = java.awt.Font.PLAIN;
2452
2453 FontFace fontFace = fontInfo.getFontFace();
2454 if (fontFace != null)
2455 {
2456 pdfFontName = fontFace.getPdf();
2457 pdfFontName = pdfFontName == null ? fontFace.getTtf() : pdfFontName;
2458 pdfFontStyle = fontInfo.getStyle();
2459 }
2460
2461 if (pdfFontName == null && jrFont.isBold() && jrFont.isItalic())
2462 {
2463 fontFace = family.getBoldItalicFace();
2464 if (fontFace != null)
2465 {
2466 pdfFontName = fontFace.getPdf();
2467 pdfFontName = pdfFontName == null ? fontFace.getTtf() : pdfFontName;
2468 pdfFontStyle = java.awt.Font.BOLD | java.awt.Font.ITALIC;
2469 }
2470 }
2471
2472 if (pdfFontName == null && jrFont.isBold())
2473 {
2474 fontFace = family.getBoldFace();
2475 if (fontFace != null)
2476 {
2477 pdfFontName = fontFace.getPdf();
2478 pdfFontName = pdfFontName == null ? fontFace.getTtf() : pdfFontName;
2479 pdfFontStyle = java.awt.Font.BOLD;
2480 }
2481 }
2482
2483 if (pdfFontName == null && jrFont.isItalic())
2484 {
2485 fontFace = family.getItalicFace();
2486 if (fontFace != null)
2487 {
2488 pdfFontName = fontFace.getPdf();
2489 pdfFontName = pdfFontName == null ? fontFace.getTtf() : pdfFontName;
2490 pdfFontStyle = java.awt.Font.ITALIC;
2491 }
2492 }
2493
2494 if (pdfFontName == null)
2495 {
2496 fontFace = family.getNormalFace();
2497 if (fontFace != null)
2498 {
2499 pdfFontName = fontFace.getPdf();
2500 pdfFontName = pdfFontName == null ? fontFace.getTtf() : pdfFontName;
2501 pdfFontStyle = java.awt.Font.PLAIN;
2502 }
2503 }
2504
2505 if (pdfFontName == null)
2506 {
2507 pdfFontName = jrFont.getPdfFontName();
2508 }
2509
2510 pdfEncoding = family.getPdfEncoding() == null ? jrFont.getPdfEncoding() : family.getPdfEncoding();
2511 isPdfEmbedded = family.isPdfEmbedded() == null ? jrFont.isPdfEmbedded() : family.isPdfEmbedded();
2512 isPdfSimulatedBold = jrFont.isBold() && ((pdfFontStyle & java.awt.Font.BOLD) == 0);
2513 isPdfSimulatedItalic = jrFont.isItalic() && ((pdfFontStyle & java.awt.Font.ITALIC) == 0);
2514 }
2515
2516 PdfFontStyle pdfFontStyle = new PdfFontStyle(isPdfSimulatedBold, isPdfSimulatedItalic,
2517 setFontLines && jrFont.isUnderline(), setFontLines && jrFont.isStrikeThrough());
2518
2519 try
2520 {
2521 recipient.setFont(
2522 pdfFontName,
2523 pdfEncoding,
2524 isPdfEmbedded,
2525 jrFont.getFontsize() * fontSizeScale,
2526 pdfFontStyle,
2527 forecolor
2528 );
2529 }
2530 catch(Exception e)
2531 {
2532 initialException = e;
2533 }
2534
2535 if (!recipient.hasFont())
2536 {
2537 byte[] bytes = null;
2538
2539 try
2540 {
2541 bytes = getRepository().getBytesFromLocation(pdfFontName);
2542 }
2543 catch(JRException e)
2544 {
2545 throw
2546 new JRRuntimeException(
2547 EXCEPTION_MESSAGE_KEY_FONT_LOADING_ERROR,
2548 new Object[]{pdfFontName, pdfEncoding, isPdfEmbedded},
2549 initialException);
2550 }
2551
2552 recipient.setFont(pdfFontName, pdfEncoding, isPdfEmbedded,
2553 jrFont.getFontsize() * fontSizeScale, pdfFontStyle, forecolor, bytes);
2554 }
2555 }
2556
2557
2558
2561 public void exportText(JRPrintText text)
2562 {
2563 JRStyledText styledText = styledTextUtil.getProcessedStyledText(text, noBackcolorSelector, null);
2564
2565 if (styledText == null)
2566 {
2567 return;
2568 }
2569
2570 AbstractPdfTextRenderer textRenderer = getTextRenderer(text, styledText);
2571 textRenderer.initialize(this, pdfProducer, text, styledText, getOffsetX(), getOffsetY());
2572
2573 double angle = 0;
2574
2575 switch (text.getRotationValue())
2576 {
2577 case LEFT :
2578 {
2579 angle = Math.PI / 2;
2580 break;
2581 }
2582 case RIGHT :
2583 {
2584 angle = - Math.PI / 2;
2585 break;
2586 }
2587 case UPSIDE_DOWN :
2588 {
2589 angle = Math.PI;
2590 break;
2591 }
2592 case NONE :
2593 default :
2594 {
2595 }
2596 }
2597
2598 AffineTransform atrans = new AffineTransform();
2599 atrans.rotate(angle, textRenderer.getX(), pageFormat.getPageHeight() - textRenderer.getY());
2600 pdfContent.transform(atrans);
2601
2602 if (text.getModeValue() == ModeEnum.OPAQUE)
2603 {
2604 Color backcolor = text.getBackcolor();
2605 pdfContent.setFillColor(backcolor);
2606 pdfContent.fillRectangle(
2607 textRenderer.getX(),
2608 pageFormat.getPageHeight() - textRenderer.getY(),
2609 textRenderer.getWidth(),
2610 - textRenderer.getHeight()
2611 );
2612 pdfContent.resetFillColor();
2613 }
2614
2615 if (textRenderer.addActualText())
2616 {
2617 tagHelper.startText(styledText.getText(), text.getLinkType() != null);
2618 }
2619 else
2620 {
2621 tagHelper.startText(text.getLinkType() != null);
2622 }
2623
2624 int forecolorAlpha = getSingleForecolorAlpha(styledText);
2625 pdfContent.setFillColorAlpha(forecolorAlpha);
2626
2627
2628 if (styledText.length() > 0)
2629 {
2630 textRenderer.render();
2631 }
2632 tagHelper.endText();
2633
2634 pdfContent.resetFillColor();
2635
2636 atrans = new AffineTransform();
2637 atrans.rotate(-angle, textRenderer.getX(), pageFormat.getPageHeight() - textRenderer.getY());
2638 pdfContent.transform(atrans);
2639
2640
2641 exportBox(
2642 text.getLineBox(),
2643 text
2644 );
2645 }
2646
2647 protected int getSingleForecolorAlpha(JRStyledText styledText)
2648 {
2649 Color forecolor = (Color) styledText.getGlobalAttributes().get(TextAttribute.FOREGROUND);
2650 if (forecolor == null || forecolor.getAlpha() == 255)
2651 {
2652 return 255;
2653 }
2654
2655 List<JRStyledText.Run> runs = styledText.getRuns();
2656 if (runs.size() > 1)
2657 {
2658 for (JRStyledText.Run run : runs)
2659 {
2660 Color runForecolor = (Color) run.attributes.get(TextAttribute.FOREGROUND);
2661 if (runForecolor != null && runForecolor.getAlpha() != forecolor.getAlpha())
2662 {
2663
2664
2665 return 255;
2666 }
2667 }
2668 }
2669
2670 return forecolor.getAlpha();
2671 }
2672
2673
2676 public void exportFieldText(JRPrintText text, PdfFieldTypeEnum fieldType)
2677 {
2678 String fieldName = text.getPropertiesMap().getProperty(PDF_FIELD_NAME);
2679 fieldName = fieldName == null || fieldName.trim().length() == 0 ? "FIELD_" + text.getUUID() : fieldName;
2680
2681 String value = null;
2682 if (text.getPropertiesMap().containsProperty(PDF_FIELD_VALUE))
2683 {
2684 value = text.getPropertiesMap().getProperty(PDF_FIELD_VALUE);
2685 }
2686 else
2687 {
2688 value = text.getFullText();
2689 }
2690
2691 int llx = text.getX() + exporterContext.getOffsetX();
2692 int lly = jasperPrint.getPageHeight() - text.getY() - exporterContext.getOffsetY();
2693 int urx = llx + text.getWidth();
2694 int ury = jasperPrint.getPageHeight() - text.getY() - exporterContext.getOffsetY() - text.getHeight();
2695
2696 PdfTextField pdfTextField;
2697 switch (fieldType)
2698 {
2699 case TEXT:
2700 pdfTextField = pdfProducer.createTextField(llx, lly, urx, ury, fieldName);
2701 if (value != null)
2702 {
2703 pdfTextField.setText(value);
2704 }
2705 break;
2706 case COMBO:
2707 String[] comboChoices = getPdfFieldChoices(text);
2708 pdfTextField = pdfProducer.createComboField(llx, lly, urx, ury, fieldName, value, comboChoices);
2709 if (propertiesUtil.getBooleanProperty(PDF_FIELD_COMBO_EDIT, false, text, jasperPrint))
2710 {
2711 pdfTextField.setEdit();
2712 }
2713 break;
2714 case LIST:
2715 String[] listChoices = getPdfFieldChoices(text);
2716 pdfTextField = pdfProducer.createListField(llx, lly, urx, ury, fieldName, value, listChoices);
2717 break;
2718 default:
2719 throw new JRRuntimeException("Unknown field type " + fieldType);
2720 }
2721
2722 if (ModeEnum.OPAQUE == text.getModeValue())
2723 {
2724 pdfTextField.setBackgroundColor(text.getBackcolor());
2725 }
2726 pdfTextField.setTextColor(text.getForecolor());
2727
2728 switch (text.getHorizontalTextAlign())
2729 {
2730 case RIGHT :
2731 pdfTextField.setAlignment(PdfTextAlignment.RIGHT);
2732 break;
2733 case CENTER :
2734 pdfTextField.setAlignment(PdfTextAlignment.CENTER);
2735 break;
2736 case JUSTIFIED :
2737 pdfTextField.setAlignment(PdfTextAlignment.JUSTIFIED);
2738 break;
2739 case LEFT :
2740 default :
2741 pdfTextField.setAlignment(PdfTextAlignment.LEFT);
2742 }
2743
2744 JRPen pen = getFieldPen(text);
2745 if (pen != null)
2746 {
2747 float borderWidth = Math.round(pen.getLineWidth());
2748 if (borderWidth > 0)
2749 {
2750 pdfTextField.setBorderColor(pen.getLineColor());
2751 pdfTextField.setBorderWidth(borderWidth);
2752 String strBorderStyle = propertiesUtil.getProperty(PDF_FIELD_BORDER_STYLE, text, jasperPrint);
2753 PdfFieldBorderStyleEnum borderStyle = PdfFieldBorderStyleEnum.getByName(strBorderStyle);
2754 if (borderStyle == null)
2755 {
2756 borderStyle = pen.getLineStyleValue() == LineStyleEnum.DASHED ? PdfFieldBorderStyleEnum.DASHED : PdfFieldBorderStyleEnum.SOLID;
2757 }
2758 pdfTextField.setBorderStyle(borderStyle);
2759 }
2760 }
2761
2762 String readOnly = text.getPropertiesMap().getProperty(PDF_FIELD_READ_ONLY);
2763 if (readOnly != null)
2764 {
2765 if (Boolean.valueOf(readOnly))
2766 {
2767 pdfTextField.setReadOnly();
2768 }
2769 }
2770
2771
2772
2773 Map<Attribute,Object> attributes = new HashMap<Attribute,Object>();
2774 fontUtil.getAttributesWithoutAwtFont(attributes, text);
2775 pdfTextField.setFont(attributes, getLocale());
2776 pdfTextField.setFontSize(text.getFontsize());
2777
2778
2779 boolean isMultiLine = JRPropertiesUtil.asBoolean(text.getPropertiesMap().getProperty(PDF_FIELD_TEXT_MULTILINE), false);
2780 if (isMultiLine)
2781 {
2782 pdfTextField.setMultiline();
2783 }
2784
2785 if (pageFormat.getOrientation() == OrientationEnum.LANDSCAPE)
2786 {
2787 pdfTextField.setRotation(90);
2788 }
2789 pdfTextField.setVisible();
2790
2791 pdfTextField.add();
2792 }
2793
2794 protected String[] getPdfFieldChoices(JRPrintText text)
2795 {
2796 String[] choices = null;
2797 String strChoices = text.getPropertiesMap().getProperty(PDF_FIELD_CHOICES);
2798 if (strChoices != null && strChoices.trim().length() > 0)
2799 {
2800 String choiceSeparators = propertiesUtil.getProperty(PDF_FIELD_CHOICE_SEPARATORS, text, jasperPrint);
2801 StringTokenizer tkzer = new StringTokenizer(strChoices, choiceSeparators);
2802 List<String> choicesList = new ArrayList<String>();
2803 while (tkzer.hasMoreTokens())
2804 {
2805 choicesList.add(tkzer.nextToken());
2806 }
2807 choices = choicesList.toArray(new String[choicesList.size()]);
2808 }
2809 return choices;
2810 }
2811
2812
2815 public void exportFieldCheck(JRPrintElement element)
2816 {
2817 String fieldName = element.getPropertiesMap().getProperty(PDF_FIELD_NAME);
2818 fieldName = fieldName == null || fieldName.trim().length() == 0 ? "FIELD_" + element.getUUID() : fieldName;
2819
2820 PdfRadioCheck checkField = pdfProducer.createCheckField(
2821 element.getX() + exporterContext.getOffsetX(),
2822 jasperPrint.getPageHeight() - element.getY() - exporterContext.getOffsetY(),
2823 element.getX() + exporterContext.getOffsetX() + element.getWidth(),
2824 jasperPrint.getPageHeight() - element.getY() - exporterContext.getOffsetY() - element.getHeight(),
2825 fieldName,
2826 "checked"
2827 );
2828
2829 PdfFieldCheckTypeEnum checkType = PdfFieldCheckTypeEnum.getByName(element.getPropertiesMap().getProperty(PDF_FIELD_CHECK_TYPE));
2830 if (checkType != null)
2831 {
2832 checkField.setCheckType(checkType);
2833 }
2834
2835 if (ModeEnum.OPAQUE == element.getModeValue())
2836 {
2837 checkField.setBackgroundColor(element.getBackcolor());
2838 }
2839 checkField.setTextColor(element.getForecolor());
2840
2841 JRPen pen = getFieldPen(element);
2842 if (pen != null)
2843 {
2844 float borderWidth = Math.round(pen.getLineWidth());
2845 if (borderWidth > 0)
2846 {
2847 checkField.setBorderColor(pen.getLineColor());
2848 checkField.setBorderWidth(borderWidth);
2849 String strBorderStyle = propertiesUtil.getProperty(PDF_FIELD_BORDER_STYLE, element, jasperPrint);
2850 PdfFieldBorderStyleEnum borderStyle = PdfFieldBorderStyleEnum.getByName(strBorderStyle);
2851 if (borderStyle == null)
2852 {
2853 borderStyle = pen.getLineStyleValue() == LineStyleEnum.DASHED ? PdfFieldBorderStyleEnum.DASHED : PdfFieldBorderStyleEnum.SOLID;
2854 }
2855 checkField.setBorderStyle(borderStyle);
2856 }
2857 }
2858
2859 String checked = element.getPropertiesMap().getProperty(PDF_FIELD_CHECKED);
2860 if (checked != null)
2861 {
2862 checkField.setChecked(Boolean.valueOf(checked));
2863 }
2864
2865 String readOnly = element.getPropertiesMap().getProperty(PDF_FIELD_READ_ONLY);
2866 if (readOnly != null)
2867 {
2868 if (Boolean.valueOf(readOnly))
2869 {
2870 checkField.setReadOnly();
2871 }
2872 }
2873
2874 checkField.add();
2875 }
2876
2877
2880 public void exportFieldRadio(JRPrintElement element) throws IOException
2881 {
2882 String fieldName = element.getPropertiesMap().getProperty(PDF_FIELD_NAME);
2883 fieldName = fieldName == null || fieldName.trim().length() == 0 ? "FIELD_" + element.getUUID() : fieldName;
2884
2885 PdfRadioCheck radioField = pdfProducer.getRadioField(
2886 element.getX() + exporterContext.getOffsetX(),
2887 jasperPrint.getPageHeight() - element.getY() - exporterContext.getOffsetY(),
2888 element.getX() + exporterContext.getOffsetX() + element.getWidth(),
2889 jasperPrint.getPageHeight() - element.getY() - exporterContext.getOffsetY() - element.getHeight(),
2890 fieldName,
2891 "FIELD_" + element.getUUID());
2892
2893 PdfFieldCheckTypeEnum checkType = PdfFieldCheckTypeEnum.getByName(element.getPropertiesMap().getProperty(PDF_FIELD_CHECK_TYPE));
2894 if (checkType != null)
2895 {
2896 radioField.setCheckType(checkType);
2897 }
2898
2899 if (ModeEnum.OPAQUE == element.getModeValue())
2900 {
2901 radioField.setBackgroundColor(element.getBackcolor());
2902 }
2903 radioField.setTextColor(element.getForecolor());
2904
2905 JRPen pen = getFieldPen(element);
2906 if (pen != null)
2907 {
2908 float borderWidth = Math.round(pen.getLineWidth());
2909 if (borderWidth > 0)
2910 {
2911 radioField.setBorderColor(pen.getLineColor());
2912 radioField.setBorderWidth(borderWidth);
2913 String strBorderStyle = propertiesUtil.getProperty(PDF_FIELD_BORDER_STYLE, element, jasperPrint);
2914 PdfFieldBorderStyleEnum borderStyle = PdfFieldBorderStyleEnum.getByName(strBorderStyle);
2915 if (borderStyle == null)
2916 {
2917 borderStyle = pen.getLineStyleValue() == LineStyleEnum.DASHED ? PdfFieldBorderStyleEnum.DASHED : PdfFieldBorderStyleEnum.SOLID;
2918 }
2919 radioField.setBorderStyle(borderStyle);
2920 }
2921 }
2922
2923 radioField.setOnValue("FIELD_" + element.getUUID());
2924
2925 String checked = element.getPropertiesMap().getProperty(PDF_FIELD_CHECKED);
2926 radioField.setChecked(Boolean.valueOf(checked));
2927
2928
2929 String readOnly = element.getPropertiesMap().getProperty(PDF_FIELD_READ_ONLY);
2930 if (readOnly != null)
2931 {
2932 if (Boolean.valueOf(readOnly))
2933 {
2934 radioField.setReadOnly();
2935 }
2936 }
2937
2938 radioField.addToGroup();
2939 }
2940
2941 protected JRPen getFieldPen(JRPrintElement element)
2942 {
2943 JRPen pen = null;
2944
2945 JRLineBox box = element instanceof JRBoxContainer ? ((JRBoxContainer)element).getLineBox() : null;
2946
2947 if (box == null)
2948 {
2949 pen = element instanceof JRCommonGraphicElement ? ((JRCommonGraphicElement)element).getLinePen() : null;
2950 }
2951 else
2952 {
2953 Float lineWidth = box.getPen().getLineWidth();
2954 if (lineWidth == 0)
2955 {
2956
2957
2958 if(
2959 ((JRBasePen)box.getTopPen()).isIdentical(box.getLeftPen())
2960 && ((JRBasePen)box.getTopPen()).isIdentical(box.getBottomPen())
2961 && ((JRBasePen)box.getTopPen()).isIdentical(box.getRightPen())
2962 && box.getTopPen().getLineWidth() > 0
2963 )
2964 {
2965 pen = new JRBasePen(box);
2966 pen.setLineWidth(box.getTopPen().getLineWidth());
2967 pen.setLineColor(box.getTopPen().getLineColor());
2968 pen.setLineStyle(box.getTopPen().getLineStyleValue());
2969 }
2970 }
2971 else
2972 {
2973 pen = new JRBasePen(box);
2974 pen.setLineWidth(lineWidth);
2975 pen.setLineColor(box.getPen().getLineColor());
2976 pen.setLineStyle(box.getPen().getLineStyleValue());
2977 }
2978 }
2979
2980 return pen;
2981 }
2982
2983 protected AbstractPdfTextRenderer getTextRenderer(JRPrintText text, JRStyledText styledText)
2984 {
2985 Locale textLocale = getTextLocale(text);
2986 AbstractPdfTextRenderer textRenderer = pdfProducer.getTextRenderer(
2987 text, styledText, textLocale,
2988 awtIgnoreMissingFont, defaultIndentFirstLine, defaultJustifyLastLine);
2989 return textRenderer;
2990 }
2991
2992
2993
2996 protected void exportBox(JRLineBox box, JRPrintElement element)
2997 {
2998 exportTopPen(box.getTopPen(), box.getLeftPen(), box.getRightPen(), element);
2999 exportLeftPen(box.getTopPen(), box.getLeftPen(), box.getBottomPen(), element);
3000 exportBottomPen(box.getLeftPen(), box.getBottomPen(), box.getRightPen(), element);
3001 exportRightPen(box.getTopPen(), box.getBottomPen(), box.getRightPen(), element);
3002
3003 pdfContent.setLineDash(0f);
3004 pdfContent.setLineCap(LineCapStyle.PROJECTING_SQUARE);
3005 }
3006
3007
3008
3011 protected void exportPen(JRPen pen, JRPrintElement element)
3012 {
3013 exportTopPen(pen, pen, pen, element);
3014 exportLeftPen(pen, pen, pen, element);
3015 exportBottomPen(pen, pen, pen, element);
3016 exportRightPen(pen, pen, pen, element);
3017
3018 pdfContent.setLineDash(0f);
3019 pdfContent.setLineCap(LineCapStyle.PROJECTING_SQUARE);
3020 }
3021
3022
3023
3026 protected void exportTopPen(
3027 JRPen topPen,
3028 JRPen leftPen,
3029 JRPen rightPen,
3030 JRPrintElement element)
3031 {
3032 if (topPen.getLineWidth() > 0f)
3033 {
3034 float leftOffset = leftPen.getLineWidth() / 2;
3035 float rightOffset = rightPen.getLineWidth() / 2;
3036 int lcOffsetX = getOffsetX();
3037 int lcOffsetY = getOffsetY();
3038
3039 preparePen(topPen, LineCapStyle.BUTT);
3040
3041 if (topPen.getLineStyleValue() == LineStyleEnum.DOUBLE)
3042 {
3043 float topOffset = topPen.getLineWidth();
3044
3045 pdfContent.strokeLine(
3046 element.getX() + lcOffsetX - leftOffset,
3047 pageFormat.getPageHeight() - element.getY() - lcOffsetY + topOffset / 3,
3048 element.getX() + lcOffsetX + element.getWidth() + rightOffset,
3049 pageFormat.getPageHeight() - element.getY() - lcOffsetY + topOffset / 3
3050 );
3051
3052 pdfContent.strokeLine(
3053 element.getX() + lcOffsetX + leftOffset / 3,
3054 pageFormat.getPageHeight() - element.getY() - lcOffsetY - topOffset / 3,
3055 element.getX() + lcOffsetX + element.getWidth() - rightOffset / 3,
3056 pageFormat.getPageHeight() - element.getY() - lcOffsetY - topOffset / 3
3057 );
3058 }
3059 else
3060 {
3061 pdfContent.strokeLine(
3062 element.getX() + lcOffsetX - leftOffset,
3063 pageFormat.getPageHeight() - element.getY() - lcOffsetY,
3064 element.getX() + lcOffsetX + element.getWidth() + rightOffset,
3065 pageFormat.getPageHeight() - element.getY() - lcOffsetY
3066 );
3067 }
3068
3069 resetPen();
3070 }
3071 }
3072
3073
3074
3077 protected void exportLeftPen(JRPen topPen, JRPen leftPen, JRPen bottomPen, JRPrintElement element)
3078 {
3079 if (leftPen.getLineWidth() > 0f)
3080 {
3081 float topOffset = topPen.getLineWidth() / 2;
3082 float bottomOffset = bottomPen.getLineWidth() / 2;
3083 int lcOffsetX = getOffsetX();
3084 int lcOffsetY = getOffsetY();
3085
3086 preparePen(leftPen, LineCapStyle.BUTT);
3087
3088 if (leftPen.getLineStyleValue() == LineStyleEnum.DOUBLE)
3089 {
3090 float leftOffset = leftPen.getLineWidth();
3091
3092 pdfContent.strokeLine(
3093 element.getX() + lcOffsetX - leftOffset / 3,
3094 pageFormat.getPageHeight() - element.getY() - lcOffsetY + topOffset,
3095 element.getX() + lcOffsetX - leftOffset / 3,
3096 pageFormat.getPageHeight() - element.getY() - lcOffsetY - element.getHeight() - bottomOffset
3097 );
3098
3099 pdfContent.strokeLine(
3100 element.getX() + lcOffsetX + leftOffset / 3,
3101 pageFormat.getPageHeight() - element.getY() - lcOffsetY - topOffset / 3,
3102 element.getX() + lcOffsetX + leftOffset / 3,
3103 pageFormat.getPageHeight() - element.getY() - lcOffsetY - element.getHeight() + bottomOffset / 3
3104 );
3105 }
3106 else
3107 {
3108 pdfContent.strokeLine(
3109 element.getX() + lcOffsetX,
3110 pageFormat.getPageHeight() - element.getY() - lcOffsetY + topOffset,
3111 element.getX() + lcOffsetX,
3112 pageFormat.getPageHeight() - element.getY() - lcOffsetY - element.getHeight() - bottomOffset
3113 );
3114 }
3115
3116 resetPen();
3117 }
3118 }
3119
3120
3121
3124 protected void exportBottomPen(JRPen leftPen, JRPen bottomPen, JRPen rightPen, JRPrintElement element)
3125 {
3126 if (bottomPen.getLineWidth() > 0f)
3127 {
3128 float leftOffset = leftPen.getLineWidth() / 2;
3129 float rightOffset = rightPen.getLineWidth() / 2;
3130 int lcOffsetX = getOffsetX();
3131 int lcOffsetY = getOffsetY();
3132
3133 preparePen(bottomPen, LineCapStyle.BUTT);
3134
3135 if (bottomPen.getLineStyleValue() == LineStyleEnum.DOUBLE)
3136 {
3137 float bottomOffset = bottomPen.getLineWidth();
3138
3139 pdfContent.strokeLine(
3140 element.getX() + lcOffsetX - leftOffset,
3141 pageFormat.getPageHeight() - element.getY() - lcOffsetY - element.getHeight() - bottomOffset / 3,
3142 element.getX() + lcOffsetX + element.getWidth() + rightOffset,
3143 pageFormat.getPageHeight() - element.getY() - lcOffsetY - element.getHeight() - bottomOffset / 3
3144 );
3145
3146 pdfContent.strokeLine(
3147 element.getX() + lcOffsetX + leftOffset / 3,
3148 pageFormat.getPageHeight() - element.getY() - lcOffsetY - element.getHeight() + bottomOffset / 3,
3149 element.getX() + lcOffsetX + element.getWidth() - rightOffset / 3,
3150 pageFormat.getPageHeight() - element.getY() - lcOffsetY - element.getHeight() + bottomOffset / 3
3151 );
3152 }
3153 else
3154 {
3155 pdfContent.strokeLine(
3156 element.getX() + lcOffsetX - leftOffset,
3157 pageFormat.getPageHeight() - element.getY() - lcOffsetY - element.getHeight(),
3158 element.getX() + lcOffsetX + element.getWidth() + rightOffset,
3159 pageFormat.getPageHeight() - element.getY() - lcOffsetY - element.getHeight()
3160 );
3161 }
3162
3163 resetPen();
3164 }
3165 }
3166
3167
3168
3171 protected void exportRightPen(JRPen topPen, JRPen bottomPen, JRPen rightPen, JRPrintElement element)
3172 {
3173 if (rightPen.getLineWidth() > 0f)
3174 {
3175 float topOffset = topPen.getLineWidth() / 2;
3176 float bottomOffset = bottomPen.getLineWidth() / 2;
3177 int lcOffsetX = getOffsetX();
3178 int lcOffsetY = getOffsetY();
3179
3180 preparePen(rightPen, LineCapStyle.BUTT);
3181
3182 if (rightPen.getLineStyleValue() == LineStyleEnum.DOUBLE)
3183 {
3184 float rightOffset = rightPen.getLineWidth();
3185
3186 pdfContent.strokeLine(
3187 element.getX() + lcOffsetX + element.getWidth() + rightOffset / 3,
3188 pageFormat.getPageHeight() - element.getY() - lcOffsetY + topOffset,
3189 element.getX() + lcOffsetX + element.getWidth() + rightOffset / 3,
3190 pageFormat.getPageHeight() - element.getY() - lcOffsetY - element.getHeight() - bottomOffset
3191 );
3192
3193 pdfContent.strokeLine(
3194 element.getX() + lcOffsetX + element.getWidth() - rightOffset / 3,
3195 pageFormat.getPageHeight() - element.getY() - lcOffsetY - topOffset / 3,
3196 element.getX() + lcOffsetX + element.getWidth() - rightOffset / 3,
3197 pageFormat.getPageHeight() - element.getY() - lcOffsetY - element.getHeight() + bottomOffset / 3
3198 );
3199 }
3200 else
3201 {
3202 pdfContent.strokeLine(
3203 element.getX() + lcOffsetX + element.getWidth(),
3204 pageFormat.getPageHeight() - element.getY() - lcOffsetY + topOffset,
3205 element.getX() + lcOffsetX + element.getWidth(),
3206 pageFormat.getPageHeight() - element.getY() - lcOffsetY - element.getHeight() - bottomOffset
3207 );
3208 }
3209
3210 resetPen();
3211 }
3212 }
3213
3214
3215
3218 private void preparePen(JRPen pen, LineCapStyle lineCap)
3219 {
3220 float lineWidth = pen.getLineWidth();
3221
3222 if (lineWidth <= 0)
3223 {
3224 return;
3225 }
3226
3227 PdfContent pdfContent = pdfProducer.getPdfContent();
3228 pdfContent.setLineWidth(lineWidth);
3229 pdfContent.setLineCap(lineCap);
3230
3231 Color color = pen.getLineColor();
3232 pdfContent.setStrokeColor(color);
3233
3234 switch (pen.getLineStyleValue())
3235 {
3236 case DOUBLE :
3237 {
3238 pdfContent.setLineWidth(lineWidth / 3);
3239 pdfContent.setLineDash(0f);
3240 break;
3241 }
3242 case DOTTED :
3243 {
3244 switch (lineCap)
3245 {
3246 case BUTT :
3247 {
3248 pdfContent.setLineDash(lineWidth, lineWidth, 0f);
3249 break;
3250 }
3251 case PROJECTING_SQUARE :
3252 {
3253 pdfContent.setLineDash(0, 2 * lineWidth, 0f);
3254 break;
3255 }
3256 }
3257 break;
3258 }
3259 case DASHED :
3260 {
3261 switch (lineCap)
3262 {
3263 case BUTT :
3264 {
3265 pdfContent.setLineDash(5 * lineWidth, 3 * lineWidth, 0f);
3266 break;
3267 }
3268 case PROJECTING_SQUARE :
3269 {
3270 pdfContent.setLineDash(4 * lineWidth, 4 * lineWidth, 0f);
3271 break;
3272 }
3273 }
3274 break;
3275 }
3276 case SOLID :
3277 default :
3278 {
3279 pdfContent.setLineDash(0f);
3280 break;
3281 }
3282 }
3283 }
3284
3285 private void resetPen()
3286 {
3287 pdfContent.resetStrokeColor();
3288 }
3289
3290 protected static synchronized void registerFonts ()
3291 {
3292
3293 if (!fontsRegistered)
3294 {
3295 List<PropertySuffix> fontFiles = JRPropertiesUtil.getInstance(DefaultJasperReportsContext.getInstance()).getProperties(PDF_FONT_FILES_PREFIX);
3296 if (!fontFiles.isEmpty())
3297 {
3298 for (Iterator<PropertySuffix> i = fontFiles.iterator(); i.hasNext();)
3299 {
3300 JRPropertiesUtil.PropertySuffix font = i.next();
3301 String file = font.getValue();
3302 if (file.toLowerCase().endsWith(".ttc"))
3303 {
3304 FontFactory.register(file);
3305 }
3306 else
3307 {
3308 String alias = font.getSuffix();
3309 FontFactory.register(file, alias);
3310 }
3311 }
3312 }
3313
3314 List<PropertySuffix> fontDirs = JRPropertiesUtil.getInstance(DefaultJasperReportsContext.getInstance()).getProperties(PDF_FONT_DIRS_PREFIX);
3315 if (!fontDirs.isEmpty())
3316 {
3317 for (Iterator<PropertySuffix> i = fontDirs.iterator(); i.hasNext();)
3318 {
3319 JRPropertiesUtil.PropertySuffix dir = i.next();
3320 FontFactory.registerDirectory(dir.getValue());
3321 }
3322 }
3323
3324 fontsRegistered = true;
3325 }
3326 }
3327
3328
3329 static protected class Bookmark
3330 {
3331 final PdfOutlineEntry pdfOutline;
3332 final int level;
3333
3334 Bookmark(Bookmark parent, int x, int top, String title)
3335 {
3336 this.pdfOutline = parent.pdfOutline.createChild(title, x, top);
3337 this.level = parent.level + 1;
3338 }
3339
3340 Bookmark(Bookmark parent, String title)
3341 {
3342 this.pdfOutline = parent.pdfOutline.createChild(title);
3343 this.level = parent.level + 1;
3344 }
3345
3346 Bookmark(PdfOutlineEntry pdfOutline, int level)
3347 {
3348 this.pdfOutline = pdfOutline;
3349 this.level = level;
3350 }
3351 }
3352
3353 static protected class BookmarkStack
3354 {
3355 LinkedList<Bookmark> stack;
3356
3357 BookmarkStack()
3358 {
3359 stack = new LinkedList<Bookmark>();
3360 }
3361
3362 void push(Bookmark bookmark)
3363 {
3364 stack.add(bookmark);
3365 }
3366
3367 Bookmark pop()
3368 {
3369 return stack.removeLast();
3370 }
3371
3372 Bookmark peek()
3373 {
3374 return stack.getLast();
3375 }
3376 }
3377
3378
3379 protected void initBookmarks(List<ExporterInputItem> items)
3380 {
3381 bookmarkStack = new BookmarkStack();
3382
3383 int rootLevel = items.size() > 1 && getCurrentConfiguration().isCreatingBatchModeBookmarks() ? -1 : 0;
3384 Bookmark bookmark = new Bookmark(pdfProducer.getRootOutline(), rootLevel);
3385 bookmarkStack.push(bookmark);
3386 }
3387
3388
3389 protected void addBookmark(int level, String title, int x, int y)
3390 {
3391 Bookmark parent = bookmarkStack.peek();
3392
3393 while(parent.level >= level)
3394 {
3395 bookmarkStack.pop();
3396 parent = bookmarkStack.peek();
3397 }
3398
3399 if (!getCurrentItemConfiguration().isCollapseMissingBookmarkLevels())
3400 {
3401
3402 for (int i = parent.level + 1; i < level; ++i)
3403 {
3404 Bookmark emptyBookmark = new Bookmark(parent, EMPTY_BOOKMARK_TITLE);
3405 bookmarkStack.push(emptyBookmark);
3406 parent = emptyBookmark;
3407 }
3408 }
3409 int height = OrientationEnum.PORTRAIT.equals(pageFormat.getOrientation())
3410 ? pageFormat.getPageHeight() - y
3411 : y;
3412 Bookmark bookmark = new Bookmark(parent, x, height, title);
3413 bookmarkStack.push(bookmark);
3414 }
3415
3416
3417 protected void setAnchor(PdfChunk chunk, JRPrintAnchor anchor, JRPrintElement element)
3418 {
3419 String anchorName = anchor.getAnchorName();
3420 if (anchorName != null)
3421 {
3422 chunk.setLocalDestination(anchorName);
3423
3424 if (anchor.getBookmarkLevel() != JRAnchor.NO_BOOKMARK)
3425 {
3426 int x = OrientationEnum.PORTRAIT.equals(pageFormat.getOrientation())
3427 ? getOffsetX() + element.getX()
3428 : getOffsetY() + element.getY();
3429 int y = OrientationEnum.PORTRAIT.equals(pageFormat.getOrientation())
3430 ? getOffsetY() + element.getY()
3431 : getOffsetX() + element.getX();
3432 addBookmark(anchor.getBookmarkLevel(), anchor.getAnchorName(), x, y);
3433 }
3434 }
3435 }
3436
3437
3438 public void exportFrame(JRPrintFrame frame) throws IOException, JRException
3439 {
3440 if (frame.getModeValue() == ModeEnum.OPAQUE)
3441 {
3442 int x = frame.getX() + getOffsetX();
3443 int y = frame.getY() + getOffsetY();
3444
3445 Color backcolor = frame.getBackcolor();
3446
3447 PdfContent pdfContent = pdfProducer.getPdfContent();
3448 pdfContent.setFillColor(backcolor);
3449 pdfContent.fillRectangle(
3450 x,
3451 pageFormat.getPageHeight() - y,
3452 frame.getWidth(),
3453 - frame.getHeight()
3454 );
3455 pdfContent.resetFillColor();
3456 }
3457
3458 setFrameElementsOffset(frame, false);
3459 try
3460 {
3461 exportElements(frame.getElements());
3462 }
3463 finally
3464 {
3465 restoreElementOffsets();
3466 }
3467
3468 exportBox(frame.getLineBox(), frame);
3469 }
3470
3471
3472
3475 protected PrintPageFormat getCurrentPageFormat()
3476 {
3477 return pageFormat;
3478 }
3479
3480
3481 @Override
3482 protected int getOffsetX()
3483 {
3484 return
3485 super.getOffsetX()
3486 + (insideFrame() ? 0 : (crtDocumentPageNumber % 2 == 0
3487 ? crtEvenPageOffsetX
3488 : crtOddPageOffsetX));
3489 }
3490
3491
3492 @Override
3493 protected int getOffsetY()
3494 {
3495 return
3496 super.getOffsetY()
3497 + (insideFrame() ? 0 : (crtDocumentPageNumber % 2 == 0
3498 ? crtEvenPageOffsetY
3499 : crtOddPageOffsetY));
3500 }
3501
3502
3503
3506 protected void exportGenericElement(JRGenericPrintElement element)
3507 {
3508 GenericElementPdfHandler handler = (GenericElementPdfHandler)
3509 GenericElementHandlerEnviroment.getInstance(getJasperReportsContext()).getElementHandler(
3510 element.getGenericType(), PDF_EXPORTER_KEY);
3511
3512 if (handler != null)
3513 {
3514 handler.exportElement(exporterContext, element);
3515 }
3516 else
3517 {
3518 if (log.isDebugEnabled())
3519 {
3520 log.debug("No PDF generic element handler for "
3521 + element.getGenericType());
3522 }
3523 }
3524 }
3525
3526
3527 @Override
3528 public String getExporterKey()
3529 {
3530 return PDF_EXPORTER_KEY;
3531 }
3532
3533
3534 @Override
3535 public String getExporterPropertiesPrefix()
3536 {
3537 return PDF_EXPORTER_PROPERTIES_PREFIX;
3538 }
3539
3540 public static int getIntegerPermissions(String permissions) {
3541 int permission = 0;
3542 if(permissions != null && permissions.length() > 0) {
3543 String[] perms = permissions.split("\\|");
3544 for(String perm : perms) {
3545 if(PdfPermissionsEnum.ALL.equals(PdfPermissionsEnum.getByName(perm))) {
3546 permission = PdfExporterConfiguration.ALL_PERMISSIONS;
3547 break;
3548 }
3549 if(perm != null && perm.length()>0) {
3550 permission |= PdfPermissionsEnum.getByName(perm).getPdfPermission();
3551 }
3552 }
3553 }
3554 return permission;
3555 }
3556 }
3557