You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PDFRenderer.java 71KB

Fop.java gets two new constructors: Fop(String) and Fop(String, FOUserAgent) where the String is the MIME type for the desired output format. MimeConstants provides a comprehensive list of MIME types used in Fop.java. Non-standard, FOP-specific MIME types changed to a uniform pattern: application/X-fop-awt-preview, application/X-fop-print and application/X-fop-areatree. RendererFactory now supports manual registration and dynamic discovery of Renderers and FOEventHandlers by their MIME types. Instantitation is done using MIME types everywhere. The RENDER_* constants are mapped to MIME types in Fop.java. RendererFactory is now an instantiable class whose reference is held by FOUserAgent just like it is done for the XLMHandlers. Renderers and FOEventHandlers now each have a *Maker class which is a kind of factory class which is used to register a Renderer/FOEventHandler and additionally serves to provide additional information about the thing, such as the MIME types it supports and if the implementation requires an OutputStream. The command-line gets a new option: -out application/pdf myfile.pdf is the generic way to create an output file. If someone created a WordML output handler and provided the right service resource file he could specify "-out text/xml+msword out.xml". ".out list" lists all MIME types that are available for output. Renderers can now potionally expose a Graphics2DAdapter which in concert with Graphics2DImagePainter can be used by FOP extensions to paint their content directly using a Graphics2D instance. That makes it possible to avoid a detour via SVG/Batik in certain cases. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@332549 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Initial support for XMP metadata (PDF 1.4) under fo:declarations. Both xmpmeta and RDF elements can be used as root elements for XMP metadata. Extracted DOM2SAX functionality from XMLXMLHandler into utility class since it is now reused elsewhere. New DOMBuilderContentHandlerFactory is used to create ContentHandlers that build generic DOMs. New DelegatingContentHandler is a convenience base class modelled after XMLFilterImpl but as passive SAX receiver. It is used by DOMBuilderContentHandlerFactory. Refactored FOTreeBuilder. FO tree building is now in a special ContentHandler which can be replaced temporarily when handling foreign XML like SVG or XMP. Extension Elements wanting the set their own ContentHandlers (instead of using the standard FO tree building mechanism) return a non-null value in getContentHandlerFactory(). The old mechanism is still supported (MathML, Plan and Barcode4J still use that). However, SVG support is changed to use a ContentHandlerFactory. Extension elements for xmpmeta and RDF elements making use of the new DOM build-up using ContentHandlerFactory. XMP metadata is passed to the renderer as ExtensionAttachment to the document. Only PDFRenderer uses the XMP extension attachment at this time. The PDFRenderer automatically builds XMP metadata based on the basic metadata information in the PDFInfo object if no explicit XMP metadata has been added to the XSL-FO document. XMP metadata merging is not implemented because this would involve a more sophisticated XMP infrastructure. That also means that XMP metadata is not validated. It's passed into the PDF as is. The PDF library now provides the PDFMetadata class to embed XMP metadata in PDFs version >=1.4. stream contents use a special filter list which is initially empty, so non-PDF-aware XMP readers can extract (and optionally modify) the XMP metadata. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@378482 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Merged revisions 607034-611115 via svnmerge from https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk ........ r607036 | jeremias | 2007-12-27 11:51:11 +0100 (Do, 27 Dez 2007) | 1 line Don't just exit with no error message if the document contains no content. Pretty irritating if it does so. ........ r608812 | acumiskey | 2008-01-04 13:14:33 +0100 (Fr, 04 Jan 2008) | 3 lines The fonts variable would have always had an empty Configuration node (non-null value) even if a <fonts/> wasn't present in the fop configuration. ........ r609567 | jeremias | 2008-01-07 11:52:09 +0100 (Mo, 07 Jan 2008) | 4 lines Reenabled documentation for fox:destination. Enabled intermediate format functionality for fox:destination. Added a test case to check fox:destination. Deprecated FOP's XMLizable in favor of the XML Graphics Commons variant (and extend that variant). ........ r609627 | jeremias | 2008-01-07 16:06:24 +0100 (Mo, 07 Jan 2008) | 5 lines Bugzilla #44176: Support for custom fonts in Java2DRenderer and derived renderers. Submitted by: Patrick Jaromin <patrick.at.jgsullivan.dot.com> Patch modified slightly by jeremias. ........ r610020 | acumiskey | 2008-01-08 16:27:02 +0100 (Di, 08 Jan 2008) | 2 lines cleaned up ........ r610021 | acumiskey | 2008-01-08 16:28:56 +0100 (Di, 08 Jan 2008) | 2 lines Appears to be unused/referenced and superceeded by PageGroup ........ r610022 | acumiskey | 2008-01-08 16:34:07 +0100 (Di, 08 Jan 2008) | 2 lines cleaned up ........ r610023 | acumiskey | 2008-01-08 16:35:18 +0100 (Di, 08 Jan 2008) | 2 lines fixed javadoc ........ r610337 | vhennebert | 2008-01-09 12:02:08 +0100 (Mi, 09 Jan 2008) | 2 lines Fixed checkstyle issues: tabs and trailing spaces ........ r610355 | vhennebert | 2008-01-09 13:01:21 +0100 (Mi, 09 Jan 2008) | 2 lines keep-together is an inherited property ........ r610420 | acumiskey | 2008-01-09 16:40:25 +0100 (Mi, 09 Jan 2008) | 2 lines cleanup ........ r610704 | jeremias | 2008-01-10 08:38:47 +0100 (Do, 10 Jan 2008) | 1 line Added basic support for PDF page labels. ........ r610739 | jeremias | 2008-01-10 11:13:21 +0100 (Do, 10 Jan 2008) | 1 line PostScript output now generates the bounding box DSC comments for the whole document. ........ r610821 | vhennebert | 2008-01-10 16:53:20 +0100 (Do, 10 Jan 2008) | 4 lines - renamed variables for clarity - moved the computation of a cell's content length in PrimaryGridUnit - better javadoc for getHeight method in EffRow ........ r610848 | vhennebert | 2008-01-10 18:41:52 +0100 (Do, 10 Jan 2008) | 2 lines No need to check if the end of the cell is reached when creating the areas for a row ........ r610853 | vhennebert | 2008-01-10 18:54:16 +0100 (Do, 10 Jan 2008) | 2 lines Simplified addAreasAndFlushRow ........ r610886 | vhennebert | 2008-01-10 20:23:56 +0100 (Do, 10 Jan 2008) | 2 lines Removed endPart() method and moved its content into addAreasAndFlushRow() ........ r610891 | vhennebert | 2008-01-10 20:34:13 +0100 (Do, 10 Jan 2008) | 2 lines Removed accumulatedBPD which is redundant with yoffset ........ r610893 | vhennebert | 2008-01-10 20:35:24 +0100 (Do, 10 Jan 2008) | 2 lines The return value of addAreasAndFlushRow is never used, changed it to void ........ r610905 | vhennebert | 2008-01-10 20:57:29 +0100 (Do, 10 Jan 2008) | 2 lines Renamed lastRow into currentRow and yoffset into currentRowOffset ........ r611114 | jeremias | 2008-01-11 10:04:28 +0100 (Fr, 11 Jan 2008) | 2 lines Bugfix: Some string objects were not encrypted (for example in named destinations) I had to refactor the PDF library a little bit but since it only affects the inner API it shouldn't be a problem that I removed some methods which caused trouble because a didn't think about encryption when I worked on the PDF library last year. ........ git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ImagePackageRedesign@611120 13f79535-47bb-0310-9956-ffa450edef68
16 years ago
Initial support for XMP metadata (PDF 1.4) under fo:declarations. Both xmpmeta and RDF elements can be used as root elements for XMP metadata. Extracted DOM2SAX functionality from XMLXMLHandler into utility class since it is now reused elsewhere. New DOMBuilderContentHandlerFactory is used to create ContentHandlers that build generic DOMs. New DelegatingContentHandler is a convenience base class modelled after XMLFilterImpl but as passive SAX receiver. It is used by DOMBuilderContentHandlerFactory. Refactored FOTreeBuilder. FO tree building is now in a special ContentHandler which can be replaced temporarily when handling foreign XML like SVG or XMP. Extension Elements wanting the set their own ContentHandlers (instead of using the standard FO tree building mechanism) return a non-null value in getContentHandlerFactory(). The old mechanism is still supported (MathML, Plan and Barcode4J still use that). However, SVG support is changed to use a ContentHandlerFactory. Extension elements for xmpmeta and RDF elements making use of the new DOM build-up using ContentHandlerFactory. XMP metadata is passed to the renderer as ExtensionAttachment to the document. Only PDFRenderer uses the XMP extension attachment at this time. The PDFRenderer automatically builds XMP metadata based on the basic metadata information in the PDFInfo object if no explicit XMP metadata has been added to the XSL-FO document. XMP metadata merging is not implemented because this would involve a more sophisticated XMP infrastructure. That also means that XMP metadata is not validated. It's passed into the PDF as is. The PDF library now provides the PDFMetadata class to embed XMP metadata in PDFs version >=1.4. stream contents use a special filter list which is initially empty, so non-PDF-aware XMP readers can extract (and optionally modify) the XMP metadata. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@378482 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Merged revisions 607034-611115 via svnmerge from https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk ........ r607036 | jeremias | 2007-12-27 11:51:11 +0100 (Do, 27 Dez 2007) | 1 line Don't just exit with no error message if the document contains no content. Pretty irritating if it does so. ........ r608812 | acumiskey | 2008-01-04 13:14:33 +0100 (Fr, 04 Jan 2008) | 3 lines The fonts variable would have always had an empty Configuration node (non-null value) even if a <fonts/> wasn't present in the fop configuration. ........ r609567 | jeremias | 2008-01-07 11:52:09 +0100 (Mo, 07 Jan 2008) | 4 lines Reenabled documentation for fox:destination. Enabled intermediate format functionality for fox:destination. Added a test case to check fox:destination. Deprecated FOP's XMLizable in favor of the XML Graphics Commons variant (and extend that variant). ........ r609627 | jeremias | 2008-01-07 16:06:24 +0100 (Mo, 07 Jan 2008) | 5 lines Bugzilla #44176: Support for custom fonts in Java2DRenderer and derived renderers. Submitted by: Patrick Jaromin <patrick.at.jgsullivan.dot.com> Patch modified slightly by jeremias. ........ r610020 | acumiskey | 2008-01-08 16:27:02 +0100 (Di, 08 Jan 2008) | 2 lines cleaned up ........ r610021 | acumiskey | 2008-01-08 16:28:56 +0100 (Di, 08 Jan 2008) | 2 lines Appears to be unused/referenced and superceeded by PageGroup ........ r610022 | acumiskey | 2008-01-08 16:34:07 +0100 (Di, 08 Jan 2008) | 2 lines cleaned up ........ r610023 | acumiskey | 2008-01-08 16:35:18 +0100 (Di, 08 Jan 2008) | 2 lines fixed javadoc ........ r610337 | vhennebert | 2008-01-09 12:02:08 +0100 (Mi, 09 Jan 2008) | 2 lines Fixed checkstyle issues: tabs and trailing spaces ........ r610355 | vhennebert | 2008-01-09 13:01:21 +0100 (Mi, 09 Jan 2008) | 2 lines keep-together is an inherited property ........ r610420 | acumiskey | 2008-01-09 16:40:25 +0100 (Mi, 09 Jan 2008) | 2 lines cleanup ........ r610704 | jeremias | 2008-01-10 08:38:47 +0100 (Do, 10 Jan 2008) | 1 line Added basic support for PDF page labels. ........ r610739 | jeremias | 2008-01-10 11:13:21 +0100 (Do, 10 Jan 2008) | 1 line PostScript output now generates the bounding box DSC comments for the whole document. ........ r610821 | vhennebert | 2008-01-10 16:53:20 +0100 (Do, 10 Jan 2008) | 4 lines - renamed variables for clarity - moved the computation of a cell's content length in PrimaryGridUnit - better javadoc for getHeight method in EffRow ........ r610848 | vhennebert | 2008-01-10 18:41:52 +0100 (Do, 10 Jan 2008) | 2 lines No need to check if the end of the cell is reached when creating the areas for a row ........ r610853 | vhennebert | 2008-01-10 18:54:16 +0100 (Do, 10 Jan 2008) | 2 lines Simplified addAreasAndFlushRow ........ r610886 | vhennebert | 2008-01-10 20:23:56 +0100 (Do, 10 Jan 2008) | 2 lines Removed endPart() method and moved its content into addAreasAndFlushRow() ........ r610891 | vhennebert | 2008-01-10 20:34:13 +0100 (Do, 10 Jan 2008) | 2 lines Removed accumulatedBPD which is redundant with yoffset ........ r610893 | vhennebert | 2008-01-10 20:35:24 +0100 (Do, 10 Jan 2008) | 2 lines The return value of addAreasAndFlushRow is never used, changed it to void ........ r610905 | vhennebert | 2008-01-10 20:57:29 +0100 (Do, 10 Jan 2008) | 2 lines Renamed lastRow into currentRow and yoffset into currentRowOffset ........ r611114 | jeremias | 2008-01-11 10:04:28 +0100 (Fr, 11 Jan 2008) | 2 lines Bugfix: Some string objects were not encrypted (for example in named destinations) I had to refactor the PDF library a little bit but since it only affects the inner API it shouldn't be a problem that I removed some methods which caused trouble because a didn't think about encryption when I worked on the PDF library last year. ........ git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ImagePackageRedesign@611120 13f79535-47bb-0310-9956-ffa450edef68
16 years ago
Merged revisions 607034-611115 via svnmerge from https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk ........ r607036 | jeremias | 2007-12-27 11:51:11 +0100 (Do, 27 Dez 2007) | 1 line Don't just exit with no error message if the document contains no content. Pretty irritating if it does so. ........ r608812 | acumiskey | 2008-01-04 13:14:33 +0100 (Fr, 04 Jan 2008) | 3 lines The fonts variable would have always had an empty Configuration node (non-null value) even if a <fonts/> wasn't present in the fop configuration. ........ r609567 | jeremias | 2008-01-07 11:52:09 +0100 (Mo, 07 Jan 2008) | 4 lines Reenabled documentation for fox:destination. Enabled intermediate format functionality for fox:destination. Added a test case to check fox:destination. Deprecated FOP's XMLizable in favor of the XML Graphics Commons variant (and extend that variant). ........ r609627 | jeremias | 2008-01-07 16:06:24 +0100 (Mo, 07 Jan 2008) | 5 lines Bugzilla #44176: Support for custom fonts in Java2DRenderer and derived renderers. Submitted by: Patrick Jaromin <patrick.at.jgsullivan.dot.com> Patch modified slightly by jeremias. ........ r610020 | acumiskey | 2008-01-08 16:27:02 +0100 (Di, 08 Jan 2008) | 2 lines cleaned up ........ r610021 | acumiskey | 2008-01-08 16:28:56 +0100 (Di, 08 Jan 2008) | 2 lines Appears to be unused/referenced and superceeded by PageGroup ........ r610022 | acumiskey | 2008-01-08 16:34:07 +0100 (Di, 08 Jan 2008) | 2 lines cleaned up ........ r610023 | acumiskey | 2008-01-08 16:35:18 +0100 (Di, 08 Jan 2008) | 2 lines fixed javadoc ........ r610337 | vhennebert | 2008-01-09 12:02:08 +0100 (Mi, 09 Jan 2008) | 2 lines Fixed checkstyle issues: tabs and trailing spaces ........ r610355 | vhennebert | 2008-01-09 13:01:21 +0100 (Mi, 09 Jan 2008) | 2 lines keep-together is an inherited property ........ r610420 | acumiskey | 2008-01-09 16:40:25 +0100 (Mi, 09 Jan 2008) | 2 lines cleanup ........ r610704 | jeremias | 2008-01-10 08:38:47 +0100 (Do, 10 Jan 2008) | 1 line Added basic support for PDF page labels. ........ r610739 | jeremias | 2008-01-10 11:13:21 +0100 (Do, 10 Jan 2008) | 1 line PostScript output now generates the bounding box DSC comments for the whole document. ........ r610821 | vhennebert | 2008-01-10 16:53:20 +0100 (Do, 10 Jan 2008) | 4 lines - renamed variables for clarity - moved the computation of a cell's content length in PrimaryGridUnit - better javadoc for getHeight method in EffRow ........ r610848 | vhennebert | 2008-01-10 18:41:52 +0100 (Do, 10 Jan 2008) | 2 lines No need to check if the end of the cell is reached when creating the areas for a row ........ r610853 | vhennebert | 2008-01-10 18:54:16 +0100 (Do, 10 Jan 2008) | 2 lines Simplified addAreasAndFlushRow ........ r610886 | vhennebert | 2008-01-10 20:23:56 +0100 (Do, 10 Jan 2008) | 2 lines Removed endPart() method and moved its content into addAreasAndFlushRow() ........ r610891 | vhennebert | 2008-01-10 20:34:13 +0100 (Do, 10 Jan 2008) | 2 lines Removed accumulatedBPD which is redundant with yoffset ........ r610893 | vhennebert | 2008-01-10 20:35:24 +0100 (Do, 10 Jan 2008) | 2 lines The return value of addAreasAndFlushRow is never used, changed it to void ........ r610905 | vhennebert | 2008-01-10 20:57:29 +0100 (Do, 10 Jan 2008) | 2 lines Renamed lastRow into currentRow and yoffset into currentRowOffset ........ r611114 | jeremias | 2008-01-11 10:04:28 +0100 (Fr, 11 Jan 2008) | 2 lines Bugfix: Some string objects were not encrypted (for example in named destinations) I had to refactor the PDF library a little bit but since it only affects the inner API it shouldn't be a problem that I removed some methods which caused trouble because a didn't think about encryption when I worked on the PDF library last year. ........ git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ImagePackageRedesign@611120 13f79535-47bb-0310-9956-ffa450edef68
16 years ago
Fop.java gets two new constructors: Fop(String) and Fop(String, FOUserAgent) where the String is the MIME type for the desired output format. MimeConstants provides a comprehensive list of MIME types used in Fop.java. Non-standard, FOP-specific MIME types changed to a uniform pattern: application/X-fop-awt-preview, application/X-fop-print and application/X-fop-areatree. RendererFactory now supports manual registration and dynamic discovery of Renderers and FOEventHandlers by their MIME types. Instantitation is done using MIME types everywhere. The RENDER_* constants are mapped to MIME types in Fop.java. RendererFactory is now an instantiable class whose reference is held by FOUserAgent just like it is done for the XLMHandlers. Renderers and FOEventHandlers now each have a *Maker class which is a kind of factory class which is used to register a Renderer/FOEventHandler and additionally serves to provide additional information about the thing, such as the MIME types it supports and if the implementation requires an OutputStream. The command-line gets a new option: -out application/pdf myfile.pdf is the generic way to create an output file. If someone created a WordML output handler and provided the right service resource file he could specify "-out text/xml+msword out.xml". ".out list" lists all MIME types that are available for output. Renderers can now potionally expose a Graphics2DAdapter which in concert with Graphics2DImagePainter can be used by FOP extensions to paint their content directly using a Graphics2D instance. That makes it possible to avoid a detour via SVG/Batik in certain cases. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@332549 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Fop.java gets two new constructors: Fop(String) and Fop(String, FOUserAgent) where the String is the MIME type for the desired output format. MimeConstants provides a comprehensive list of MIME types used in Fop.java. Non-standard, FOP-specific MIME types changed to a uniform pattern: application/X-fop-awt-preview, application/X-fop-print and application/X-fop-areatree. RendererFactory now supports manual registration and dynamic discovery of Renderers and FOEventHandlers by their MIME types. Instantitation is done using MIME types everywhere. The RENDER_* constants are mapped to MIME types in Fop.java. RendererFactory is now an instantiable class whose reference is held by FOUserAgent just like it is done for the XLMHandlers. Renderers and FOEventHandlers now each have a *Maker class which is a kind of factory class which is used to register a Renderer/FOEventHandler and additionally serves to provide additional information about the thing, such as the MIME types it supports and if the implementation requires an OutputStream. The command-line gets a new option: -out application/pdf myfile.pdf is the generic way to create an output file. If someone created a WordML output handler and provided the right service resource file he could specify "-out text/xml+msword out.xml". ".out list" lists all MIME types that are available for output. Renderers can now potionally expose a Graphics2DAdapter which in concert with Graphics2DImagePainter can be used by FOP extensions to paint their content directly using a Graphics2D instance. That makes it possible to avoid a detour via SVG/Batik in certain cases. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@332549 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Merged revisions 607034-611115 via svnmerge from https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk ........ r607036 | jeremias | 2007-12-27 11:51:11 +0100 (Do, 27 Dez 2007) | 1 line Don't just exit with no error message if the document contains no content. Pretty irritating if it does so. ........ r608812 | acumiskey | 2008-01-04 13:14:33 +0100 (Fr, 04 Jan 2008) | 3 lines The fonts variable would have always had an empty Configuration node (non-null value) even if a <fonts/> wasn't present in the fop configuration. ........ r609567 | jeremias | 2008-01-07 11:52:09 +0100 (Mo, 07 Jan 2008) | 4 lines Reenabled documentation for fox:destination. Enabled intermediate format functionality for fox:destination. Added a test case to check fox:destination. Deprecated FOP's XMLizable in favor of the XML Graphics Commons variant (and extend that variant). ........ r609627 | jeremias | 2008-01-07 16:06:24 +0100 (Mo, 07 Jan 2008) | 5 lines Bugzilla #44176: Support for custom fonts in Java2DRenderer and derived renderers. Submitted by: Patrick Jaromin <patrick.at.jgsullivan.dot.com> Patch modified slightly by jeremias. ........ r610020 | acumiskey | 2008-01-08 16:27:02 +0100 (Di, 08 Jan 2008) | 2 lines cleaned up ........ r610021 | acumiskey | 2008-01-08 16:28:56 +0100 (Di, 08 Jan 2008) | 2 lines Appears to be unused/referenced and superceeded by PageGroup ........ r610022 | acumiskey | 2008-01-08 16:34:07 +0100 (Di, 08 Jan 2008) | 2 lines cleaned up ........ r610023 | acumiskey | 2008-01-08 16:35:18 +0100 (Di, 08 Jan 2008) | 2 lines fixed javadoc ........ r610337 | vhennebert | 2008-01-09 12:02:08 +0100 (Mi, 09 Jan 2008) | 2 lines Fixed checkstyle issues: tabs and trailing spaces ........ r610355 | vhennebert | 2008-01-09 13:01:21 +0100 (Mi, 09 Jan 2008) | 2 lines keep-together is an inherited property ........ r610420 | acumiskey | 2008-01-09 16:40:25 +0100 (Mi, 09 Jan 2008) | 2 lines cleanup ........ r610704 | jeremias | 2008-01-10 08:38:47 +0100 (Do, 10 Jan 2008) | 1 line Added basic support for PDF page labels. ........ r610739 | jeremias | 2008-01-10 11:13:21 +0100 (Do, 10 Jan 2008) | 1 line PostScript output now generates the bounding box DSC comments for the whole document. ........ r610821 | vhennebert | 2008-01-10 16:53:20 +0100 (Do, 10 Jan 2008) | 4 lines - renamed variables for clarity - moved the computation of a cell's content length in PrimaryGridUnit - better javadoc for getHeight method in EffRow ........ r610848 | vhennebert | 2008-01-10 18:41:52 +0100 (Do, 10 Jan 2008) | 2 lines No need to check if the end of the cell is reached when creating the areas for a row ........ r610853 | vhennebert | 2008-01-10 18:54:16 +0100 (Do, 10 Jan 2008) | 2 lines Simplified addAreasAndFlushRow ........ r610886 | vhennebert | 2008-01-10 20:23:56 +0100 (Do, 10 Jan 2008) | 2 lines Removed endPart() method and moved its content into addAreasAndFlushRow() ........ r610891 | vhennebert | 2008-01-10 20:34:13 +0100 (Do, 10 Jan 2008) | 2 lines Removed accumulatedBPD which is redundant with yoffset ........ r610893 | vhennebert | 2008-01-10 20:35:24 +0100 (Do, 10 Jan 2008) | 2 lines The return value of addAreasAndFlushRow is never used, changed it to void ........ r610905 | vhennebert | 2008-01-10 20:57:29 +0100 (Do, 10 Jan 2008) | 2 lines Renamed lastRow into currentRow and yoffset into currentRowOffset ........ r611114 | jeremias | 2008-01-11 10:04:28 +0100 (Fr, 11 Jan 2008) | 2 lines Bugfix: Some string objects were not encrypted (for example in named destinations) I had to refactor the PDF library a little bit but since it only affects the inner API it shouldn't be a problem that I removed some methods which caused trouble because a didn't think about encryption when I worked on the PDF library last year. ........ git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ImagePackageRedesign@611120 13f79535-47bb-0310-9956-ffa450edef68
16 years ago
Initial support for XMP metadata (PDF 1.4) under fo:declarations. Both xmpmeta and RDF elements can be used as root elements for XMP metadata. Extracted DOM2SAX functionality from XMLXMLHandler into utility class since it is now reused elsewhere. New DOMBuilderContentHandlerFactory is used to create ContentHandlers that build generic DOMs. New DelegatingContentHandler is a convenience base class modelled after XMLFilterImpl but as passive SAX receiver. It is used by DOMBuilderContentHandlerFactory. Refactored FOTreeBuilder. FO tree building is now in a special ContentHandler which can be replaced temporarily when handling foreign XML like SVG or XMP. Extension Elements wanting the set their own ContentHandlers (instead of using the standard FO tree building mechanism) return a non-null value in getContentHandlerFactory(). The old mechanism is still supported (MathML, Plan and Barcode4J still use that). However, SVG support is changed to use a ContentHandlerFactory. Extension elements for xmpmeta and RDF elements making use of the new DOM build-up using ContentHandlerFactory. XMP metadata is passed to the renderer as ExtensionAttachment to the document. Only PDFRenderer uses the XMP extension attachment at this time. The PDFRenderer automatically builds XMP metadata based on the basic metadata information in the PDFInfo object if no explicit XMP metadata has been added to the XSL-FO document. XMP metadata merging is not implemented because this would involve a more sophisticated XMP infrastructure. That also means that XMP metadata is not validated. It's passed into the PDF as is. The PDF library now provides the PDFMetadata class to embed XMP metadata in PDFs version >=1.4. stream contents use a special filter list which is initially empty, so non-PDF-aware XMP readers can extract (and optionally modify) the XMP metadata. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@378482 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Initial support for XMP metadata (PDF 1.4) under fo:declarations. Both xmpmeta and RDF elements can be used as root elements for XMP metadata. Extracted DOM2SAX functionality from XMLXMLHandler into utility class since it is now reused elsewhere. New DOMBuilderContentHandlerFactory is used to create ContentHandlers that build generic DOMs. New DelegatingContentHandler is a convenience base class modelled after XMLFilterImpl but as passive SAX receiver. It is used by DOMBuilderContentHandlerFactory. Refactored FOTreeBuilder. FO tree building is now in a special ContentHandler which can be replaced temporarily when handling foreign XML like SVG or XMP. Extension Elements wanting the set their own ContentHandlers (instead of using the standard FO tree building mechanism) return a non-null value in getContentHandlerFactory(). The old mechanism is still supported (MathML, Plan and Barcode4J still use that). However, SVG support is changed to use a ContentHandlerFactory. Extension elements for xmpmeta and RDF elements making use of the new DOM build-up using ContentHandlerFactory. XMP metadata is passed to the renderer as ExtensionAttachment to the document. Only PDFRenderer uses the XMP extension attachment at this time. The PDFRenderer automatically builds XMP metadata based on the basic metadata information in the PDFInfo object if no explicit XMP metadata has been added to the XSL-FO document. XMP metadata merging is not implemented because this would involve a more sophisticated XMP infrastructure. That also means that XMP metadata is not validated. It's passed into the PDF as is. The PDF library now provides the PDFMetadata class to embed XMP metadata in PDFs version >=1.4. stream contents use a special filter list which is initially empty, so non-PDF-aware XMP readers can extract (and optionally modify) the XMP metadata. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@378482 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Initial support for XMP metadata (PDF 1.4) under fo:declarations. Both xmpmeta and RDF elements can be used as root elements for XMP metadata. Extracted DOM2SAX functionality from XMLXMLHandler into utility class since it is now reused elsewhere. New DOMBuilderContentHandlerFactory is used to create ContentHandlers that build generic DOMs. New DelegatingContentHandler is a convenience base class modelled after XMLFilterImpl but as passive SAX receiver. It is used by DOMBuilderContentHandlerFactory. Refactored FOTreeBuilder. FO tree building is now in a special ContentHandler which can be replaced temporarily when handling foreign XML like SVG or XMP. Extension Elements wanting the set their own ContentHandlers (instead of using the standard FO tree building mechanism) return a non-null value in getContentHandlerFactory(). The old mechanism is still supported (MathML, Plan and Barcode4J still use that). However, SVG support is changed to use a ContentHandlerFactory. Extension elements for xmpmeta and RDF elements making use of the new DOM build-up using ContentHandlerFactory. XMP metadata is passed to the renderer as ExtensionAttachment to the document. Only PDFRenderer uses the XMP extension attachment at this time. The PDFRenderer automatically builds XMP metadata based on the basic metadata information in the PDFInfo object if no explicit XMP metadata has been added to the XSL-FO document. XMP metadata merging is not implemented because this would involve a more sophisticated XMP infrastructure. That also means that XMP metadata is not validated. It's passed into the PDF as is. The PDF library now provides the PDFMetadata class to embed XMP metadata in PDFs version >=1.4. stream contents use a special filter list which is initially empty, so non-PDF-aware XMP readers can extract (and optionally modify) the XMP metadata. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@378482 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Initial support for XMP metadata (PDF 1.4) under fo:declarations. Both xmpmeta and RDF elements can be used as root elements for XMP metadata. Extracted DOM2SAX functionality from XMLXMLHandler into utility class since it is now reused elsewhere. New DOMBuilderContentHandlerFactory is used to create ContentHandlers that build generic DOMs. New DelegatingContentHandler is a convenience base class modelled after XMLFilterImpl but as passive SAX receiver. It is used by DOMBuilderContentHandlerFactory. Refactored FOTreeBuilder. FO tree building is now in a special ContentHandler which can be replaced temporarily when handling foreign XML like SVG or XMP. Extension Elements wanting the set their own ContentHandlers (instead of using the standard FO tree building mechanism) return a non-null value in getContentHandlerFactory(). The old mechanism is still supported (MathML, Plan and Barcode4J still use that). However, SVG support is changed to use a ContentHandlerFactory. Extension elements for xmpmeta and RDF elements making use of the new DOM build-up using ContentHandlerFactory. XMP metadata is passed to the renderer as ExtensionAttachment to the document. Only PDFRenderer uses the XMP extension attachment at this time. The PDFRenderer automatically builds XMP metadata based on the basic metadata information in the PDFInfo object if no explicit XMP metadata has been added to the XSL-FO document. XMP metadata merging is not implemented because this would involve a more sophisticated XMP infrastructure. That also means that XMP metadata is not validated. It's passed into the PDF as is. The PDF library now provides the PDFMetadata class to embed XMP metadata in PDFs version >=1.4. stream contents use a special filter list which is initially empty, so non-PDF-aware XMP readers can extract (and optionally modify) the XMP metadata. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@378482 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Fop.java gets two new constructors: Fop(String) and Fop(String, FOUserAgent) where the String is the MIME type for the desired output format. MimeConstants provides a comprehensive list of MIME types used in Fop.java. Non-standard, FOP-specific MIME types changed to a uniform pattern: application/X-fop-awt-preview, application/X-fop-print and application/X-fop-areatree. RendererFactory now supports manual registration and dynamic discovery of Renderers and FOEventHandlers by their MIME types. Instantitation is done using MIME types everywhere. The RENDER_* constants are mapped to MIME types in Fop.java. RendererFactory is now an instantiable class whose reference is held by FOUserAgent just like it is done for the XLMHandlers. Renderers and FOEventHandlers now each have a *Maker class which is a kind of factory class which is used to register a Renderer/FOEventHandler and additionally serves to provide additional information about the thing, such as the MIME types it supports and if the implementation requires an OutputStream. The command-line gets a new option: -out application/pdf myfile.pdf is the generic way to create an output file. If someone created a WordML output handler and provided the right service resource file he could specify "-out text/xml+msword out.xml". ".out list" lists all MIME types that are available for output. Renderers can now potionally expose a Graphics2DAdapter which in concert with Graphics2DImagePainter can be used by FOP extensions to paint their content directly using a Graphics2D instance. That makes it possible to avoid a detour via SVG/Batik in certain cases. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@332549 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Initial support for XMP metadata (PDF 1.4) under fo:declarations. Both xmpmeta and RDF elements can be used as root elements for XMP metadata. Extracted DOM2SAX functionality from XMLXMLHandler into utility class since it is now reused elsewhere. New DOMBuilderContentHandlerFactory is used to create ContentHandlers that build generic DOMs. New DelegatingContentHandler is a convenience base class modelled after XMLFilterImpl but as passive SAX receiver. It is used by DOMBuilderContentHandlerFactory. Refactored FOTreeBuilder. FO tree building is now in a special ContentHandler which can be replaced temporarily when handling foreign XML like SVG or XMP. Extension Elements wanting the set their own ContentHandlers (instead of using the standard FO tree building mechanism) return a non-null value in getContentHandlerFactory(). The old mechanism is still supported (MathML, Plan and Barcode4J still use that). However, SVG support is changed to use a ContentHandlerFactory. Extension elements for xmpmeta and RDF elements making use of the new DOM build-up using ContentHandlerFactory. XMP metadata is passed to the renderer as ExtensionAttachment to the document. Only PDFRenderer uses the XMP extension attachment at this time. The PDFRenderer automatically builds XMP metadata based on the basic metadata information in the PDFInfo object if no explicit XMP metadata has been added to the XSL-FO document. XMP metadata merging is not implemented because this would involve a more sophisticated XMP infrastructure. That also means that XMP metadata is not validated. It's passed into the PDF as is. The PDF library now provides the PDFMetadata class to embed XMP metadata in PDFs version >=1.4. stream contents use a special filter list which is initially empty, so non-PDF-aware XMP readers can extract (and optionally modify) the XMP metadata. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@378482 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Initial support for XMP metadata (PDF 1.4) under fo:declarations. Both xmpmeta and RDF elements can be used as root elements for XMP metadata. Extracted DOM2SAX functionality from XMLXMLHandler into utility class since it is now reused elsewhere. New DOMBuilderContentHandlerFactory is used to create ContentHandlers that build generic DOMs. New DelegatingContentHandler is a convenience base class modelled after XMLFilterImpl but as passive SAX receiver. It is used by DOMBuilderContentHandlerFactory. Refactored FOTreeBuilder. FO tree building is now in a special ContentHandler which can be replaced temporarily when handling foreign XML like SVG or XMP. Extension Elements wanting the set their own ContentHandlers (instead of using the standard FO tree building mechanism) return a non-null value in getContentHandlerFactory(). The old mechanism is still supported (MathML, Plan and Barcode4J still use that). However, SVG support is changed to use a ContentHandlerFactory. Extension elements for xmpmeta and RDF elements making use of the new DOM build-up using ContentHandlerFactory. XMP metadata is passed to the renderer as ExtensionAttachment to the document. Only PDFRenderer uses the XMP extension attachment at this time. The PDFRenderer automatically builds XMP metadata based on the basic metadata information in the PDFInfo object if no explicit XMP metadata has been added to the XSL-FO document. XMP metadata merging is not implemented because this would involve a more sophisticated XMP infrastructure. That also means that XMP metadata is not validated. It's passed into the PDF as is. The PDF library now provides the PDFMetadata class to embed XMP metadata in PDFs version >=1.4. stream contents use a special filter list which is initially empty, so non-PDF-aware XMP readers can extract (and optionally modify) the XMP metadata. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@378482 13f79535-47bb-0310-9956-ffa450edef68
18 years ago
Merged revisions 607034-611115 via svnmerge from https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk ........ r607036 | jeremias | 2007-12-27 11:51:11 +0100 (Do, 27 Dez 2007) | 1 line Don't just exit with no error message if the document contains no content. Pretty irritating if it does so. ........ r608812 | acumiskey | 2008-01-04 13:14:33 +0100 (Fr, 04 Jan 2008) | 3 lines The fonts variable would have always had an empty Configuration node (non-null value) even if a <fonts/> wasn't present in the fop configuration. ........ r609567 | jeremias | 2008-01-07 11:52:09 +0100 (Mo, 07 Jan 2008) | 4 lines Reenabled documentation for fox:destination. Enabled intermediate format functionality for fox:destination. Added a test case to check fox:destination. Deprecated FOP's XMLizable in favor of the XML Graphics Commons variant (and extend that variant). ........ r609627 | jeremias | 2008-01-07 16:06:24 +0100 (Mo, 07 Jan 2008) | 5 lines Bugzilla #44176: Support for custom fonts in Java2DRenderer and derived renderers. Submitted by: Patrick Jaromin <patrick.at.jgsullivan.dot.com> Patch modified slightly by jeremias. ........ r610020 | acumiskey | 2008-01-08 16:27:02 +0100 (Di, 08 Jan 2008) | 2 lines cleaned up ........ r610021 | acumiskey | 2008-01-08 16:28:56 +0100 (Di, 08 Jan 2008) | 2 lines Appears to be unused/referenced and superceeded by PageGroup ........ r610022 | acumiskey | 2008-01-08 16:34:07 +0100 (Di, 08 Jan 2008) | 2 lines cleaned up ........ r610023 | acumiskey | 2008-01-08 16:35:18 +0100 (Di, 08 Jan 2008) | 2 lines fixed javadoc ........ r610337 | vhennebert | 2008-01-09 12:02:08 +0100 (Mi, 09 Jan 2008) | 2 lines Fixed checkstyle issues: tabs and trailing spaces ........ r610355 | vhennebert | 2008-01-09 13:01:21 +0100 (Mi, 09 Jan 2008) | 2 lines keep-together is an inherited property ........ r610420 | acumiskey | 2008-01-09 16:40:25 +0100 (Mi, 09 Jan 2008) | 2 lines cleanup ........ r610704 | jeremias | 2008-01-10 08:38:47 +0100 (Do, 10 Jan 2008) | 1 line Added basic support for PDF page labels. ........ r610739 | jeremias | 2008-01-10 11:13:21 +0100 (Do, 10 Jan 2008) | 1 line PostScript output now generates the bounding box DSC comments for the whole document. ........ r610821 | vhennebert | 2008-01-10 16:53:20 +0100 (Do, 10 Jan 2008) | 4 lines - renamed variables for clarity - moved the computation of a cell's content length in PrimaryGridUnit - better javadoc for getHeight method in EffRow ........ r610848 | vhennebert | 2008-01-10 18:41:52 +0100 (Do, 10 Jan 2008) | 2 lines No need to check if the end of the cell is reached when creating the areas for a row ........ r610853 | vhennebert | 2008-01-10 18:54:16 +0100 (Do, 10 Jan 2008) | 2 lines Simplified addAreasAndFlushRow ........ r610886 | vhennebert | 2008-01-10 20:23:56 +0100 (Do, 10 Jan 2008) | 2 lines Removed endPart() method and moved its content into addAreasAndFlushRow() ........ r610891 | vhennebert | 2008-01-10 20:34:13 +0100 (Do, 10 Jan 2008) | 2 lines Removed accumulatedBPD which is redundant with yoffset ........ r610893 | vhennebert | 2008-01-10 20:35:24 +0100 (Do, 10 Jan 2008) | 2 lines The return value of addAreasAndFlushRow is never used, changed it to void ........ r610905 | vhennebert | 2008-01-10 20:57:29 +0100 (Do, 10 Jan 2008) | 2 lines Renamed lastRow into currentRow and yoffset into currentRowOffset ........ r611114 | jeremias | 2008-01-11 10:04:28 +0100 (Fr, 11 Jan 2008) | 2 lines Bugfix: Some string objects were not encrypted (for example in named destinations) I had to refactor the PDF library a little bit but since it only affects the inner API it shouldn't be a problem that I removed some methods which caused trouble because a didn't think about encryption when I worked on the PDF library last year. ........ git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ImagePackageRedesign@611120 13f79535-47bb-0310-9956-ffa450edef68
16 years ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.render.pdf;
  19. // Java
  20. import java.awt.Color;
  21. import java.awt.Point;
  22. import java.awt.Rectangle;
  23. import java.awt.color.ColorSpace;
  24. import java.awt.color.ICC_Profile;
  25. import java.awt.geom.AffineTransform;
  26. import java.awt.geom.Point2D;
  27. import java.awt.geom.Rectangle2D;
  28. import java.io.IOException;
  29. import java.io.InputStream;
  30. import java.io.OutputStream;
  31. import java.net.URL;
  32. import java.util.Iterator;
  33. import java.util.List;
  34. import java.util.Map;
  35. import javax.xml.transform.Source;
  36. import javax.xml.transform.stream.StreamSource;
  37. import org.apache.commons.io.IOUtils;
  38. import org.apache.xmlgraphics.image.loader.ImageException;
  39. import org.apache.xmlgraphics.image.loader.ImageInfo;
  40. import org.apache.xmlgraphics.image.loader.ImageManager;
  41. import org.apache.xmlgraphics.image.loader.ImageSessionContext;
  42. import org.apache.xmlgraphics.image.loader.util.ImageUtil;
  43. import org.apache.xmlgraphics.xmp.Metadata;
  44. import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
  45. import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;
  46. import org.apache.fop.apps.FOPException;
  47. import org.apache.fop.apps.FOUserAgent;
  48. import org.apache.fop.apps.MimeConstants;
  49. import org.apache.fop.area.Area;
  50. import org.apache.fop.area.Block;
  51. import org.apache.fop.area.BookmarkData;
  52. import org.apache.fop.area.CTM;
  53. import org.apache.fop.area.DestinationData;
  54. import org.apache.fop.area.LineArea;
  55. import org.apache.fop.area.OffDocumentExtensionAttachment;
  56. import org.apache.fop.area.OffDocumentItem;
  57. import org.apache.fop.area.PageViewport;
  58. import org.apache.fop.area.RegionViewport;
  59. import org.apache.fop.area.Trait;
  60. import org.apache.fop.area.inline.AbstractTextArea;
  61. import org.apache.fop.area.inline.Image;
  62. import org.apache.fop.area.inline.InlineArea;
  63. import org.apache.fop.area.inline.InlineParent;
  64. import org.apache.fop.area.inline.Leader;
  65. import org.apache.fop.area.inline.SpaceArea;
  66. import org.apache.fop.area.inline.TextArea;
  67. import org.apache.fop.area.inline.WordArea;
  68. import org.apache.fop.datatypes.URISpecification;
  69. import org.apache.fop.fo.Constants;
  70. import org.apache.fop.fo.extensions.ExtensionAttachment;
  71. import org.apache.fop.fo.extensions.xmp.XMPMetadata;
  72. import org.apache.fop.fonts.Font;
  73. import org.apache.fop.fonts.Typeface;
  74. import org.apache.fop.pdf.PDFAMode;
  75. import org.apache.fop.pdf.PDFAction;
  76. import org.apache.fop.pdf.PDFAnnotList;
  77. import org.apache.fop.pdf.PDFColor;
  78. import org.apache.fop.pdf.PDFConformanceException;
  79. import org.apache.fop.pdf.PDFDictionary;
  80. import org.apache.fop.pdf.PDFDocument;
  81. import org.apache.fop.pdf.PDFEncryptionManager;
  82. import org.apache.fop.pdf.PDFEncryptionParams;
  83. import org.apache.fop.pdf.PDFFactory;
  84. import org.apache.fop.pdf.PDFFilterList;
  85. import org.apache.fop.pdf.PDFGoTo;
  86. import org.apache.fop.pdf.PDFICCBasedColorSpace;
  87. import org.apache.fop.pdf.PDFICCStream;
  88. import org.apache.fop.pdf.PDFInfo;
  89. import org.apache.fop.pdf.PDFLink;
  90. import org.apache.fop.pdf.PDFMetadata;
  91. import org.apache.fop.pdf.PDFNumber;
  92. import org.apache.fop.pdf.PDFNumsArray;
  93. import org.apache.fop.pdf.PDFOutline;
  94. import org.apache.fop.pdf.PDFOutputIntent;
  95. import org.apache.fop.pdf.PDFPage;
  96. import org.apache.fop.pdf.PDFPageLabels;
  97. import org.apache.fop.pdf.PDFResourceContext;
  98. import org.apache.fop.pdf.PDFResources;
  99. import org.apache.fop.pdf.PDFState;
  100. import org.apache.fop.pdf.PDFStream;
  101. import org.apache.fop.pdf.PDFText;
  102. import org.apache.fop.pdf.PDFXMode;
  103. import org.apache.fop.pdf.PDFXObject;
  104. import org.apache.fop.render.AbstractPathOrientedRenderer;
  105. import org.apache.fop.render.Graphics2DAdapter;
  106. import org.apache.fop.render.RendererContext;
  107. import org.apache.fop.util.CharUtilities;
  108. import org.apache.fop.util.ColorProfileUtil;
  109. /**
  110. * Renderer that renders areas to PDF.
  111. */
  112. public class PDFRenderer extends AbstractPathOrientedRenderer {
  113. /**
  114. * The mime type for pdf
  115. */
  116. public static final String MIME_TYPE = MimeConstants.MIME_PDF;
  117. /** Normal PDF resolution (72dpi) */
  118. public static final int NORMAL_PDF_RESOLUTION = 72;
  119. /** PDF encryption parameter: all parameters as object, datatype: PDFEncryptionParams */
  120. public static final String ENCRYPTION_PARAMS = "encryption-params";
  121. /** PDF encryption parameter: user password, datatype: String */
  122. public static final String USER_PASSWORD = "user-password";
  123. /** PDF encryption parameter: owner password, datatype: String */
  124. public static final String OWNER_PASSWORD = "owner-password";
  125. /** PDF encryption parameter: Forbids printing, datatype: Boolean or "true"/"false" */
  126. public static final String NO_PRINT = "noprint";
  127. /** PDF encryption parameter: Forbids copying content, datatype: Boolean or "true"/"false" */
  128. public static final String NO_COPY_CONTENT = "nocopy";
  129. /** PDF encryption parameter: Forbids editing content, datatype: Boolean or "true"/"false" */
  130. public static final String NO_EDIT_CONTENT = "noedit";
  131. /** PDF encryption parameter: Forbids annotations, datatype: Boolean or "true"/"false" */
  132. public static final String NO_ANNOTATIONS = "noannotations";
  133. /** Rendering Options key for the PDF/A mode. */
  134. public static final String PDF_A_MODE = "pdf-a-mode";
  135. /** Rendering Options key for the PDF/X mode. */
  136. public static final String PDF_X_MODE = "pdf-x-mode";
  137. /** Rendering Options key for the ICC profile for the output intent. */
  138. public static final String KEY_OUTPUT_PROFILE = "output-profile";
  139. /** Controls whether comments are written to the PDF stream. */
  140. protected static final boolean WRITE_COMMENTS = true;
  141. /**
  142. * the PDF Document being created
  143. */
  144. protected PDFDocument pdfDoc;
  145. /** the PDF/A mode (Default: disabled) */
  146. protected PDFAMode pdfAMode = PDFAMode.DISABLED;
  147. /** the PDF/X mode (Default: disabled) */
  148. protected PDFXMode pdfXMode = PDFXMode.DISABLED;
  149. /**
  150. * Map of pages using the PageViewport as the key
  151. * this is used for prepared pages that cannot be immediately
  152. * rendered
  153. */
  154. protected Map pages = null;
  155. /**
  156. * Maps unique PageViewport key to PDF page reference
  157. */
  158. protected Map pageReferences = new java.util.HashMap();
  159. /**
  160. * Maps unique PageViewport key back to PageViewport itself
  161. */
  162. protected Map pvReferences = new java.util.HashMap();
  163. /**
  164. * Maps XSL-FO element IDs to their on-page XY-positions
  165. * Must be used in conjunction with the page reference to fully specify the PDFGoTo details
  166. */
  167. protected Map idPositions = new java.util.HashMap();
  168. /**
  169. * Maps XSL-FO element IDs to PDFGoTo objects targeting the corresponding areas
  170. * These objects may not all be fully filled in yet
  171. */
  172. protected Map idGoTos = new java.util.HashMap();
  173. /**
  174. * The PDFGoTos in idGoTos that are not complete yet
  175. */
  176. protected List unfinishedGoTos = new java.util.ArrayList();
  177. // can't use a Set because PDFGoTo.equals returns true if the target is the same,
  178. // even if the object number differs
  179. /**
  180. * The output stream to write the document to
  181. */
  182. protected OutputStream ostream;
  183. /**
  184. * the /Resources object of the PDF document being created
  185. */
  186. protected PDFResources pdfResources;
  187. /**
  188. * the current stream to add PDF commands to
  189. */
  190. protected PDFStream currentStream;
  191. /**
  192. * the current annotation list to add annotations to
  193. */
  194. protected PDFResourceContext currentContext = null;
  195. /**
  196. * the current page to add annotations to
  197. */
  198. protected PDFPage currentPage;
  199. /**
  200. * the current page's PDF reference string (to avoid numerous function calls)
  201. */
  202. protected String currentPageRef;
  203. /** the (optional) encryption parameters */
  204. protected PDFEncryptionParams encryptionParams;
  205. /** the ICC stream used as output profile by this document for PDF/A and PDF/X functionality. */
  206. protected PDFICCStream outputProfile;
  207. /** the ICC stream for the sRGB color space. */
  208. //protected PDFICCStream sRGBProfile;
  209. /** the default sRGB color space. */
  210. protected PDFICCBasedColorSpace sRGBColorSpace;
  211. /** Optional URI to an output profile to be used. */
  212. protected String outputProfileURI;
  213. /** drawing state */
  214. protected PDFState currentState = null;
  215. /** Name of currently selected font */
  216. protected String currentFontName = "";
  217. /** Size of currently selected font */
  218. protected int currentFontSize = 0;
  219. /** page height */
  220. protected int pageHeight;
  221. /** Registry of PDF filters */
  222. protected Map filterMap;
  223. /**
  224. * true if a BT command has been written.
  225. */
  226. protected boolean inTextMode = false;
  227. /** Image handler registry */
  228. private PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry();
  229. /**
  230. * create the PDF renderer
  231. */
  232. public PDFRenderer() {
  233. }
  234. private boolean booleanValueOf(Object obj) {
  235. if (obj instanceof Boolean) {
  236. return ((Boolean)obj).booleanValue();
  237. } else if (obj instanceof String) {
  238. return Boolean.valueOf((String)obj).booleanValue();
  239. } else {
  240. throw new IllegalArgumentException("Boolean or \"true\" or \"false\" expected.");
  241. }
  242. }
  243. /**
  244. * {@inheritDoc}
  245. */
  246. public void setUserAgent(FOUserAgent agent) {
  247. super.setUserAgent(agent);
  248. PDFEncryptionParams params
  249. = (PDFEncryptionParams)agent.getRendererOptions().get(ENCRYPTION_PARAMS);
  250. if (params != null) {
  251. this.encryptionParams = params; //overwrite if available
  252. }
  253. String pwd;
  254. pwd = (String)agent.getRendererOptions().get(USER_PASSWORD);
  255. if (pwd != null) {
  256. if (encryptionParams == null) {
  257. this.encryptionParams = new PDFEncryptionParams();
  258. }
  259. this.encryptionParams.setUserPassword(pwd);
  260. }
  261. pwd = (String)agent.getRendererOptions().get(OWNER_PASSWORD);
  262. if (pwd != null) {
  263. if (encryptionParams == null) {
  264. this.encryptionParams = new PDFEncryptionParams();
  265. }
  266. this.encryptionParams.setOwnerPassword(pwd);
  267. }
  268. Object setting;
  269. setting = agent.getRendererOptions().get(NO_PRINT);
  270. if (setting != null) {
  271. if (encryptionParams == null) {
  272. this.encryptionParams = new PDFEncryptionParams();
  273. }
  274. this.encryptionParams.setAllowPrint(!booleanValueOf(setting));
  275. }
  276. setting = agent.getRendererOptions().get(NO_COPY_CONTENT);
  277. if (setting != null) {
  278. if (encryptionParams == null) {
  279. this.encryptionParams = new PDFEncryptionParams();
  280. }
  281. this.encryptionParams.setAllowCopyContent(!booleanValueOf(setting));
  282. }
  283. setting = agent.getRendererOptions().get(NO_EDIT_CONTENT);
  284. if (setting != null) {
  285. if (encryptionParams == null) {
  286. this.encryptionParams = new PDFEncryptionParams();
  287. }
  288. this.encryptionParams.setAllowEditContent(!booleanValueOf(setting));
  289. }
  290. setting = agent.getRendererOptions().get(NO_ANNOTATIONS);
  291. if (setting != null) {
  292. if (encryptionParams == null) {
  293. this.encryptionParams = new PDFEncryptionParams();
  294. }
  295. this.encryptionParams.setAllowEditAnnotations(!booleanValueOf(setting));
  296. }
  297. String s = (String)agent.getRendererOptions().get(PDF_A_MODE);
  298. if (s != null) {
  299. this.pdfAMode = PDFAMode.valueOf(s);
  300. }
  301. s = (String)agent.getRendererOptions().get(PDF_X_MODE);
  302. if (s != null) {
  303. this.pdfXMode = PDFXMode.valueOf(s);
  304. }
  305. s = (String)agent.getRendererOptions().get(KEY_OUTPUT_PROFILE);
  306. if (s != null) {
  307. this.outputProfileURI = s;
  308. }
  309. }
  310. /**
  311. * {@inheritDoc}
  312. */
  313. public void startRenderer(OutputStream stream) throws IOException {
  314. if (userAgent == null) {
  315. throw new IllegalStateException("UserAgent must be set before starting the renderer");
  316. }
  317. ostream = stream;
  318. this.pdfDoc = new PDFDocument(
  319. userAgent.getProducer() != null ? userAgent.getProducer() : "");
  320. this.pdfDoc.getProfile().setPDFAMode(this.pdfAMode);
  321. this.pdfDoc.getProfile().setPDFXMode(this.pdfXMode);
  322. this.pdfDoc.getInfo().setCreator(userAgent.getCreator());
  323. this.pdfDoc.getInfo().setCreationDate(userAgent.getCreationDate());
  324. this.pdfDoc.getInfo().setAuthor(userAgent.getAuthor());
  325. this.pdfDoc.getInfo().setTitle(userAgent.getTitle());
  326. this.pdfDoc.getInfo().setKeywords(userAgent.getKeywords());
  327. this.pdfDoc.setFilterMap(filterMap);
  328. this.pdfDoc.outputHeader(ostream);
  329. //Setup encryption if necessary
  330. PDFEncryptionManager.setupPDFEncryption(encryptionParams, this.pdfDoc);
  331. addsRGBColorSpace();
  332. if (this.outputProfileURI != null) {
  333. addDefaultOutputProfile();
  334. }
  335. if (pdfXMode != PDFXMode.DISABLED) {
  336. log.debug(pdfXMode + " is active.");
  337. log.warn("Note: " + pdfXMode
  338. + " support is work-in-progress and not fully implemented, yet!");
  339. addPDFXOutputIntent();
  340. }
  341. if (pdfAMode.isPDFA1LevelB()) {
  342. log.debug("PDF/A is active. Conformance Level: " + pdfAMode);
  343. addPDFA1OutputIntent();
  344. }
  345. }
  346. private void addsRGBColorSpace() throws IOException {
  347. if (this.sRGBColorSpace != null) {
  348. return;
  349. }
  350. ICC_Profile profile;
  351. PDFICCStream sRGBProfile = pdfDoc.getFactory().makePDFICCStream();
  352. InputStream in = PDFDocument.class.getResourceAsStream("sRGB Color Space Profile.icm");
  353. if (in != null) {
  354. try {
  355. profile = ICC_Profile.getInstance(in);
  356. } finally {
  357. IOUtils.closeQuietly(in);
  358. }
  359. } else {
  360. //Fallback: Use the sRGB profile from the JRE (about 140KB)
  361. profile = ICC_Profile.getInstance(ColorSpace.CS_sRGB);
  362. }
  363. sRGBProfile.setColorSpace(profile, null);
  364. //Map sRGB as default RGB profile for DeviceRGB
  365. this.sRGBColorSpace = pdfDoc.getFactory().makeICCBasedColorSpace(
  366. null, "DefaultRGB", sRGBProfile);
  367. }
  368. private void addDefaultOutputProfile() throws IOException {
  369. if (this.outputProfile != null) {
  370. return;
  371. }
  372. ICC_Profile profile;
  373. InputStream in = null;
  374. if (this.outputProfileURI != null) {
  375. this.outputProfile = pdfDoc.getFactory().makePDFICCStream();
  376. Source src = userAgent.resolveURI(this.outputProfileURI);
  377. if (src == null) {
  378. throw new IOException("Output profile not found: " + this.outputProfileURI);
  379. }
  380. if (src instanceof StreamSource) {
  381. in = ((StreamSource)src).getInputStream();
  382. } else {
  383. in = new URL(src.getSystemId()).openStream();
  384. }
  385. try {
  386. profile = ICC_Profile.getInstance(in);
  387. } finally {
  388. IOUtils.closeQuietly(in);
  389. }
  390. this.outputProfile.setColorSpace(profile, null);
  391. } else {
  392. //Fall back to sRGB profile
  393. outputProfile = sRGBColorSpace.getICCStream();
  394. }
  395. }
  396. /**
  397. * Adds an OutputIntent to the PDF as mandated by PDF/A-1 when uncalibrated color spaces
  398. * are used (which is true if we use DeviceRGB to represent sRGB colors).
  399. * @throws IOException in case of an I/O problem
  400. */
  401. private void addPDFA1OutputIntent() throws IOException {
  402. addDefaultOutputProfile();
  403. String desc = ColorProfileUtil.getICCProfileDescription(this.outputProfile.getICCProfile());
  404. PDFOutputIntent outputIntent = pdfDoc.getFactory().makeOutputIntent();
  405. outputIntent.setSubtype(PDFOutputIntent.GTS_PDFA1);
  406. outputIntent.setDestOutputProfile(this.outputProfile);
  407. outputIntent.setOutputConditionIdentifier(desc);
  408. outputIntent.setInfo(outputIntent.getOutputConditionIdentifier());
  409. pdfDoc.getRoot().addOutputIntent(outputIntent);
  410. }
  411. /**
  412. * Adds an OutputIntent to the PDF as mandated by PDF/X when uncalibrated color spaces
  413. * are used (which is true if we use DeviceRGB to represent sRGB colors).
  414. * @throws IOException in case of an I/O problem
  415. */
  416. private void addPDFXOutputIntent() throws IOException {
  417. addDefaultOutputProfile();
  418. String desc = ColorProfileUtil.getICCProfileDescription(this.outputProfile.getICCProfile());
  419. int deviceClass = this.outputProfile.getICCProfile().getProfileClass();
  420. if (deviceClass != ICC_Profile.CLASS_OUTPUT) {
  421. throw new PDFConformanceException(pdfDoc.getProfile().getPDFXMode() + " requires that"
  422. + " the DestOutputProfile be an Output Device Profile. "
  423. + desc + " does not match that requirement.");
  424. }
  425. PDFOutputIntent outputIntent = pdfDoc.getFactory().makeOutputIntent();
  426. outputIntent.setSubtype(PDFOutputIntent.GTS_PDFX);
  427. outputIntent.setDestOutputProfile(this.outputProfile);
  428. outputIntent.setOutputConditionIdentifier(desc);
  429. outputIntent.setInfo(outputIntent.getOutputConditionIdentifier());
  430. pdfDoc.getRoot().addOutputIntent(outputIntent);
  431. }
  432. /**
  433. * Checks if there are any unfinished PDFGoTos left in the list and resolves them
  434. * to a default position on the page. Logs a warning, as this should not happen.
  435. */
  436. protected void finishOpenGoTos() {
  437. int count = unfinishedGoTos.size();
  438. if (count > 0) {
  439. // TODO : page height may not be the same for all targeted pages
  440. Point2D.Float defaultPos = new Point2D.Float(0f, pageHeight / 1000f); // top-o-page
  441. while (!unfinishedGoTos.isEmpty()) {
  442. PDFGoTo gt = (PDFGoTo) unfinishedGoTos.get(0);
  443. finishIDGoTo(gt, defaultPos);
  444. }
  445. boolean one = count == 1;
  446. String pl = one ? "" : "s";
  447. String ww = one ? "was" : "were";
  448. String ia = one ? "is" : "are";
  449. log.warn("" + count + " link target" + pl + " could not be fully resolved and "
  450. + ww + " now point to the top of the page or "
  451. + ia + " dysfunctional."); // dysfunctional if pageref is null
  452. }
  453. }
  454. /**
  455. * {@inheritDoc}
  456. */
  457. public void stopRenderer() throws IOException {
  458. finishOpenGoTos();
  459. pdfDoc.getResources().addFonts(pdfDoc, fontInfo);
  460. pdfDoc.outputTrailer(ostream);
  461. this.pdfDoc = null;
  462. ostream = null;
  463. pages = null;
  464. pageReferences.clear();
  465. pvReferences.clear();
  466. pdfResources = null;
  467. currentStream = null;
  468. currentContext = null;
  469. currentPage = null;
  470. currentState = null;
  471. currentFontName = "";
  472. idPositions.clear();
  473. idGoTos.clear();
  474. }
  475. /**
  476. * {@inheritDoc}
  477. */
  478. public boolean supportsOutOfOrder() {
  479. //return false;
  480. return true;
  481. }
  482. /**
  483. * {@inheritDoc}
  484. */
  485. public void processOffDocumentItem(OffDocumentItem odi) {
  486. if (odi instanceof DestinationData) {
  487. // render Destinations
  488. renderDestination((DestinationData) odi);
  489. } else if (odi instanceof BookmarkData) {
  490. // render Bookmark-Tree
  491. renderBookmarkTree((BookmarkData) odi);
  492. } else if (odi instanceof OffDocumentExtensionAttachment) {
  493. ExtensionAttachment attachment = ((OffDocumentExtensionAttachment)odi).getAttachment();
  494. if (XMPMetadata.CATEGORY.equals(attachment.getCategory())) {
  495. renderXMPMetadata((XMPMetadata)attachment);
  496. }
  497. }
  498. }
  499. private void renderDestination(DestinationData dd) {
  500. String targetID = dd.getIDRef();
  501. if (targetID != null && targetID.length() > 0) {
  502. PageViewport pv = dd.getPageViewport();
  503. if (pv == null) {
  504. log.warn("Unresolved destination item received: " + dd.getIDRef());
  505. }
  506. PDFGoTo gt = getPDFGoToForID(targetID, pv.getKey());
  507. pdfDoc.getFactory().makeDestination(
  508. dd.getIDRef(), gt.makeReference());
  509. } else {
  510. log.warn("DestinationData item with null or empty IDRef received.");
  511. }
  512. }
  513. /**
  514. * Renders a Bookmark-Tree object
  515. * @param bookmarks the BookmarkData object containing all the Bookmark-Items
  516. */
  517. protected void renderBookmarkTree(BookmarkData bookmarks) {
  518. for (int i = 0; i < bookmarks.getCount(); i++) {
  519. BookmarkData ext = bookmarks.getSubData(i);
  520. renderBookmarkItem(ext, null);
  521. }
  522. }
  523. private void renderBookmarkItem(BookmarkData bookmarkItem,
  524. PDFOutline parentBookmarkItem) {
  525. PDFOutline pdfOutline = null;
  526. String targetID = bookmarkItem.getIDRef();
  527. if (targetID != null && targetID.length() > 0) {
  528. PageViewport pv = bookmarkItem.getPageViewport();
  529. if (pv != null) {
  530. String pvKey = pv.getKey();
  531. PDFGoTo gt = getPDFGoToForID(targetID, pvKey);
  532. // create outline object:
  533. PDFOutline parent = parentBookmarkItem != null
  534. ? parentBookmarkItem
  535. : pdfDoc.getOutlineRoot();
  536. pdfOutline = pdfDoc.getFactory().makeOutline(parent,
  537. bookmarkItem.getBookmarkTitle(), gt, bookmarkItem.showChildItems());
  538. } else {
  539. log.warn("Bookmark with IDRef \"" + targetID + "\" has a null PageViewport.");
  540. }
  541. } else {
  542. log.warn("Bookmark item with null or empty IDRef received.");
  543. }
  544. for (int i = 0; i < bookmarkItem.getCount(); i++) {
  545. renderBookmarkItem(bookmarkItem.getSubData(i), pdfOutline);
  546. }
  547. }
  548. private void renderXMPMetadata(XMPMetadata metadata) {
  549. Metadata docXMP = metadata.getMetadata();
  550. Metadata fopXMP = PDFMetadata.createXMPFromUserAgent(pdfDoc);
  551. //Merge FOP's own metadata into the one from the XSL-FO document
  552. fopXMP.mergeInto(docXMP);
  553. XMPBasicAdapter xmpBasic = XMPBasicSchema.getAdapter(docXMP);
  554. //Metadata was changed so update metadata date
  555. xmpBasic.setMetadataDate(new java.util.Date());
  556. PDFMetadata.updateInfoFromMetadata(docXMP, pdfDoc.getInfo());
  557. PDFMetadata pdfMetadata = pdfDoc.getFactory().makeMetadata(
  558. docXMP, metadata.isReadOnly());
  559. pdfDoc.getRoot().setMetadata(pdfMetadata);
  560. }
  561. /** {@inheritDoc} */
  562. public Graphics2DAdapter getGraphics2DAdapter() {
  563. return new PDFGraphics2DAdapter(this);
  564. }
  565. /**
  566. * writes out a comment.
  567. * @param text text for the comment
  568. */
  569. protected void comment(String text) {
  570. if (WRITE_COMMENTS) {
  571. currentStream.add("% " + text + "\n");
  572. }
  573. }
  574. /** Saves the graphics state of the rendering engine. */
  575. protected void saveGraphicsState() {
  576. endTextObject();
  577. currentStream.add("q\n");
  578. }
  579. /** Restores the last graphics state of the rendering engine. */
  580. protected void restoreGraphicsState() {
  581. endTextObject();
  582. currentStream.add("Q\n");
  583. }
  584. /** Indicates the beginning of a text object. */
  585. protected void beginTextObject() {
  586. if (!inTextMode) {
  587. currentStream.add("BT\n");
  588. currentFontName = "";
  589. inTextMode = true;
  590. }
  591. }
  592. /** Indicates the end of a text object. */
  593. protected void endTextObject() {
  594. closeText();
  595. if (inTextMode) {
  596. currentStream.add("ET\n");
  597. inTextMode = false;
  598. }
  599. }
  600. /**
  601. * Start the next page sequence.
  602. * For the pdf renderer there is no concept of page sequences
  603. * but it uses the first available page sequence title to set
  604. * as the title of the pdf document.
  605. *
  606. * @param seqTitle the title of the page sequence
  607. */
  608. public void startPageSequence(LineArea seqTitle) {
  609. if (seqTitle != null) {
  610. String str = convertTitleToString(seqTitle);
  611. PDFInfo info = this.pdfDoc.getInfo();
  612. if (info.getTitle() == null) {
  613. info.setTitle(str);
  614. }
  615. }
  616. if (pdfDoc.getRoot().getMetadata() == null) {
  617. //If at this time no XMP metadata for the overall document has been set, create it
  618. //from the PDFInfo object.
  619. Metadata xmp = PDFMetadata.createXMPFromUserAgent(pdfDoc);
  620. PDFMetadata pdfMetadata = pdfDoc.getFactory().makeMetadata(
  621. xmp, true);
  622. pdfDoc.getRoot().setMetadata(pdfMetadata);
  623. }
  624. }
  625. /**
  626. * The pdf page is prepared by making the page.
  627. * The page is made in the pdf document without any contents
  628. * and then stored to add the contents later.
  629. * The page objects is stored using the area tree PageViewport
  630. * as a key.
  631. *
  632. * @param page the page to prepare
  633. */
  634. public void preparePage(PageViewport page) {
  635. setupPage(page);
  636. if (pages == null) {
  637. pages = new java.util.HashMap();
  638. }
  639. pages.put(page, currentPage);
  640. }
  641. private void setupPage(PageViewport page) {
  642. this.pdfResources = this.pdfDoc.getResources();
  643. Rectangle2D bounds = page.getViewArea();
  644. double w = bounds.getWidth();
  645. double h = bounds.getHeight();
  646. currentPage = this.pdfDoc.getFactory().makePage(
  647. this.pdfResources,
  648. (int) Math.round(w / 1000), (int) Math.round(h / 1000),
  649. page.getPageIndex());
  650. pageReferences.put(page.getKey(), currentPage.referencePDF());
  651. pvReferences.put(page.getKey(), page);
  652. //Produce page labels
  653. PDFPageLabels pageLabels = this.pdfDoc.getRoot().getPageLabels();
  654. if (pageLabels == null) {
  655. //Set up PageLabels
  656. pageLabels = this.pdfDoc.getFactory().makePageLabels();
  657. this.pdfDoc.getRoot().setPageLabels(pageLabels);
  658. }
  659. PDFNumsArray nums = pageLabels.getNums();
  660. PDFDictionary dict = new PDFDictionary(nums);
  661. dict.put("P", page.getPageNumberString());
  662. //TODO If the sequence of generated page numbers were inspected, this could be
  663. //expressed in a more space-efficient way
  664. nums.put(page.getPageIndex(), dict);
  665. }
  666. /**
  667. * This method creates a pdf stream for the current page
  668. * uses it as the contents of a new page. The page is written
  669. * immediately to the output stream.
  670. * {@inheritDoc}
  671. */
  672. public void renderPage(PageViewport page)
  673. throws IOException, FOPException {
  674. if (pages != null
  675. && (currentPage = (PDFPage) pages.get(page)) != null) {
  676. //Retrieve previously prepared page (out-of-line rendering)
  677. pages.remove(page);
  678. } else {
  679. setupPage(page);
  680. }
  681. currentPageRef = currentPage.referencePDF();
  682. Rectangle2D bounds = page.getViewArea();
  683. double h = bounds.getHeight();
  684. pageHeight = (int) h;
  685. currentStream = this.pdfDoc.getFactory()
  686. .makeStream(PDFFilterList.CONTENT_FILTER, false);
  687. currentState = new PDFState();
  688. // Transform the PDF's default coordinate system (0,0 at lower left) to the PDFRenderer's
  689. AffineTransform basicPageTransform = new AffineTransform(1, 0, 0, -1, 0,
  690. pageHeight / 1000f);
  691. currentState.concatenate(basicPageTransform);
  692. currentStream.add(CTMHelper.toPDFString(basicPageTransform, false) + " cm\n");
  693. currentFontName = "";
  694. super.renderPage(page);
  695. this.pdfDoc.registerObject(currentStream);
  696. currentPage.setContents(currentStream);
  697. PDFAnnotList annots = currentPage.getAnnotations();
  698. if (annots != null) {
  699. this.pdfDoc.addObject(annots);
  700. }
  701. this.pdfDoc.addObject(currentPage);
  702. this.pdfDoc.output(ostream);
  703. }
  704. /**
  705. * {@inheritDoc}
  706. */
  707. protected void startVParea(CTM ctm, Rectangle2D clippingRect) {
  708. // Set the given CTM in the graphics state
  709. currentState.push();
  710. currentState.concatenate(
  711. new AffineTransform(CTMHelper.toPDFArray(ctm)));
  712. saveGraphicsState();
  713. if (clippingRect != null) {
  714. clipRect((float)clippingRect.getX() / 1000f,
  715. (float)clippingRect.getY() / 1000f,
  716. (float)clippingRect.getWidth() / 1000f,
  717. (float)clippingRect.getHeight() / 1000f);
  718. }
  719. // multiply with current CTM
  720. currentStream.add(CTMHelper.toPDFString(ctm) + " cm\n");
  721. }
  722. /**
  723. * {@inheritDoc}
  724. */
  725. protected void endVParea() {
  726. restoreGraphicsState();
  727. currentState.pop();
  728. }
  729. /**
  730. * Handle the traits for a region
  731. * This is used to draw the traits for the given page region.
  732. * (See Sect. 6.4.1.2 of XSL-FO spec.)
  733. * @param region the RegionViewport whose region is to be drawn
  734. */
  735. protected void handleRegionTraits(RegionViewport region) {
  736. currentFontName = "";
  737. super.handleRegionTraits(region);
  738. }
  739. /**
  740. * Formats a float value (normally coordinates) as Strings.
  741. * @param value the value
  742. * @return the formatted value
  743. */
  744. protected static final String format(float value) {
  745. return PDFNumber.doubleOut(value);
  746. }
  747. /** {@inheritDoc} */
  748. protected void drawBorderLine(float x1, float y1, float x2, float y2,
  749. boolean horz, boolean startOrBefore, int style, Color col) {
  750. float w = x2 - x1;
  751. float h = y2 - y1;
  752. if ((w < 0) || (h < 0)) {
  753. log.error("Negative extent received (w=" + w + ", h=" + h + "). Border won't be painted.");
  754. return;
  755. }
  756. switch (style) {
  757. case Constants.EN_DASHED:
  758. setColor(col, false, null);
  759. if (horz) {
  760. float unit = Math.abs(2 * h);
  761. int rep = (int)(w / unit);
  762. if (rep % 2 == 0) {
  763. rep++;
  764. }
  765. unit = w / rep;
  766. currentStream.add("[" + format(unit) + "] 0 d ");
  767. currentStream.add(format(h) + " w\n");
  768. float ym = y1 + (h / 2);
  769. currentStream.add(format(x1) + " " + format(ym) + " m "
  770. + format(x2) + " " + format(ym) + " l S\n");
  771. } else {
  772. float unit = Math.abs(2 * w);
  773. int rep = (int)(h / unit);
  774. if (rep % 2 == 0) {
  775. rep++;
  776. }
  777. unit = h / rep;
  778. currentStream.add("[" + format(unit) + "] 0 d ");
  779. currentStream.add(format(w) + " w\n");
  780. float xm = x1 + (w / 2);
  781. currentStream.add(format(xm) + " " + format(y1) + " m "
  782. + format(xm) + " " + format(y2) + " l S\n");
  783. }
  784. break;
  785. case Constants.EN_DOTTED:
  786. setColor(col, false, null);
  787. currentStream.add("1 J ");
  788. if (horz) {
  789. float unit = Math.abs(2 * h);
  790. int rep = (int)(w / unit);
  791. if (rep % 2 == 0) {
  792. rep++;
  793. }
  794. unit = w / rep;
  795. currentStream.add("[0 " + format(unit) + "] 0 d ");
  796. currentStream.add(format(h) + " w\n");
  797. float ym = y1 + (h / 2);
  798. currentStream.add(format(x1) + " " + format(ym) + " m "
  799. + format(x2) + " " + format(ym) + " l S\n");
  800. } else {
  801. float unit = Math.abs(2 * w);
  802. int rep = (int)(h / unit);
  803. if (rep % 2 == 0) {
  804. rep++;
  805. }
  806. unit = h / rep;
  807. currentStream.add("[0 " + format(unit) + " ] 0 d ");
  808. currentStream.add(format(w) + " w\n");
  809. float xm = x1 + (w / 2);
  810. currentStream.add(format(xm) + " " + format(y1) + " m "
  811. + format(xm) + " " + format(y2) + " l S\n");
  812. }
  813. break;
  814. case Constants.EN_DOUBLE:
  815. setColor(col, false, null);
  816. currentStream.add("[] 0 d ");
  817. if (horz) {
  818. float h3 = h / 3;
  819. currentStream.add(format(h3) + " w\n");
  820. float ym1 = y1 + (h3 / 2);
  821. float ym2 = ym1 + h3 + h3;
  822. currentStream.add(format(x1) + " " + format(ym1) + " m "
  823. + format(x2) + " " + format(ym1) + " l S\n");
  824. currentStream.add(format(x1) + " " + format(ym2) + " m "
  825. + format(x2) + " " + format(ym2) + " l S\n");
  826. } else {
  827. float w3 = w / 3;
  828. currentStream.add(format(w3) + " w\n");
  829. float xm1 = x1 + (w3 / 2);
  830. float xm2 = xm1 + w3 + w3;
  831. currentStream.add(format(xm1) + " " + format(y1) + " m "
  832. + format(xm1) + " " + format(y2) + " l S\n");
  833. currentStream.add(format(xm2) + " " + format(y1) + " m "
  834. + format(xm2) + " " + format(y2) + " l S\n");
  835. }
  836. break;
  837. case Constants.EN_GROOVE:
  838. case Constants.EN_RIDGE:
  839. {
  840. float colFactor = (style == EN_GROOVE ? 0.4f : -0.4f);
  841. currentStream.add("[] 0 d ");
  842. if (horz) {
  843. Color uppercol = lightenColor(col, -colFactor);
  844. Color lowercol = lightenColor(col, colFactor);
  845. float h3 = h / 3;
  846. currentStream.add(format(h3) + " w\n");
  847. float ym1 = y1 + (h3 / 2);
  848. setColor(uppercol, false, null);
  849. currentStream.add(format(x1) + " " + format(ym1) + " m "
  850. + format(x2) + " " + format(ym1) + " l S\n");
  851. setColor(col, false, null);
  852. currentStream.add(format(x1) + " " + format(ym1 + h3) + " m "
  853. + format(x2) + " " + format(ym1 + h3) + " l S\n");
  854. setColor(lowercol, false, null);
  855. currentStream.add(format(x1) + " " + format(ym1 + h3 + h3) + " m "
  856. + format(x2) + " " + format(ym1 + h3 + h3) + " l S\n");
  857. } else {
  858. Color leftcol = lightenColor(col, -colFactor);
  859. Color rightcol = lightenColor(col, colFactor);
  860. float w3 = w / 3;
  861. currentStream.add(format(w3) + " w\n");
  862. float xm1 = x1 + (w3 / 2);
  863. setColor(leftcol, false, null);
  864. currentStream.add(format(xm1) + " " + format(y1) + " m "
  865. + format(xm1) + " " + format(y2) + " l S\n");
  866. setColor(col, false, null);
  867. currentStream.add(format(xm1 + w3) + " " + format(y1) + " m "
  868. + format(xm1 + w3) + " " + format(y2) + " l S\n");
  869. setColor(rightcol, false, null);
  870. currentStream.add(format(xm1 + w3 + w3) + " " + format(y1) + " m "
  871. + format(xm1 + w3 + w3) + " " + format(y2) + " l S\n");
  872. }
  873. break;
  874. }
  875. case Constants.EN_INSET:
  876. case Constants.EN_OUTSET:
  877. {
  878. float colFactor = (style == EN_OUTSET ? 0.4f : -0.4f);
  879. currentStream.add("[] 0 d ");
  880. Color c = col;
  881. if (horz) {
  882. c = lightenColor(c, (startOrBefore ? 1 : -1) * colFactor);
  883. currentStream.add(format(h) + " w\n");
  884. float ym1 = y1 + (h / 2);
  885. setColor(c, false, null);
  886. currentStream.add(format(x1) + " " + format(ym1) + " m "
  887. + format(x2) + " " + format(ym1) + " l S\n");
  888. } else {
  889. c = lightenColor(c, (startOrBefore ? 1 : -1) * colFactor);
  890. currentStream.add(format(w) + " w\n");
  891. float xm1 = x1 + (w / 2);
  892. setColor(c, false, null);
  893. currentStream.add(format(xm1) + " " + format(y1) + " m "
  894. + format(xm1) + " " + format(y2) + " l S\n");
  895. }
  896. break;
  897. }
  898. case Constants.EN_HIDDEN:
  899. break;
  900. default:
  901. setColor(col, false, null);
  902. currentStream.add("[] 0 d ");
  903. if (horz) {
  904. currentStream.add(format(h) + " w\n");
  905. float ym = y1 + (h / 2);
  906. currentStream.add(format(x1) + " " + format(ym) + " m "
  907. + format(x2) + " " + format(ym) + " l S\n");
  908. } else {
  909. currentStream.add(format(w) + " w\n");
  910. float xm = x1 + (w / 2);
  911. currentStream.add(format(xm) + " " + format(y1) + " m "
  912. + format(xm) + " " + format(y2) + " l S\n");
  913. }
  914. }
  915. }
  916. /**
  917. * Sets the current line width in points.
  918. * @param width line width in points
  919. */
  920. private void updateLineWidth(float width) {
  921. if (currentState.setLineWidth(width)) {
  922. //Only write if value has changed WRT the current line width
  923. currentStream.add(format(width) + " w\n");
  924. }
  925. }
  926. /**
  927. * Clip a rectangular area.
  928. * write a clipping operation given coordinates in the current
  929. * transform.
  930. * @param x the x coordinate
  931. * @param y the y coordinate
  932. * @param width the width of the area
  933. * @param height the height of the area
  934. */
  935. protected void clipRect(float x, float y, float width, float height) {
  936. currentStream.add(format(x) + " " + format(y) + " "
  937. + format(width) + " " + format(height) + " re ");
  938. clip();
  939. }
  940. /**
  941. * Clip an area.
  942. */
  943. protected void clip() {
  944. currentStream.add("W\n");
  945. currentStream.add("n\n");
  946. }
  947. /**
  948. * Moves the current point to (x, y), omitting any connecting line segment.
  949. * @param x x coordinate
  950. * @param y y coordinate
  951. */
  952. protected void moveTo(float x, float y) {
  953. currentStream.add(format(x) + " " + format(y) + " m ");
  954. }
  955. /**
  956. * Appends a straight line segment from the current point to (x, y). The
  957. * new current point is (x, y).
  958. * @param x x coordinate
  959. * @param y y coordinate
  960. */
  961. protected void lineTo(float x, float y) {
  962. currentStream.add(format(x) + " " + format(y) + " l ");
  963. }
  964. /**
  965. * Closes the current subpath by appending a straight line segment from
  966. * the current point to the starting point of the subpath.
  967. */
  968. protected void closePath() {
  969. currentStream.add("h ");
  970. }
  971. /**
  972. * {@inheritDoc}
  973. */
  974. protected void fillRect(float x, float y, float w, float h) {
  975. if (w != 0 && h != 0) {
  976. currentStream.add(format(x) + " " + format(y) + " "
  977. + format(w) + " " + format(h) + " re f\n");
  978. }
  979. }
  980. /**
  981. * Draw a line.
  982. *
  983. * @param startx the start x position
  984. * @param starty the start y position
  985. * @param endx the x end position
  986. * @param endy the y end position
  987. */
  988. private void drawLine(float startx, float starty, float endx, float endy) {
  989. currentStream.add(format(startx) + " " + format(starty) + " m ");
  990. currentStream.add(format(endx) + " " + format(endy) + " l S\n");
  991. }
  992. /**
  993. * Breaks out of the state stack to handle fixed block-containers.
  994. * @return the saved state stack to recreate later
  995. */
  996. protected List breakOutOfStateStack() {
  997. List breakOutList = new java.util.ArrayList();
  998. PDFState.Data data;
  999. while (true) {
  1000. data = currentState.getData();
  1001. if (currentState.pop() == null) {
  1002. break;
  1003. }
  1004. if (breakOutList.size() == 0) {
  1005. comment("------ break out!");
  1006. }
  1007. breakOutList.add(0, data); //Insert because of stack-popping
  1008. restoreGraphicsState();
  1009. }
  1010. return breakOutList;
  1011. }
  1012. /**
  1013. * Restores the state stack after a break out.
  1014. * @param breakOutList the state stack to restore.
  1015. */
  1016. protected void restoreStateStackAfterBreakOut(List breakOutList) {
  1017. CTM tempctm;
  1018. comment("------ restoring context after break-out...");
  1019. PDFState.Data data;
  1020. Iterator i = breakOutList.iterator();
  1021. double[] matrix = new double[6];
  1022. while (i.hasNext()) {
  1023. data = (PDFState.Data)i.next();
  1024. currentState.push();
  1025. saveGraphicsState();
  1026. AffineTransform at = data.getTransform();
  1027. if (!at.isIdentity()) {
  1028. currentState.concatenate(at);
  1029. at.getMatrix(matrix);
  1030. tempctm = new CTM(matrix[0], matrix[1], matrix[2], matrix[3],
  1031. matrix[4] * 1000, matrix[5] * 1000);
  1032. currentStream.add(CTMHelper.toPDFString(tempctm) + " cm\n");
  1033. }
  1034. //TODO Break-out: Also restore items such as line width and color
  1035. //Left out for now because all this painting stuff is very
  1036. //inconsistent. Some values go over PDFState, some don't.
  1037. }
  1038. comment("------ done.");
  1039. }
  1040. /**
  1041. * Returns area's id if it is the first area in the document with that id
  1042. * (i.e. if the area qualifies as a link target).
  1043. * Otherwise, or if the area has no id, null is returned.
  1044. *
  1045. * NOTE : area must be on currentPageViewport, otherwise result may be wrong!
  1046. *
  1047. * @param area the area for which to return the id
  1048. */
  1049. protected String getTargetableID(Area area) {
  1050. String id = (String) area.getTrait(Trait.PROD_ID);
  1051. if (id == null || id.length() == 0
  1052. || !currentPageViewport.isFirstWithID(id)
  1053. || idPositions.containsKey(id)) {
  1054. return null;
  1055. } else {
  1056. return id;
  1057. }
  1058. }
  1059. /**
  1060. * Set XY position in the PDFGoTo and add it to the PDF trailer.
  1061. *
  1062. * @param gt the PDFGoTo object
  1063. * @param position the X,Y position to set
  1064. */
  1065. protected void finishIDGoTo(PDFGoTo gt, Point2D.Float position) {
  1066. gt.setPosition(position);
  1067. pdfDoc.addTrailerObject(gt);
  1068. unfinishedGoTos.remove(gt);
  1069. }
  1070. /**
  1071. * Set page reference and XY position in the PDFGoTo and add it to the PDF trailer.
  1072. *
  1073. * @param gt the PDFGoTo object
  1074. * @param pdfPageRef the PDF reference string of the target page object
  1075. * @param position the X,Y position to set
  1076. */
  1077. protected void finishIDGoTo(PDFGoTo gt, String pdfPageRef, Point2D.Float position) {
  1078. gt.setPageReference(pdfPageRef);
  1079. finishIDGoTo(gt, position);
  1080. }
  1081. /**
  1082. * Get a PDFGoTo pointing to the given id. Create one if necessary.
  1083. * It is possible that the PDFGoTo is not fully resolved yet. In that case
  1084. * it must be completed (and added to the PDF trailer) later.
  1085. *
  1086. * @param targetID the target id of the PDFGoTo
  1087. * @param pvKey the unique key of the target PageViewport
  1088. *
  1089. * @return the PDFGoTo that was found or created
  1090. */
  1091. protected PDFGoTo getPDFGoToForID(String targetID, String pvKey) {
  1092. // Already a PDFGoTo present for this target? If not, create.
  1093. PDFGoTo gt = (PDFGoTo) idGoTos.get(targetID);
  1094. if (gt == null) {
  1095. String pdfPageRef = (String) pageReferences.get(pvKey);
  1096. Point2D.Float position = (Point2D.Float) idPositions.get(targetID);
  1097. // can the GoTo already be fully filled in?
  1098. if (pdfPageRef != null && position != null) {
  1099. // getPDFGoTo shares PDFGoTo objects as much as possible.
  1100. // It also takes care of assignObjectNumber and addTrailerObject.
  1101. gt = pdfDoc.getFactory().getPDFGoTo(pdfPageRef, position);
  1102. } else {
  1103. // Not complete yet, can't use getPDFGoTo:
  1104. gt = new PDFGoTo(pdfPageRef);
  1105. pdfDoc.assignObjectNumber(gt);
  1106. // pdfDoc.addTrailerObject() will be called later, from finishIDGoTo()
  1107. unfinishedGoTos.add(gt);
  1108. }
  1109. idGoTos.put(targetID, gt);
  1110. }
  1111. return gt;
  1112. }
  1113. /**
  1114. * Saves id's absolute position on page for later retrieval by PDFGoTos
  1115. *
  1116. * @param id the id of the area whose position must be saved
  1117. * @param pdfPageRef the PDF page reference string
  1118. * @param relativeIPP the *relative* IP position in millipoints
  1119. * @param relativeBPP the *relative* BP position in millipoints
  1120. * @param tf the transformation to apply once the relative positions have been
  1121. * converted to points
  1122. */
  1123. protected void saveAbsolutePosition(String id, String pdfPageRef,
  1124. int relativeIPP, int relativeBPP, AffineTransform tf) {
  1125. Point2D.Float position = new Point2D.Float(relativeIPP / 1000f, relativeBPP / 1000f);
  1126. tf.transform(position, position);
  1127. idPositions.put(id, position);
  1128. // is there already a PDFGoTo waiting to be completed?
  1129. PDFGoTo gt = (PDFGoTo) idGoTos.get(id);
  1130. if (gt != null) {
  1131. finishIDGoTo(gt, pdfPageRef, position);
  1132. }
  1133. /*
  1134. // The code below auto-creates a named destination for every id in the document.
  1135. // This should probably be controlled by a user-configurable setting, as it may
  1136. // make the PDF file grow noticeably.
  1137. // *** NOT YET WELL-TESTED ! ***
  1138. if (true) {
  1139. PDFFactory factory = pdfDoc.getFactory();
  1140. if (gt == null) {
  1141. gt = factory.getPDFGoTo(pdfPageRef, position);
  1142. idGoTos.put(id, gt); // so others can pick it up too
  1143. }
  1144. factory.makeDestination(id, gt.referencePDF(), currentPageViewport);
  1145. // Note: using currentPageViewport is only correct if the id is indeed on
  1146. // the current PageViewport. But even if incorrect, it won't interfere with
  1147. // what gets created in the PDF.
  1148. // For speedup, we should also create a lookup map id -> PDFDestination
  1149. }
  1150. */
  1151. }
  1152. /**
  1153. * Saves id's absolute position on page for later retrieval by PDFGoTos,
  1154. * using the currently valid transformation and the currently valid PDF page reference
  1155. *
  1156. * @param id the id of the area whose position must be saved
  1157. * @param relativeIPP the *relative* IP position in millipoints
  1158. * @param relativeBPP the *relative* BP position in millipoints
  1159. */
  1160. protected void saveAbsolutePosition(String id, int relativeIPP, int relativeBPP) {
  1161. saveAbsolutePosition(id, currentPageRef,
  1162. relativeIPP, relativeBPP, currentState.getTransform());
  1163. }
  1164. /**
  1165. * If the given block area is a possible link target, its id + absolute position will
  1166. * be saved. The saved position is only correct if this function is called at the very
  1167. * start of renderBlock!
  1168. *
  1169. * @param block the block area in question
  1170. */
  1171. protected void saveBlockPosIfTargetable(Block block) {
  1172. String id = getTargetableID(block);
  1173. if (id != null) {
  1174. // FIXME: Like elsewhere in the renderer code, absolute and relative
  1175. // directions are happily mixed here. This makes sure that the
  1176. // links point to the right location, but it is not correct.
  1177. int ipp = block.getXOffset();
  1178. int bpp = block.getYOffset() + block.getSpaceBefore();
  1179. int positioning = block.getPositioning();
  1180. if (!(positioning == Block.FIXED || positioning == Block.ABSOLUTE)) {
  1181. ipp += currentIPPosition;
  1182. bpp += currentBPPosition;
  1183. }
  1184. AffineTransform tf = positioning == Block.FIXED
  1185. ? currentState.getBaseTransform()
  1186. : currentState.getTransform();
  1187. saveAbsolutePosition(id, currentPageRef, ipp, bpp, tf);
  1188. }
  1189. }
  1190. /**
  1191. * If the given inline area is a possible link target, its id + absolute position will
  1192. * be saved. The saved position is only correct if this function is called at the very
  1193. * start of renderInlineArea!
  1194. *
  1195. * @param inlineArea the inline area in question
  1196. */
  1197. protected void saveInlinePosIfTargetable(InlineArea inlineArea) {
  1198. String id = getTargetableID(inlineArea);
  1199. if (id != null) {
  1200. int extraMarginBefore = 5000; // millipoints
  1201. int ipp = currentIPPosition;
  1202. int bpp = currentBPPosition + inlineArea.getOffset() - extraMarginBefore;
  1203. saveAbsolutePosition(id, ipp, bpp);
  1204. }
  1205. }
  1206. /**
  1207. * {@inheritDoc}
  1208. */
  1209. protected void renderBlock(Block block) {
  1210. saveBlockPosIfTargetable(block);
  1211. super.renderBlock(block);
  1212. }
  1213. /**
  1214. * {@inheritDoc}
  1215. */
  1216. protected void renderLineArea(LineArea line) {
  1217. super.renderLineArea(line);
  1218. closeText();
  1219. }
  1220. /**
  1221. * {@inheritDoc}
  1222. */
  1223. protected void renderInlineArea(InlineArea inlineArea) {
  1224. saveInlinePosIfTargetable(inlineArea);
  1225. super.renderInlineArea(inlineArea);
  1226. }
  1227. /**
  1228. * Render inline parent area.
  1229. * For pdf this handles the inline parent area traits such as
  1230. * links, border, background.
  1231. * @param ip the inline parent area
  1232. */
  1233. public void renderInlineParent(InlineParent ip) {
  1234. boolean annotsAllowed = pdfDoc.getProfile().isAnnotationAllowed();
  1235. // stuff we only need if a link must be created:
  1236. Rectangle2D ipRect = null;
  1237. PDFFactory factory = null;
  1238. PDFAction action = null;
  1239. if (annotsAllowed) {
  1240. // make sure the rect is determined *before* calling super!
  1241. int ipp = currentIPPosition;
  1242. int bpp = currentBPPosition + ip.getOffset();
  1243. ipRect = new Rectangle2D.Float(ipp / 1000f, bpp / 1000f,
  1244. ip.getIPD() / 1000f, ip.getBPD() / 1000f);
  1245. AffineTransform transform = currentState.getTransform();
  1246. ipRect = transform.createTransformedShape(ipRect).getBounds2D();
  1247. factory = pdfDoc.getFactory();
  1248. }
  1249. // render contents
  1250. super.renderInlineParent(ip);
  1251. boolean linkTraitFound = false;
  1252. // try INTERNAL_LINK first
  1253. Trait.InternalLink intLink = (Trait.InternalLink) ip.getTrait(Trait.INTERNAL_LINK);
  1254. if (intLink != null) {
  1255. linkTraitFound = true;
  1256. String pvKey = intLink.getPVKey();
  1257. String idRef = intLink.getIDRef();
  1258. boolean pvKeyOK = pvKey != null && pvKey.length() > 0;
  1259. boolean idRefOK = idRef != null && idRef.length() > 0;
  1260. if (pvKeyOK && idRefOK) {
  1261. if (annotsAllowed) {
  1262. action = getPDFGoToForID(idRef, pvKey);
  1263. }
  1264. } else if (pvKeyOK) {
  1265. log.warn("Internal link trait with PageViewport key " + pvKey
  1266. + " contains no ID reference.");
  1267. } else if (idRefOK) {
  1268. log.warn("Internal link trait with ID reference " + idRef
  1269. + " contains no PageViewport key.");
  1270. } else {
  1271. log.warn("Internal link trait received with neither PageViewport key"
  1272. + " nor ID reference.");
  1273. }
  1274. }
  1275. // no INTERNAL_LINK, look for EXTERNAL_LINK
  1276. if (!linkTraitFound) {
  1277. String extDest = (String) ip.getTrait(Trait.EXTERNAL_LINK);
  1278. if (extDest != null && extDest.length() > 0) {
  1279. linkTraitFound = true;
  1280. if (annotsAllowed) {
  1281. action = factory.getExternalAction(extDest);
  1282. }
  1283. }
  1284. }
  1285. // warn if link trait found but not allowed, else create link
  1286. if (linkTraitFound) {
  1287. if (!annotsAllowed) {
  1288. log.warn("Skipping annotation for a link due to PDF profile: "
  1289. + pdfDoc.getProfile());
  1290. } else if (action != null) {
  1291. PDFLink pdfLink = factory.makeLink(ipRect, action);
  1292. currentPage.addAnnotation(pdfLink);
  1293. }
  1294. }
  1295. }
  1296. /**
  1297. * {@inheritDoc}
  1298. */
  1299. public void renderText(TextArea text) {
  1300. renderInlineAreaBackAndBorders(text);
  1301. beginTextObject();
  1302. StringBuffer pdf = new StringBuffer();
  1303. String fontName = getInternalFontNameForArea(text);
  1304. int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue();
  1305. // This assumes that *all* CIDFonts use a /ToUnicode mapping
  1306. Typeface tf = (Typeface) fontInfo.getFonts().get(fontName);
  1307. boolean useMultiByte = tf.isMultiByte();
  1308. updateFont(fontName, size, pdf);
  1309. Color ct = (Color) text.getTrait(Trait.COLOR);
  1310. updateColor(ct, true, pdf);
  1311. // word.getOffset() = only height of text itself
  1312. // currentBlockIPPosition: 0 for beginning of line; nonzero
  1313. // where previous line area failed to take up entire allocated space
  1314. int rx = currentIPPosition + text.getBorderAndPaddingWidthStart();
  1315. int bl = currentBPPosition + text.getOffset() + text.getBaselineOffset();
  1316. pdf.append("1 0 0 -1 " + format(rx / 1000f) + " " + format(bl / 1000f) + " Tm "
  1317. /*+ format(text.getTextLetterSpaceAdjust() / 1000f) + " Tc\n"*/
  1318. /*+ format(text.getTextWordSpaceAdjust() / 1000f) + " Tw ["*/);
  1319. pdf.append("[");
  1320. currentStream.add(pdf.toString());
  1321. super.renderText(text);
  1322. currentStream.add("] TJ\n");
  1323. renderTextDecoration(tf, size, text, bl, rx);
  1324. }
  1325. /**
  1326. * {@inheritDoc}
  1327. */
  1328. public void renderWord(WordArea word) {
  1329. Font font = getFontFromArea(word.getParentArea());
  1330. Typeface tf = (Typeface) fontInfo.getFonts().get(font.getFontName());
  1331. boolean useMultiByte = tf.isMultiByte();
  1332. StringBuffer pdf = new StringBuffer();
  1333. String s = word.getWord();
  1334. escapeText(s, word.getLetterAdjustArray(),
  1335. font, (AbstractTextArea)word.getParentArea(), useMultiByte, pdf);
  1336. currentStream.add(pdf.toString());
  1337. super.renderWord(word);
  1338. }
  1339. /**
  1340. * {@inheritDoc}
  1341. */
  1342. public void renderSpace(SpaceArea space) {
  1343. Font font = getFontFromArea(space.getParentArea());
  1344. Typeface tf = (Typeface) fontInfo.getFonts().get(font.getFontName());
  1345. boolean useMultiByte = tf.isMultiByte();
  1346. String s = space.getSpace();
  1347. StringBuffer pdf = new StringBuffer();
  1348. AbstractTextArea textArea = (AbstractTextArea)space.getParentArea();
  1349. escapeText(s, null, font, textArea, useMultiByte, pdf);
  1350. if (space.isAdjustable()) {
  1351. int tws = -((TextArea) space.getParentArea()).getTextWordSpaceAdjust()
  1352. - 2 * textArea.getTextLetterSpaceAdjust();
  1353. if (tws != 0) {
  1354. pdf.append(format(tws / (font.getFontSize() / 1000f)));
  1355. pdf.append(" ");
  1356. }
  1357. }
  1358. currentStream.add(pdf.toString());
  1359. super.renderSpace(space);
  1360. }
  1361. /**
  1362. * Escapes text according to PDF rules.
  1363. * @param s Text to escape
  1364. * @param letterAdjust an array of widths for letter adjustment (may be null)
  1365. * @param fs Font state
  1366. * @param parentArea the parent text area to retrieve certain traits from
  1367. * @param useMultiByte Indicates the use of multi byte convention
  1368. * @param pdf target buffer for the escaped text
  1369. */
  1370. public void escapeText(String s, int[] letterAdjust,
  1371. Font fs, AbstractTextArea parentArea,
  1372. boolean useMultiByte, StringBuffer pdf) {
  1373. String startText = useMultiByte ? "<" : "(";
  1374. String endText = useMultiByte ? "> " : ") ";
  1375. /*
  1376. boolean kerningAvailable = false;
  1377. Map kerning = fs.getKerning();
  1378. if (kerning != null && !kerning.isEmpty()) {
  1379. //kerningAvailable = true;
  1380. //TODO Reenable me when the layout engine supports kerning, too
  1381. log.warn("Kerning support is disabled until it is supported by the layout engine!");
  1382. }
  1383. */
  1384. int l = s.length();
  1385. float fontSize = fs.getFontSize() / 1000f;
  1386. boolean startPending = true;
  1387. for (int i = 0; i < l; i++) {
  1388. char orgChar = s.charAt(i);
  1389. char ch;
  1390. float glyphAdjust = 0;
  1391. if (fs.hasChar(orgChar)) {
  1392. ch = fs.mapChar(orgChar);
  1393. int tls = (i < l - 1 ? parentArea.getTextLetterSpaceAdjust() : 0);
  1394. glyphAdjust -= tls;
  1395. } else {
  1396. if (CharUtilities.isFixedWidthSpace(orgChar)) {
  1397. //Fixed width space are rendered as spaces so copy/paste works in a reader
  1398. ch = fs.mapChar(CharUtilities.SPACE);
  1399. glyphAdjust = fs.getCharWidth(ch) - fs.getCharWidth(orgChar);
  1400. } else {
  1401. ch = fs.mapChar(orgChar);
  1402. }
  1403. }
  1404. if (letterAdjust != null && i < l - 1) {
  1405. glyphAdjust -= letterAdjust[i + 1];
  1406. }
  1407. if (startPending) {
  1408. pdf.append(startText);
  1409. startPending = false;
  1410. }
  1411. if (!useMultiByte) {
  1412. if (ch > 127) {
  1413. pdf.append("\\");
  1414. pdf.append(Integer.toOctalString((int) ch));
  1415. } else {
  1416. switch (ch) {
  1417. case '(':
  1418. case ')':
  1419. case '\\':
  1420. pdf.append("\\");
  1421. break;
  1422. default:
  1423. }
  1424. pdf.append(ch);
  1425. }
  1426. } else {
  1427. pdf.append(PDFText.toUnicodeHex(ch));
  1428. }
  1429. float adjust = glyphAdjust / fontSize;
  1430. if (adjust != 0) {
  1431. pdf.append(endText).append(format(adjust)).append(' ');
  1432. startPending = true;
  1433. }
  1434. }
  1435. if (!startPending) {
  1436. pdf.append(endText);
  1437. }
  1438. }
  1439. /**
  1440. * Checks to see if we have some text rendering commands open
  1441. * still and writes out the TJ command to the stream if we do
  1442. */
  1443. protected void closeText() {
  1444. /*
  1445. if (textOpen) {
  1446. currentStream.add("] TJ\n");
  1447. textOpen = false;
  1448. prevWordX = 0;
  1449. prevWordY = 0;
  1450. currentFontName = "";
  1451. }*/
  1452. }
  1453. /**
  1454. * Establishes a new foreground or fill color. In contrast to updateColor
  1455. * this method does not check the PDFState for optimization possibilities.
  1456. * @param col the color to apply
  1457. * @param fill true to set the fill color, false for the foreground color
  1458. * @param pdf StringBuffer to write the PDF code to, if null, the code is
  1459. * written to the current stream.
  1460. */
  1461. protected void setColor(Color col, boolean fill, StringBuffer pdf) {
  1462. PDFColor color = new PDFColor(this.pdfDoc, col);
  1463. closeText();
  1464. if (pdf != null) {
  1465. pdf.append(color.getColorSpaceOut(fill));
  1466. } else {
  1467. currentStream.add(color.getColorSpaceOut(fill));
  1468. }
  1469. }
  1470. /**
  1471. * Establishes a new foreground or fill color.
  1472. * @param col the color to apply (null skips this operation)
  1473. * @param fill true to set the fill color, false for the foreground color
  1474. * @param pdf StringBuffer to write the PDF code to, if null, the code is
  1475. * written to the current stream.
  1476. */
  1477. private void updateColor(Color col, boolean fill, StringBuffer pdf) {
  1478. if (col == null) {
  1479. return;
  1480. }
  1481. boolean update = false;
  1482. if (fill) {
  1483. update = currentState.setBackColor(col);
  1484. } else {
  1485. update = currentState.setColor(col);
  1486. }
  1487. if (update) {
  1488. setColor(col, fill, pdf);
  1489. }
  1490. }
  1491. /** {@inheritDoc} */
  1492. protected void updateColor(Color col, boolean fill) {
  1493. updateColor(col, fill, null);
  1494. }
  1495. private void updateFont(String name, int size, StringBuffer pdf) {
  1496. if ((!name.equals(this.currentFontName))
  1497. || (size != this.currentFontSize)) {
  1498. closeText();
  1499. this.currentFontName = name;
  1500. this.currentFontSize = size;
  1501. pdf = pdf.append("/" + name + " " + format((float) size / 1000f)
  1502. + " Tf\n");
  1503. }
  1504. }
  1505. /** {@inheritDoc} */
  1506. public void renderImage(Image image, Rectangle2D pos) {
  1507. endTextObject();
  1508. String url = image.getURL();
  1509. putImage(url, pos, image.getForeignAttributes());
  1510. }
  1511. /** {@inheritDoc} */
  1512. protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) {
  1513. endTextObject();
  1514. putImage(url, pos, foreignAttributes);
  1515. }
  1516. /**
  1517. * Adds a PDF XObject (a bitmap or form) to the PDF that will later be referenced.
  1518. * @param uri URL of the bitmap
  1519. * @param pos Position of the bitmap
  1520. * @deprecated Use {@link @putImage(String, Rectangle2D, Map)} instead.
  1521. */
  1522. protected void putImage(String uri, Rectangle2D pos) {
  1523. putImage(uri, pos, null);
  1524. }
  1525. /**
  1526. * Adds a PDF XObject (a bitmap or form) to the PDF that will later be referenced.
  1527. * @param uri URL of the bitmap
  1528. * @param pos Position of the bitmap
  1529. * @param foreignAttributes foreign attributes associated with the image
  1530. */
  1531. protected void putImage(String uri, Rectangle2D pos, Map foreignAttributes) {
  1532. Rectangle posInt = new Rectangle(
  1533. (int)pos.getX(),
  1534. (int)pos.getY(),
  1535. (int)pos.getWidth(),
  1536. (int)pos.getHeight());
  1537. uri = URISpecification.getURL(uri);
  1538. PDFXObject xobject = pdfDoc.getXObject(uri);
  1539. if (xobject != null) {
  1540. float w = (float) pos.getWidth() / 1000f;
  1541. float h = (float) pos.getHeight() / 1000f;
  1542. placeImage((float)pos.getX() / 1000f,
  1543. (float)pos.getY() / 1000f, w, h, xobject);
  1544. return;
  1545. }
  1546. Point origin = new Point(currentIPPosition, currentBPPosition);
  1547. int x = origin.x + posInt.x;
  1548. int y = origin.y + posInt.y;
  1549. ImageManager manager = getUserAgent().getFactory().getImageManager();
  1550. ImageInfo info = null;
  1551. try {
  1552. ImageSessionContext sessionContext = getUserAgent().getImageSessionContext();
  1553. info = manager.getImageInfo(uri, sessionContext);
  1554. Map hints = ImageUtil.getDefaultHints(sessionContext);
  1555. org.apache.xmlgraphics.image.loader.Image img = manager.getImage(
  1556. info, imageHandlerRegistry.getSupportedFlavors(), hints, sessionContext);
  1557. //First check for a dynamically registered handler
  1558. PDFImageHandler handler = imageHandlerRegistry.getHandler(img.getClass());
  1559. if (handler != null) {
  1560. if (log.isDebugEnabled()) {
  1561. log.debug("Using PDFImageHandler: " + handler.getClass().getName());
  1562. }
  1563. try {
  1564. RendererContext context = createRendererContext(
  1565. x, y, posInt.width, posInt.height, foreignAttributes);
  1566. handler.generateImage(context, img, origin, posInt);
  1567. } catch (IOException ioe) {
  1568. log.error("I/O error while handling image: " + info, ioe);
  1569. return;
  1570. }
  1571. } else {
  1572. throw new UnsupportedOperationException(
  1573. "No PDFImageHandler available for image: "
  1574. + info + " (" + img.getClass().getName() + ")");
  1575. }
  1576. } catch (ImageException ie) {
  1577. log.error("Error while processing image: "
  1578. + (info != null ? info.toString() : uri), ie);
  1579. } catch (IOException ioe) {
  1580. log.error("I/O error while processing image: "
  1581. + (info != null ? info.toString() : uri), ioe);
  1582. }
  1583. // output new data
  1584. try {
  1585. this.pdfDoc.output(ostream);
  1586. } catch (IOException ioe) {
  1587. // ioexception will be caught later
  1588. }
  1589. }
  1590. /**
  1591. * Places a previously registered image at a certain place on the page.
  1592. * @param x X coordinate
  1593. * @param y Y coordinate
  1594. * @param w width for image
  1595. * @param h height for image
  1596. * @param xobj the image XObject
  1597. */
  1598. public void placeImage(float x, float y, float w, float h, PDFXObject xobj) {
  1599. saveGraphicsState();
  1600. currentStream.add(format(w) + " 0 0 "
  1601. + format(-h) + " "
  1602. + format(currentIPPosition / 1000f + x) + " "
  1603. + format(currentBPPosition / 1000f + h + y)
  1604. + " cm\n" + xobj.getName() + " Do\n");
  1605. restoreGraphicsState();
  1606. }
  1607. /** {@inheritDoc} */
  1608. protected RendererContext createRendererContext(int x, int y, int width, int height,
  1609. Map foreignAttributes) {
  1610. RendererContext context = super.createRendererContext(
  1611. x, y, width, height, foreignAttributes);
  1612. context.setProperty(PDFRendererContextConstants.PDF_DOCUMENT, pdfDoc);
  1613. context.setProperty(PDFRendererContextConstants.OUTPUT_STREAM, ostream);
  1614. context.setProperty(PDFRendererContextConstants.PDF_STATE, currentState);
  1615. context.setProperty(PDFRendererContextConstants.PDF_PAGE, currentPage);
  1616. context.setProperty(PDFRendererContextConstants.PDF_CONTEXT,
  1617. currentContext == null ? currentPage : currentContext);
  1618. context.setProperty(PDFRendererContextConstants.PDF_CONTEXT, currentContext);
  1619. context.setProperty(PDFRendererContextConstants.PDF_STREAM, currentStream);
  1620. context.setProperty(PDFRendererContextConstants.PDF_FONT_INFO, fontInfo);
  1621. context.setProperty(PDFRendererContextConstants.PDF_FONT_NAME, currentFontName);
  1622. context.setProperty(PDFRendererContextConstants.PDF_FONT_SIZE,
  1623. new Integer(currentFontSize));
  1624. return context;
  1625. }
  1626. /**
  1627. * Render leader area.
  1628. * This renders a leader area which is an area with a rule.
  1629. * @param area the leader area to render
  1630. */
  1631. public void renderLeader(Leader area) {
  1632. renderInlineAreaBackAndBorders(area);
  1633. currentState.push();
  1634. saveGraphicsState();
  1635. int style = area.getRuleStyle();
  1636. float startx = (currentIPPosition + area.getBorderAndPaddingWidthStart()) / 1000f;
  1637. float starty = (currentBPPosition + area.getOffset()) / 1000f;
  1638. float endx = (currentIPPosition + area.getBorderAndPaddingWidthStart()
  1639. + area.getIPD()) / 1000f;
  1640. float ruleThickness = area.getRuleThickness() / 1000f;
  1641. Color col = (Color)area.getTrait(Trait.COLOR);
  1642. switch (style) {
  1643. case EN_SOLID:
  1644. case EN_DASHED:
  1645. case EN_DOUBLE:
  1646. drawBorderLine(startx, starty, endx, starty + ruleThickness,
  1647. true, true, style, col);
  1648. break;
  1649. case EN_DOTTED:
  1650. clipRect(startx, starty, endx - startx, ruleThickness);
  1651. //This displaces the dots to the right by half a dot's width
  1652. //TODO There's room for improvement here
  1653. currentStream.add("1 0 0 1 " + format(ruleThickness / 2) + " 0 cm\n");
  1654. drawBorderLine(startx, starty, endx, starty + ruleThickness,
  1655. true, true, style, col);
  1656. break;
  1657. case EN_GROOVE:
  1658. case EN_RIDGE:
  1659. float half = area.getRuleThickness() / 2000f;
  1660. setColor(lightenColor(col, 0.6f), true, null);
  1661. currentStream.add(format(startx) + " " + format(starty) + " m\n");
  1662. currentStream.add(format(endx) + " " + format(starty) + " l\n");
  1663. currentStream.add(format(endx) + " " + format(starty + 2 * half) + " l\n");
  1664. currentStream.add(format(startx) + " " + format(starty + 2 * half) + " l\n");
  1665. currentStream.add("h\n");
  1666. currentStream.add("f\n");
  1667. setColor(col, true, null);
  1668. if (style == EN_GROOVE) {
  1669. currentStream.add(format(startx) + " " + format(starty) + " m\n");
  1670. currentStream.add(format(endx) + " " + format(starty) + " l\n");
  1671. currentStream.add(format(endx) + " " + format(starty + half) + " l\n");
  1672. currentStream.add(format(startx + half) + " " + format(starty + half) + " l\n");
  1673. currentStream.add(format(startx) + " " + format(starty + 2 * half) + " l\n");
  1674. } else {
  1675. currentStream.add(format(endx) + " " + format(starty) + " m\n");
  1676. currentStream.add(format(endx) + " " + format(starty + 2 * half) + " l\n");
  1677. currentStream.add(format(startx) + " " + format(starty + 2 * half) + " l\n");
  1678. currentStream.add(format(startx) + " " + format(starty + half) + " l\n");
  1679. currentStream.add(format(endx - half) + " " + format(starty + half) + " l\n");
  1680. }
  1681. currentStream.add("h\n");
  1682. currentStream.add("f\n");
  1683. break;
  1684. default:
  1685. throw new UnsupportedOperationException("rule style not supported");
  1686. }
  1687. restoreGraphicsState();
  1688. currentState.pop();
  1689. beginTextObject();
  1690. super.renderLeader(area);
  1691. }
  1692. /** {@inheritDoc} */
  1693. public String getMimeType() {
  1694. return MIME_TYPE;
  1695. }
  1696. public void setAMode(PDFAMode mode) {
  1697. this.pdfAMode = mode;
  1698. }
  1699. public void setXMode(PDFXMode mode) {
  1700. this.pdfXMode = mode;
  1701. }
  1702. public void setOutputProfileURI(String outputProfileURI) {
  1703. this.outputProfileURI = outputProfileURI;
  1704. }
  1705. public void setFilterMap(Map filterMap) {
  1706. this.filterMap = filterMap;
  1707. }
  1708. }