aboutsummaryrefslogtreecommitdiffstats
path: root/src/java
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2008-01-11 19:50:53 +0000
committerJeremias Maerki <jeremias@apache.org>2008-01-11 19:50:53 +0000
commit44c5761c1a801f4b6ae91ae7afb8006e8bb9c7fe (patch)
tree9371198cf7c65d77ec225b9327de3db7d1fc98ca /src/java
parent2a63d91286fdb6735d859a851d8237ef631d01be (diff)
downloadxmlgraphics-fop-44c5761c1a801f4b6ae91ae7afb8006e8bb9c7fe.tar.gz
xmlgraphics-fop-44c5761c1a801f4b6ae91ae7afb8006e8bb9c7fe.zip
Merged branch https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ImagePackageRedesign (revs 594558 to 611138) into Trunk:
A new image loading framework has been introduced to fix various problems with external graphics and improve performance. Switched to Batik 1.7. Added xml-apis-ext.jar as needed by Batik 1.7. Updated to latest XML Graphics Commons snapshot. Changelog of branch: ------------------------------------------------------------------------ r594558 | jeremias | 2007-11-13 16:04:56 +0100 (Di, 13 Nov 2007) | 1 line Branch for image package redesign ------------------------------------------------------------------------ r594560 | jeremias | 2007-11-13 16:10:35 +0100 (Di, 13 Nov 2007) | 1 line Implementation of Dijkstra's algorithm for finding the shortest path. Used in the new image package to find the best combination of image loaders and image converters to provide an image in the optimal form for a renderer. ------------------------------------------------------------------------ r594848 | jeremias | 2007-11-14 13:12:50 +0100 (Mi, 14 Nov 2007) | 3 lines Initial upload of what I have already for the image package redesign. For now, it's in a parallel package (image2). The final package name is TBD. The code isn't hooked into the renderers, yet, and there's no image cache. This is still all work in progress. ------------------------------------------------------------------------ r594851 | jeremias | 2007-11-14 13:20:12 +0100 (Mi, 14 Nov 2007) | 1 line Test cases and additional test files for the new image package. ------------------------------------------------------------------------ r595305 | jeremias | 2007-11-15 15:01:37 +0100 (Do, 15 Nov 2007) | 1 line Small mistake while reimplementing JPEG. ------------------------------------------------------------------------ r595308 | jeremias | 2007-11-15 15:13:36 +0100 (Do, 15 Nov 2007) | 5 lines Introduced a usage penalty for ImageLoaders so we can calculate an overall penalty for a pipeline. Multiple image flavors can be passed to ImageManager.getImage() if the caller supports multiple formats. The image package chooses the best pipeline. Implemented a converter from RenderedImage to PNG. Implemented loaders for raw formats (EMF, JPEG and PNG). Hooked the new image package into the RTF handler as first real proof-of-concept. ------------------------------------------------------------------------ r596240 | jeremias | 2007-11-19 11:02:13 +0100 (Mo, 19 Nov 2007) | 1 line Fixed bug in pipeline selection. ------------------------------------------------------------------------ r596242 | jeremias | 2007-11-19 11:03:06 +0100 (Mo, 19 Nov 2007) | 1 line MIME type in parentheses behind the URI makes more sense. ------------------------------------------------------------------------ r599430 | jeremias | 2007-11-29 14:08:01 +0100 (Do, 29 Nov 2007) | 1 line Support for baseline information (needed by at least MathML). ------------------------------------------------------------------------ r599433 | jeremias | 2007-11-29 14:09:04 +0100 (Do, 29 Nov 2007) | 1 line Bugfix: BMP don't all have resolution information. ------------------------------------------------------------------------ r599434 | jeremias | 2007-11-29 14:10:54 +0100 (Do, 29 Nov 2007) | 1 line Change MIME type ------------------------------------------------------------------------ r599436 | jeremias | 2007-11-29 14:17:14 +0100 (Do, 29 Nov 2007) | 3 lines Started integrating into Java2D and PostScript renderers and ExternalGraphic. Added support for EPS graphics. Added support for raw embedding of JPEG images (for PostScript). ------------------------------------------------------------------------ r600821 | jeremias | 2007-12-04 08:51:06 +0100 (Di, 04 Dez 2007) | 5 lines Clean up Javadocs Generally make more useful. Reuse FOProcessor instance for the whole run to actually feel the effect of an image cache attached to the FopFactory. Add option to prompt the user before actually starting (in order to connect a VM monitor). ------------------------------------------------------------------------ r600870 | jeremias | 2007-12-04 11:27:51 +0100 (Di, 04 Dez 2007) | 14 lines Note: The API of the new image package has changed a bit. (it became necessary when I introduced caching) The direct dependency on FOUserAgent has been removed to make the image package more universally usable. Instead an ImageContext (provided by FopFactory in FOP) and ImageSessionContext (provided by FOUserAgent in FOP) was introduced. Introduced image caching with soft references (I didn't reintroduce the FOUserAgent lock, yet, because it doesn't help much) ImageInfo doesn't carry the Source for the image anymore. The Source is provided by the new ImageSessionContext.java and only shared within the same thread to make things simpler and to avoid complex synchronization and cleanup. Image instances now indicate whether they are cacheable (not all Image instances are cacheable, for example when they just carry an InputStream). Moved the converter pipeline functionality into its own subpackage to keep "spi" clean. Added checks in ImageSize to detect incomplete Preloaders. ImageSource can now indicate whether its a fast source (loading from local file) or a slow source (loading over the network). (but this isn't used, yet) Fixed a bug in WMF and SVG preloaders: they didn't close their Sources after fully loading the images. Bugfix in ImageRawJPEG: it illegally reported being an EPS file ImageRawStream got an "InputStreamFactory" so it is possible to reuse raw images if they have been loaded into memory (or to a local file which hasn't been implemented, yet). The pipeline code now converts single-use raw images to reusable raw images when possible. But there's nothing built in to restrict the image size to a maximum, yet. Improved JPEG preloader so it can stop early an deal with images that have to APP0 segment. Images from digicams are such an example. They carry the resolution info in the EXIF block which is currently not interpreted. Fallback is to the configured source resolution. ------------------------------------------------------------------------ r600930 | jeremias | 2007-12-04 14:25:43 +0100 (Di, 04 Dez 2007) | 1 line Package HTML Files. ------------------------------------------------------------------------ r600934 | jeremias | 2007-12-04 14:34:41 +0100 (Di, 04 Dez 2007) | 1 line Javadoc fixes ------------------------------------------------------------------------ r602023 | jeremias | 2007-12-07 09:46:56 +0100 (Fr, 07 Dez 2007) | 2 lines Bugfix for bug in SVG preloader which didn't calculate the size of an SVG correctly when there's no explicit size. ------------------------------------------------------------------------ r602024 | jeremias | 2007-12-07 09:49:49 +0100 (Fr, 07 Dez 2007) | 1 line Some small javadoc and logging improvements/refinements. ------------------------------------------------------------------------ r602025 | jeremias | 2007-12-07 09:50:22 +0100 (Fr, 07 Dez 2007) | 1 line Enable assert keyword for javadoc production. ------------------------------------------------------------------------ r602032 | jeremias | 2007-12-07 09:59:10 +0100 (Fr, 07 Dez 2007) | 11 lines Added color space information and an optional ICC color profile to the basic Image interface. Reimplemented transparency support (for now only for ImageIO loader and PDF output) ImageIO preloader passes the already loaded metadata to the ImageIO loader through the "custom objects" so it doesn't have to load them again. PDF library: Corrected the naming of the method indicating the "bits per component" (bits per component != bits per pixel) PDF library: Added a method which lets a user override values in an XObject's dictionary after the major values have been set (useful not to make the PDFImage interface more complicated). PDF library: Support for gray transparent colors. PDF library: Added a convenience class for alpha channel bitmaps (AlphaRasterImage) Integration of the new image package into the PDFRenderer (currently supports all previous embedding methods except deprecated EPS embedding and CCITT embedding, now supports even more transparency options than before) ------------------------------------------------------------------------ r602033 | jeremias | 2007-12-07 09:59:57 +0100 (Fr, 07 Dez 2007) | 1 line Small optimization from my failed experiments to support native PNG embedding. ------------------------------------------------------------------------ r602034 | jeremias | 2007-12-07 10:01:34 +0100 (Fr, 07 Dez 2007) | 1 line Don't use "content" filter for ICC profiles. Instead compress using "default". "content" is for page content. ------------------------------------------------------------------------ r602036 | jeremias | 2007-12-07 10:02:25 +0100 (Fr, 07 Dez 2007) | 1 line Added general key for precompressed content of any kind. ------------------------------------------------------------------------ r602037 | jeremias | 2007-12-07 10:03:39 +0100 (Fr, 07 Dez 2007) | 1 line Various variants of the FOP logo for testing. Some of them have transparency info. ------------------------------------------------------------------------ r602228 | jeremias | 2007-12-07 22:30:17 +0100 (Fr, 07 Dez 2007) | 4 lines Discarded PreloaderPNG in favor of PreloaderImageIO which now supports all formats supported by ImageIO (meaning that you can uses JPEG-2000 images if you have a suitable ImageIO codec installed). ImagePreloader.getMimeType() removed because it isn't really used in the new setup. ImagePreloader.getPriority() introduced which allows to prioritize preloaders and thus gives the opportunity to tweak the order in which the preloaders are checked when an image is inspected. ImageLoaderImageIO can now use multiple Readers if one fails (one codec may not support all format variants, for example). ------------------------------------------------------------------------ r602229 | jeremias | 2007-12-07 22:30:48 +0100 (Fr, 07 Dez 2007) | 1 line Added a toString() impl for debugging. ------------------------------------------------------------------------ r602442 | jeremias | 2007-12-08 11:36:32 +0100 (Sa, 08 Dez 2007) | 6 lines Support handling images with no associated URI (from instream-foreign-object). These images are not cached. Add support for plain image conversion (i.e. with no loading) for instream-foreign-object. Add convenience writeTo() methods in ImageRawStream to save a few lines of code. Support for instream-foreign-object in RTF output. Teach RTF library to handle images without an associated URL. ------------------------------------------------------------------------ r603191 | jeremias | 2007-12-11 11:03:32 +0100 (Di, 11 Dez 2007) | 2 lines Bugfix: Graphics2DAdapter didn't do the graphics state save correct so subsequent images may have been painted with the wrong transformation matrix. Bugfix: bitmap images didn't scale correctly when the resolutions were changed. ------------------------------------------------------------------------ r603207 | jeremias | 2007-12-11 12:08:36 +0100 (Di, 11 Dez 2007) | 1 line Convenience method for obtaining the image size in points. ------------------------------------------------------------------------ r603208 | jeremias | 2007-12-11 12:12:50 +0100 (Di, 11 Dez 2007) | 3 lines Precisely define the expectations for the area parameter in Graphics2DImagePainter. New ImageConverter: Bitmap -> Graphics2D ------------------------------------------------------------------------ r603209 | jeremias | 2007-12-11 12:15:49 +0100 (Di, 11 Dez 2007) | 3 lines Refine pipeline building: Expose a method to allow the PS Renderer to predict what kind of pipeline will be selected (because it doesn't support all image types as PostScript forms) If there are multiple candidate pipelines for one conversion type, choose the one with the lowest penalty, not just the one that happens to be first. ------------------------------------------------------------------------ r603250 | jeremias | 2007-12-11 15:17:32 +0100 (Di, 11 Dez 2007) | 1 line Removing failed experiment: raw PNG embedding didn't work out. ------------------------------------------------------------------------ r603254 | jeremias | 2007-12-11 15:29:48 +0100 (Di, 11 Dez 2007) | 2 lines Plugged new image package into form generation for PostScript. XML images and EPS files are currently supported as forms. They are added inline. ------------------------------------------------------------------------ r603256 | jeremias | 2007-12-11 15:34:52 +0100 (Di, 11 Dez 2007) | 1 line Embedding EPS in PDF is no longer implemented as it is a deprecated feature in PDF. Therefore, this test is not needed anymore. The PDF renderer will say: "Cannot load image (no suitable loader/converter combination available) for myfile.eps (application/postscript)" ------------------------------------------------------------------------ r603266 | jeremias | 2007-12-11 16:16:22 +0100 (Di, 11 Dez 2007) | 1 line Size calculation for images can be slightly different after the redesign due to different rounding. Give a little tolerance. ------------------------------------------------------------------------ r603271 | jeremias | 2007-12-11 16:24:08 +0100 (Di, 11 Dez 2007) | 1 line Bugfix: Only generate the FixedLength if there is baseline information. ------------------------------------------------------------------------ r603358 | jeremias | 2007-12-11 22:13:22 +0100 (Di, 11 Dez 2007) | 1 line Switched background images to new image package. ------------------------------------------------------------------------ r603632 | jeremias | 2007-12-12 15:52:09 +0100 (Mi, 12 Dez 2007) | 1 line Switch to new image package for PDF/SVG support. ------------------------------------------------------------------------ r603642 | jeremias | 2007-12-12 16:30:16 +0100 (Mi, 12 Dez 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-594557" from https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk ------------------------------------------------------------------------ r603656 | jeremias | 2007-12-12 17:13:06 +0100 (Mi, 12 Dez 2007) | 307 lines Merged revisions 594558-603642 via svnmerge from https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk ........ r594571 | vhennebert | 2007-11-13 17:24:32 +0100 (Di, 13 Nov 2007) | 7 lines Moved the creation of grid units to the FO tree building stage. Brought a few improvements along with the move: - bugfix: border-resolution for border-end on row-spanning cells was wrong - bugfix: in case of missing cells the border-end of the table was applied to an inner cell, instead of the cell in the last column (but missing cells aren't painted yet :-\) - bugfix: in collapsing-border model, border-before and -after specified on table-column were applied to every cell of the column, instead of only the first and the last ones - border resolution is now made progressively when possible, and no longer triggers the fetching of all the rows of the table Added testcases for the border conflict resolution (between the various elements of a table and not only the cells) ........ r594578 | vhennebert | 2007-11-13 17:50:09 +0100 (Di, 13 Nov 2007) | 2 lines Moved *GridUnit from layoutmgr/table to fo/flow/table ........ r594579 | vhennebert | 2007-11-13 17:55:54 +0100 (Di, 13 Nov 2007) | 2 lines Changed back visibility of fields from public to package-private, due to the move of *GridUnit in the fo.flow.table package ........ r594584 | vhennebert | 2007-11-13 18:13:19 +0100 (Di, 13 Nov 2007) | 2 lines Use a singleton for a default BorderInfo of style none, instead of every time a new instance ........ r594592 | vhennebert | 2007-11-13 18:39:17 +0100 (Di, 13 Nov 2007) | 2 lines Cleaned up RowGroupLayoutManager and TableRowIterator ........ r594821 | vhennebert | 2007-11-14 11:18:45 +0100 (Mi, 14 Nov 2007) | 2 lines Moved EffRow to the fo.flow.table package ........ r594829 | vhennebert | 2007-11-14 11:41:52 +0100 (Mi, 14 Nov 2007) | 2 lines Reduced visibility of some methods and constructors from public to package-private, as a consequence of the move of *GridUnit to the fo.flow.table package ........ r594836 | vhennebert | 2007-11-14 12:14:03 +0100 (Mi, 14 Nov 2007) | 2 lines Restored the setting of the parent table-row element on grid units ........ r594852 | vhennebert | 2007-11-14 13:21:53 +0100 (Mi, 14 Nov 2007) | 2 lines Restored the setting of rowIndex on primary grid units (although testcases were already working...) ........ r595297 | jeremias | 2007-11-15 14:28:58 +0100 (Do, 15 Nov 2007) | 2 lines Bugzilla #43143: Had to remove the Expert(Subset) Encoding detection as this caused problems with a barcode font that used dfCharset=2 but was not using ExpertSubset encoding. To detect Expert(Subset)Encoding, the AFM needs to be parsed. And since we don't support that encoding, yet, the fallback to WinAnsiEncoding should work well enough. ........ r595637 | acumiskey | 2007-11-16 13:12:52 +0100 (Fr, 16 Nov 2007) | 3 lines This should improve the ability of the FontLoader when resolving PFM files for Type 1 fonts on case sensitive Unix systems. ........ r596072 | jeremias | 2007-11-18 11:48:53 +0100 (So, 18 Nov 2007) | 4 lines ApacheCon US is over. OSSSummit was cancelled/postponed. Added example for total page count using XSL 1.1 Adjusted total page count example to new FOP API. (Thanks to Miroslav Gregan for the hint) ........ r596097 | jeremias | 2007-11-18 17:56:09 +0100 (So, 18 Nov 2007) | 6 lines Bugzilla #43605: Added methods for page-number-citation and page-number-citation-last in FOEventHandler.java Submitted by: V. Schappert <vschappert.at.bloomberg.net> Patch modified by Jeremias: Bugfix: FOEventHandler.startPageNumberCitation() was also called in the case of a page-number-citation-last. Introduced abstract base classes to avoid this. ........ r596100 | jeremias | 2007-11-18 18:17:24 +0100 (So, 18 Nov 2007) | 1 line Added sample as suggested by Kumar Puppala. ........ r596390 | vhennebert | 2007-11-19 19:25:27 +0100 (Mo, 19 Nov 2007) | 2 lines Bugzilla #43766: breaks generated by the merging algorithm for table rows containing empty cells has always a penalty of 900 ........ r596554 | jeremias | 2007-11-20 08:14:33 +0100 (Di, 20 Nov 2007) | 2 lines Bugzilla #43904: Buffer the OutputStreams in our transcoders if the users forget. ........ r596600 | jeremias | 2007-11-20 11:20:29 +0100 (Di, 20 Nov 2007) | 3 lines Bugzilla #43910: Avoid a NullPointerException in AreaTreeHandler.endDocument(). Submitted by: David Delbecq <delbd.at.oma.be> ........ r596724 | jeremias | 2007-11-20 16:56:33 +0100 (Di, 20 Nov 2007) | 3 lines Bugfix: Bugfix for URI resolution: Make StreamSources without system identifier work again. Bugfix: Close streams opened by test font resolution in font configuration (the font URIs will be resolved again later anyway). Better error message when the loading of font metric files doesn't work due to missing information in the returned Source instances. ........ r596727 | vhennebert | 2007-11-20 17:07:32 +0100 (Di, 20 Nov 2007) | 2 lines Bugfix in tables: wrong element generation by the merging algorithm when glues must be produced to cope with conditional spaces. The corresponding length was added twice: one in the glue itself and one in the following box. ........ r596739 | cbowditch | 2007-11-20 17:49:13 +0100 (Di, 20 Nov 2007) | 1 line bug fix: memory leak in PropertyCache. Fix provided by Jeremias. There are still some thread synchronization issues to be addressed in the PropertyCache. See the following thread for details: http://mail-archives.apache.org/mod_mbox/xmlgraphics-fop-dev/200711.mbox/%3cBAY117-DAV109E36CC066889386AB917FB870@phx.gbl%3e ........ r596742 | vhennebert | 2007-11-20 18:08:46 +0100 (Di, 20 Nov 2007) | 2 lines Added a news entry about Max Berger becoming a committer. Welcome Max! ........ r596776 | vhennebert | 2007-11-20 19:47:39 +0100 (Di, 20 Nov 2007) | 2 lines Bugzilla #43803: table cells having no children are allowed in relaxed validation mode. ........ r597052 | vhennebert | 2007-11-21 13:23:59 +0100 (Mi, 21 Nov 2007) | 2 lines Bugfix: the last element generated by the merging algorithm may now be a glue ........ r597448 | jeremias | 2007-11-22 17:13:05 +0100 (Do, 22 Nov 2007) | 2 lines First draft of a possible new intermediate format for Apache FOP. Details on: http://wiki.apache.org/xmlgraphics-fop/AreaTreeIntermediateXml/NewDesign ........ r598558 | jeremias | 2007-11-27 09:36:23 +0100 (Di, 27 Nov 2007) | 6 lines Bugzilla #40230: Bugfix: no empty page is generated anymore if there's no content after a break-after. Bugzilla #43917: Bugfix for border-after painting and element list generation when a forced break is involved. ........ r599536 | vhennebert | 2007-11-29 19:31:13 +0100 (Do, 29 Nov 2007) | 4 lines Added fixes-bug attributes for: - wrong element generation in table when glues are produced - border-resolution on row-spanning cells ........ r599746 | jeremias | 2007-11-30 10:04:54 +0100 (Fr, 30 Nov 2007) | 2 lines Bugzilla #37993: Bugfix: allow multiple bookmarks to point at the same destination. ........ r600195 | adelmelle | 2007-12-01 22:11:53 +0100 (Sa, 01 Dez 2007) | 1 line Correction and simplification of the PropertyCache: subclass WeakReference and remove internal threading ........ r600467 | jeremias | 2007-12-03 11:16:27 +0100 (Mo, 03 Dez 2007) | 2 lines Log RuntimeExceptions during rendering so that they are at least visible somewhere if someone doesn't set an ErrorListener on the XSLT processor (this could lead to exceptions being swallowed). This is a temporary measure until we have time to improve the exception handling in FOP. The original problem that led to this change was: "The number of this PDFNumber must not be empty" while producing a PDF/A with customized filter entries in the PDF configuration. The exception was a follow-up exception after a PDFConformanceException that was swallowed by a default ErrorListener. ........ r600521 | jeremias | 2007-12-03 14:21:06 +0100 (Mo, 03 Dez 2007) | 1 line Added a possibility to rerun the whole run a defined number of times to test for possible issues outside a single rendering run. ........ r600529 | jeremias | 2007-12-03 14:32:04 +0100 (Mo, 03 Dez 2007) | 1 line Oops. ........ r601413 | vhennebert | 2007-12-05 17:56:47 +0100 (Mi, 05 Dez 2007) | 2 lines Typo in property: svn:kewords -> svn:keywords ........ r601415 | acumiskey | 2007-12-05 18:11:44 +0100 (Mi, 05 Dez 2007) | 2 lines Corrected javadocs ........ r601416 | acumiskey | 2007-12-05 18:12:54 +0100 (Mi, 05 Dez 2007) | 2 lines Corrected javadoc ........ r601417 | acumiskey | 2007-12-05 18:13:31 +0100 (Mi, 05 Dez 2007) | 2 lines Corrected javadoc ........ r601419 | acumiskey | 2007-12-05 18:15:46 +0100 (Mi, 05 Dez 2007) | 2 lines Improved use of logging ........ r601423 | acumiskey | 2007-12-05 18:19:43 +0100 (Mi, 05 Dez 2007) | 2 lines Corrected javadoc, fixed checkstyle issues, and now also correctly caters for negative number conversions ........ r601424 | acumiskey | 2007-12-05 18:21:15 +0100 (Mi, 05 Dez 2007) | 2 lines Fixed checkstyle issues ........ r601426 | acumiskey | 2007-12-05 18:24:15 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601427 | acumiskey | 2007-12-05 18:25:07 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601428 | acumiskey | 2007-12-05 18:25:58 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601429 | acumiskey | 2007-12-05 18:27:06 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601430 | acumiskey | 2007-12-05 18:28:03 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601431 | acumiskey | 2007-12-05 18:28:48 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601432 | acumiskey | 2007-12-05 18:29:31 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601433 | acumiskey | 2007-12-05 18:30:04 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601434 | acumiskey | 2007-12-05 18:31:20 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601435 | acumiskey | 2007-12-05 18:32:29 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601436 | acumiskey | 2007-12-05 18:34:44 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601437 | acumiskey | 2007-12-05 18:35:31 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601438 | acumiskey | 2007-12-05 18:36:12 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes and cleanup ........ r601439 | acumiskey | 2007-12-05 18:37:40 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601440 | acumiskey | 2007-12-05 18:39:54 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601442 | acumiskey | 2007-12-05 18:42:13 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601443 | acumiskey | 2007-12-05 18:42:48 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601444 | acumiskey | 2007-12-05 18:43:46 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601445 | acumiskey | 2007-12-05 18:44:36 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601446 | acumiskey | 2007-12-05 18:45:20 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601447 | acumiskey | 2007-12-05 18:47:44 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601448 | acumiskey | 2007-12-05 18:48:56 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601449 | acumiskey | 2007-12-05 18:49:46 +0100 (Mi, 05 Dez 2007) | 2 lines Checkstyle fixes ........ r601712 | acumiskey | 2007-12-06 12:57:14 +0100 (Do, 06 Dez 2007) | 2 lines Temporary fix to the build ........ r602045 | jeremias | 2007-12-07 10:20:28 +0100 (Fr, 07 Dez 2007) | 1 line Avoid a NPE in toString(). ........ r602125 | maxberger | 2007-12-07 16:36:53 +0100 (Fr, 07 Dez 2007) | 6 lines Updated xmlgraphics from SVN Added autodetection of fonts in jar files (x-font and x-font-truetype) Added files needed for testcase Please note: Actual testcase is still missing! ........ r602898 | maxberger | 2007-12-10 14:35:33 +0100 (Mo, 10 Dez 2007) | 2 lines Added documentation for font-in-jar-files ........ r603590 | acumiskey | 2007-12-12 13:24:10 +0100 (Mi, 12 Dez 2007) | 4 lines * Added an SVG handler and Graphics2D implementation for AFP which injects AFP GOCA structured fields into the AFPDataStream. * Fixed many checkstyle problems. * Updated xmlgraphics-commons-1.3svn.jar to include changes to TextHandler ........ r603592 | acumiskey | 2007-12-12 13:26:39 +0100 (Mi, 12 Dez 2007) | 2 lines Updated status with SVG support for AFP. ........ ------------------------------------------------------------------------ r603661 | jeremias | 2007-12-12 17:20:09 +0100 (Mi, 12 Dez 2007) | 1 line Fix javadoc ------------------------------------------------------------------------ r603886 | jeremias | 2007-12-13 12:15:48 +0100 (Do, 13 Dez 2007) | 1 line Copy/paste programming is dangerous. :-) ------------------------------------------------------------------------ r603902 | jeremias | 2007-12-13 13:17:56 +0100 (Do, 13 Dez 2007) | 2 lines Factored out all image handling code in the PDFRenderer into PDFImageHandler classes. The interface was introduced to handle PDF-in-PDF images. The PDFImageHandler interface changes in a backwards-incompatible way but since the PDF-in-PDF plug-in probably has the only implementation, that's not very problematic. I'll release a new version as soon as the image stuff is merged back into Trunk. ------------------------------------------------------------------------ r603937 | jeremias | 2007-12-13 16:20:46 +0100 (Do, 13 Dez 2007) | 1 line Some cleanup ------------------------------------------------------------------------ r603938 | jeremias | 2007-12-13 16:23:23 +0100 (Do, 13 Dez 2007) | 2 lines Switch PCL renderer to new image package. Add an option to force a color canvas (RGB) instead of a gray canvas. Set this to true for all SVG graphics since Batik does not seem to support gradients on a grayscale canvas (IllegalArgumentException). ------------------------------------------------------------------------ r604122 | jeremias | 2007-12-14 08:58:56 +0100 (Fr, 14 Dez 2007) | 1 line Stupid copy/paste again. ------------------------------------------------------------------------ r604135 | jeremias | 2007-12-14 10:04:43 +0100 (Fr, 14 Dez 2007) | 1 line Preliminary changes to switch to the new image library. TIFF optimizations still missing. Untested. ------------------------------------------------------------------------ r604144 | jeremias | 2007-12-14 11:12:41 +0100 (Fr, 14 Dez 2007) | 1 line Switch to new image package. At some point we will probably want to remove this example as JEuclid has a better plug-in now. ------------------------------------------------------------------------ r604150 | jeremias | 2007-12-14 11:27:39 +0100 (Fr, 14 Dez 2007) | 1 line Old JEuclid doesn't notice itself if no MathML document is loaded. ------------------------------------------------------------------------ r604155 | jeremias | 2007-12-14 11:48:07 +0100 (Fr, 14 Dez 2007) | 2 lines Switched to new image package. The preloader simply loads the full document and converts it to SVG. That's the only way to determine the intrinsic size of the image. ------------------------------------------------------------------------ r604157 | jeremias | 2007-12-14 11:51:21 +0100 (Fr, 14 Dez 2007) | 1 line No longer needed. ------------------------------------------------------------------------ r604214 | jeremias | 2007-12-14 17:07:30 +0100 (Fr, 14 Dez 2007) | 1 line Added work-around for decoding CMYK JPEGs with ImageIO (no guarantees for color fidelity but it's better than not being able to use CMYK images). ------------------------------------------------------------------------ r604297 | jeremias | 2007-12-14 22:14:12 +0100 (Fr, 14 Dez 2007) | 68 lines Merged revisions 603643-604293 via svnmerge from https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk ........ r603890 | vhennebert | 2007-12-13 12:35:17 +0100 (Do, 13 Dez 2007) | 2 lines Fixed @throws statements in javadoc ........ r603926 | adelmelle | 2007-12-13 15:43:08 +0100 (Do, 13 Dez 2007) | 4 lines Minor tweaks: * only add text to a fo:wrapper if it is not a direct flow-descendant * error if an fo:wrapper that is a direct flow-descendant contains inline-level children ........ r603943 | vhennebert | 2007-12-13 16:55:29 +0100 (Do, 13 Dez 2007) | 2 lines Removed calls to removeLegalBreaks since they aren't necessary (the whole content is put in a single box anyway) and the method is buggy. ........ r603945 | vhennebert | 2007-12-13 17:10:32 +0100 (Do, 13 Dez 2007) | 2 lines Implemented the resolution of collapsing borders in the FO tree, for every situation (normal, cell at the top of a page, cell broken), taking conditionality, headers and footers into account. ........ r603959 | vhennebert | 2007-12-13 18:21:24 +0100 (Do, 13 Dez 2007) | 2 lines Reverted change accidentally introduced in the previous commit. A proper fix needs to be found for this one. ........ r603961 | vhennebert | 2007-12-13 18:31:26 +0100 (Do, 13 Dez 2007) | 2 lines Ok, now /really/ revert the previous commit :-\ ........ r603962 | vhennebert | 2007-12-13 18:32:43 +0100 (Do, 13 Dez 2007) | 2 lines Style only: removed trailing white spaces ........ r603968 | vhennebert | 2007-12-13 19:28:56 +0100 (Do, 13 Dez 2007) | 2 lines Fixed the handling of columns in the border resolution, especially in case of column-spanning cells ........ r603975 | vhennebert | 2007-12-13 19:52:48 +0100 (Do, 13 Dez 2007) | 2 lines Removed parameter from the endPart method, since the part is already passed as a parameter of the previously called startPart method ........ r603979 | vhennebert | 2007-12-13 19:57:25 +0100 (Do, 13 Dez 2007) | 2 lines Removed parameter from the endTablePart method, as the part is already passed as as a parameter of the previously called startTablePart method ........ r603990 | vhennebert | 2007-12-13 20:17:12 +0100 (Do, 13 Dez 2007) | 2 lines Throw a ValidationException if table-footer is put after table-body and the table uses the collapsing border model. The footer must be known to properly resolve borders. ........ r604171 | vhennebert | 2007-12-14 12:32:51 +0100 (Fr, 14 Dez 2007) | 2 lines Clean up: removed all reset and resetPosition methods, which pre-date the Knuth era and are no longer needed ........ r604180 | vhennebert | 2007-12-14 13:23:10 +0100 (Fr, 14 Dez 2007) | 2 lines Reduced visibility of methods from public to package-private ........ r604185 | acumiskey | 2007-12-14 14:16:06 +0100 (Fr, 14 Dez 2007) | 2 lines Fixed copy constructor ........ r604293 | jeremias | 2007-12-14 21:58:53 +0100 (Fr, 14 Dez 2007) | 2 lines Bugfix: DecodeParms -> DecodeParams (introduced when I changed to generic PDF structures) (fixes CCITT encoded images) ........ ------------------------------------------------------------------------ r604301 | jeremias | 2007-12-14 22:26:27 +0100 (Fr, 14 Dez 2007) | 9 lines Merged revisions 604294-604299 via svnmerge from https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk ........ r604299 | jeremias | 2007-12-14 22:24:14 +0100 (Fr, 14 Dez 2007) | 1 line Don't hack when you're tired! Reverting r604293 and instead fixing the right value. It's DecodeParams -> DecodeParms! ........ ------------------------------------------------------------------------ r604930 | jeremias | 2007-12-17 18:05:47 +0100 (Mo, 17 Dez 2007) | 2 lines Dispose ImageReader when done reading. Don't close streams as some codecs appear to do "late reading" of the image, i.e. only when the rasters are accessed, at which point they still seek on the stream. For this, the streams must remain open. I hope the codecs all properly close the streams once they don't need them anymore. The javadocs are not clear enough in this regards, IMO. ------------------------------------------------------------------------ r604968 | jeremias | 2007-12-17 20:03:45 +0100 (Mo, 17 Dez 2007) | 3 lines Added an isSupported() method to ImageLoaderFactory so we can check early if an ImageLoader may or may not support a particular subformat. This is used to allow optimized loading of CCITT compressed TIFF images. Support for undecoded embedding of single-strip CCITT compressed images for PDF, PostScript and AFP. Added a fallback mechanism for ImageLoaders: if one ImageLoader cannot load a particular image, try equivalent others registered for the same format. ------------------------------------------------------------------------ r604972 | jeremias | 2007-12-17 20:07:43 +0100 (Mo, 17 Dez 2007) | 1 line Update Commons ------------------------------------------------------------------------ r605138 | jeremias | 2007-12-18 09:42:41 +0100 (Di, 18 Dez 2007) | 2 lines Support for specifying a particular page number of a multi-page image (such as TIFF). Format: http://localhost/images/scan1.tif#page=3 ------------------------------------------------------------------------ r605479 | jeremias | 2007-12-19 10:18:33 +0100 (Mi, 19 Dez 2007) | 3 lines Removed new image package after the copying it to XML Graphics Commons. Adjusted to use the Commons' version. Batik-dependent plugins remain but will eventually need a different resting place. ------------------------------------------------------------------------ r605486 | jeremias | 2007-12-19 10:39:33 +0100 (Mi, 19 Dez 2007) | 1 line Adjust the (pre)loader registration for the demo extensions. ------------------------------------------------------------------------ r605567 | jeremias | 2007-12-19 16:03:25 +0100 (Mi, 19 Dez 2007) | 1 line Fixed scaling and translation (didn't work correctly in certain situations) ------------------------------------------------------------------------ r607034 | jeremias | 2007-12-27 11:47:12 +0100 (Do, 27 Dez 2007) | 71 lines Merged revisions 604300-607033 via svnmerge from https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk ........ r604475 | vhennebert | 2007-12-15 19:16:01 +0100 (Sa, 15 Dez 2007) | 2 lines Testcase for the resolution of collapsed and conditional borders in the FO tree ........ r604678 | adelmelle | 2007-12-16 20:54:00 +0100 (So, 16 Dez 2007) | 8 lines Streamlining/Correction of the changes made in r603926 - delegate validation of the fo:wrapper's children to the parent: added static FONode.validateChildNode() - narrow the condition for processing text-childnodes: this is not only constrained to fo:flow and fo:static-content, but the same goes for a fo:wrapper that is a direct descendant of a fo:block-container or fo:inline-container, which only allow block-level content (interpretation) - minor javadoc fixups/improvements ........ r604814 | vhennebert | 2007-12-17 11:21:04 +0100 (Mo, 17 Dez 2007) | 2 lines Organized imports ........ r604965 | vhennebert | 2007-12-17 19:56:46 +0100 (Mo, 17 Dez 2007) | 2 lines Renaming GridUnitPart into the more accurate CellPart. Moreover I was always making the confusion between gup and pgu ........ r604970 | vhennebert | 2007-12-17 20:05:27 +0100 (Mo, 17 Dez 2007) | 2 lines Simplified addAreasAndFlushRow: there can no longer be null GridUnits, every hole in the grid is now filled with an EmptyGridUnit ........ r605195 | vhennebert | 2007-12-18 12:56:38 +0100 (Di, 18 Dez 2007) | 2 lines Reset previousRowsLength before a new row-group is handled ........ r605246 | vhennebert | 2007-12-18 17:48:03 +0100 (Di, 18 Dez 2007) | 2 lines Simplification in RowPainter: avoid the use of an array to store rowOffsets and firstRow index for each part of the table (header, footer, body). One at a time is enough. ........ r605253 | vhennebert | 2007-12-18 18:01:45 +0100 (Di, 18 Dez 2007) | 2 lines Renamed firstRow into firstRowIndex and moved its initialization into handeTableContentPosition ........ r605295 | vhennebert | 2007-12-18 19:58:29 +0100 (Di, 18 Dez 2007) | 2 lines Streamlined the recording of row offsets, by replacing Map with a List. Fixed bug #43633 in the same time. ........ r605297 | vhennebert | 2007-12-18 20:02:02 +0100 (Di, 18 Dez 2007) | 3 lines SVG support for AFP is an important addition IMO. IIUC it will have to be advertised in the next release as "Support for SVG images using primitive AFP graphics commands instead of bitmap images", or something like that? ........ r605517 | vhennebert | 2007-12-19 12:47:38 +0100 (Mi, 19 Dez 2007) | 2 lines I said currentGU can no longer be null ........ r605978 | jeremias | 2007-12-20 18:00:46 +0100 (Do, 20 Dez 2007) | 1 line Remove commented code. ........ r606004 | jeremias | 2007-12-20 20:19:19 +0100 (Do, 20 Dez 2007) | 1 line Added support for scale-down-to-fit and scale-up-to-fit. ........ r607032 | jeremias | 2007-12-27 11:34:15 +0100 (Do, 27 Dez 2007) | 4 lines Added new extension element: fox:external-document. It allows to add whole documents such as multi-page TIFF images to be inserted as peers to a page-sequence. Each image will make up an entire page. See the documentation for details. ATM, only single pages are possible. Multi-page images will be supported with the new image package. Some preparations for page-position="only" but the implementation is incomplete and "only" has no effect, yet. (Just uploaded some stuff I once started) Some javadoc cleanups. ........ ------------------------------------------------------------------------ r607091 | jeremias | 2007-12-27 18:13:45 +0100 (Do, 27 Dez 2007) | 1 line Avoid cutting away the URI fragment when building URLs from filenames. ------------------------------------------------------------------------ r607092 | jeremias | 2007-12-27 18:15:49 +0100 (Do, 27 Dez 2007) | 3 lines Switched fox:external-document to new image package. Added multi-page support for fox:external-document. Changed multi-page.tiff: page 4 is now bigger than all other pages. (to make sure that individually sized pages are handled properly) ------------------------------------------------------------------------ r607188 | jeremias | 2007-12-28 09:38:26 +0100 (Fr, 28 Dez 2007) | 2 lines Throwing IllegalStateException causes a prior exception to be swallowed by Xalan-J. Need to throw a SAXException instead. Instead of logging an error about the element mismatch throw a SAXException because the logging only confuses the user as it's practically always a follow-up exception of an exception happening earlier in the respective startElement() event. ------------------------------------------------------------------------ r607249 | jeremias | 2007-12-28 15:27:39 +0100 (Fr, 28 Dez 2007) | 1 line Metadata didn't get transported to the renderer when only fox:external-document is used. ------------------------------------------------------------------------ r607256 | jeremias | 2007-12-28 16:06:35 +0100 (Fr, 28 Dez 2007) | 1 line Corrected content model. ------------------------------------------------------------------------ r607261 | jeremias | 2007-12-28 16:11:56 +0100 (Fr, 28 Dez 2007) | 1 line Added -imagein to command-line so (multi-page) images such as TIFF files can be converted to PDF and other formats supported by FOP. The default stylesheet can be overwritten (with -xslt) if desired. ------------------------------------------------------------------------ r609530 | jeremias | 2008-01-07 09:16:09 +0100 (Mo, 07 Jan 2008) | 1 line Fixed copy/paste mistake. Thanks for spotting it, Vincent. ------------------------------------------------------------------------ r609600 | jeremias | 2008-01-07 14:28:53 +0100 (Mo, 07 Jan 2008) | 1 line Removed "image2" package again and moved the Batik-dependent implementations under the old "image" package. In this form, the deprecated code doesn't conflict with the new implementations anymore. ------------------------------------------------------------------------ r610029 | jeremias | 2008-01-08 16:48:53 +0100 (Di, 08 Jan 2008) | 3 lines Added minimal support for the .minimum/.maximum components of block/inline-progression-dimension on fo:external-graphic and fo:instream-foreign-object. This will only constrain the image itself but not allow the layout engine itself to resize the image as seen fit. Added missing Javadocs in ImageLayout.java. ------------------------------------------------------------------------ r611120 | jeremias | 2008-01-11 10:20:57 +0100 (Fr, 11 Jan 2008) | 100 lines 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. ........ ------------------------------------------------------------------------ r611133 | jeremias | 2008-01-11 11:45:01 +0100 (Fr, 11 Jan 2008) | 4 lines Fixed merge problems. Fixed a NPE when a mask is null in BitmapImage.java Add support for properly encoding binary data as a hexadecimal string object (including encryption). Adjust palette generation for indexed bitmaps to work correctly with encryption. ------------------------------------------------------------------------ r611138 | jeremias | 2008-01-11 11:59:27 +0100 (Fr, 11 Jan 2008) | 1 line Removed empty package. ------------------------------------------------------------------------ git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@611278 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java')
-rw-r--r--src/java/META-INF/services/org.apache.fop.render.pdf.PDFImageHandler5
-rw-r--r--src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageConverter2
-rw-r--r--src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageLoaderFactory2
-rw-r--r--src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImagePreloader2
-rw-r--r--src/java/org/apache/fop/apps/FOURIResolver.java21
-rw-r--r--src/java/org/apache/fop/apps/FOUserAgent.java31
-rw-r--r--src/java/org/apache/fop/apps/FopFactory.java24
-rw-r--r--src/java/org/apache/fop/area/AreaTreeHandler.java22
-rw-r--r--src/java/org/apache/fop/area/AreaTreeParser.java33
-rw-r--r--src/java/org/apache/fop/area/Trait.java19
-rw-r--r--src/java/org/apache/fop/cli/CommandLineOptions.java48
-rw-r--r--src/java/org/apache/fop/cli/ImageInputHandler.java60
-rw-r--r--src/java/org/apache/fop/cli/InputHandler.java33
-rw-r--r--src/java/org/apache/fop/cli/image2fo.xsl45
-rw-r--r--src/java/org/apache/fop/fo/FOTreeBuilder.java15
-rw-r--r--src/java/org/apache/fop/fo/flow/ExternalGraphic.java43
-rw-r--r--src/java/org/apache/fop/fo/pagination/Root.java14
-rwxr-xr-xsrc/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java35
-rw-r--r--src/java/org/apache/fop/image/loader/batik/BatikUtil.java41
-rw-r--r--src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java120
-rw-r--r--src/java/org/apache/fop/image/loader/batik/ImageConverterWMF2G2D.java107
-rw-r--r--src/java/org/apache/fop/image/loader/batik/ImageLoaderFactorySVG.java63
-rw-r--r--src/java/org/apache/fop/image/loader/batik/ImageLoaderFactoryWMF.java62
-rw-r--r--src/java/org/apache/fop/image/loader/batik/ImageLoaderSVG.java78
-rw-r--r--src/java/org/apache/fop/image/loader/batik/ImageLoaderWMF.java70
-rw-r--r--src/java/org/apache/fop/image/loader/batik/ImageWMF.java69
-rw-r--r--src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java182
-rw-r--r--src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java142
-rw-r--r--src/java/org/apache/fop/image/loader/batik/package.html26
-rw-r--r--src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java105
-rw-r--r--src/java/org/apache/fop/layoutmgr/TraitSetter.java17
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/ImageLayout.java190
-rw-r--r--src/java/org/apache/fop/pdf/AlphaRasterImage.java181
-rw-r--r--src/java/org/apache/fop/pdf/BitmapImage.java27
-rw-r--r--src/java/org/apache/fop/pdf/FlateFilter.java8
-rw-r--r--src/java/org/apache/fop/pdf/PDFFactory.java3
-rw-r--r--src/java/org/apache/fop/pdf/PDFFilterList.java5
-rw-r--r--src/java/org/apache/fop/pdf/PDFICCStream.java4
-rw-r--r--src/java/org/apache/fop/pdf/PDFImage.java14
-rw-r--r--src/java/org/apache/fop/pdf/PDFImageXObject.java21
-rw-r--r--src/java/org/apache/fop/pdf/PDFObject.java26
-rw-r--r--src/java/org/apache/fop/pdf/PDFReference.java3
-rw-r--r--src/java/org/apache/fop/pdf/PDFText.java26
-rw-r--r--src/java/org/apache/fop/render/AbstractGenericSVGHandler.java26
-rw-r--r--src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java6
-rw-r--r--src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java88
-rw-r--r--src/java/org/apache/fop/render/Graphics2DAdapter.java2
-rw-r--r--src/java/org/apache/fop/render/Graphics2DImagePainter.java21
-rw-r--r--src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java3
-rw-r--r--src/java/org/apache/fop/render/afp/AFPRenderer.java184
-rw-r--r--src/java/org/apache/fop/render/java2d/Java2DGraphics2DAdapter.java32
-rw-r--r--src/java/org/apache/fop/render/java2d/Java2DRenderer.java141
-rw-r--r--src/java/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java9
-rw-r--r--src/java/org/apache/fop/render/pcl/PCLRenderer.java255
-rw-r--r--src/java/org/apache/fop/render/pcl/PCLRendererContext.java17
-rw-r--r--src/java/org/apache/fop/render/pcl/PCLRendererContextConstants.java32
-rw-r--r--src/java/org/apache/fop/render/pcl/PCLSVGHandler.java8
-rw-r--r--src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java200
-rw-r--r--src/java/org/apache/fop/render/pdf/FopPDFImage.java374
-rw-r--r--src/java/org/apache/fop/render/pdf/ImageRawCCITTFaxAdapter.java110
-rw-r--r--src/java/org/apache/fop/render/pdf/ImageRawJPEGAdapter.java96
-rw-r--r--src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java249
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java3
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFImageHandler.java44
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java68
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFImageHandlerRawCCITTFax.java83
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java83
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java84
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java84
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFImageHandlerXML.java74
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRenderer.java160
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java2
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFSVGHandler.java51
-rw-r--r--src/java/org/apache/fop/render/ps/ImageEncoderCCITTFax.java71
-rw-r--r--src/java/org/apache/fop/render/ps/ImageEncoderJPEG.java51
-rw-r--r--src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java34
-rw-r--r--src/java/org/apache/fop/render/ps/PSImageUtils.java100
-rw-r--r--src/java/org/apache/fop/render/ps/PSRenderer.java232
-rw-r--r--src/java/org/apache/fop/render/ps/PSSupportedFlavors.java67
-rw-r--r--src/java/org/apache/fop/render/ps/ResourceHandler.java149
-rw-r--r--src/java/org/apache/fop/render/rtf/RTFHandler.java188
-rw-r--r--src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfExternalGraphic.java26
-rw-r--r--src/java/org/apache/fop/svg/PDFBridgeContext.java45
-rw-r--r--src/java/org/apache/fop/svg/PDFGraphics2D.java17
-rw-r--r--src/java/org/apache/fop/svg/PDFImageElementBridge.java209
-rw-r--r--src/java/org/apache/fop/svg/PDFTranscoder.java57
-rw-r--r--src/java/org/apache/fop/util/dijkstra/DefaultEdgeDirectory.java109
-rw-r--r--src/java/org/apache/fop/util/dijkstra/DijkstraAlgorithm.java215
-rw-r--r--src/java/org/apache/fop/util/dijkstra/Edge.java47
-rw-r--r--src/java/org/apache/fop/util/dijkstra/EdgeDirectory.java45
-rw-r--r--src/java/org/apache/fop/util/dijkstra/Vertex.java32
91 files changed, 4855 insertions, 1472 deletions
diff --git a/src/java/META-INF/services/org.apache.fop.render.pdf.PDFImageHandler b/src/java/META-INF/services/org.apache.fop.render.pdf.PDFImageHandler
new file mode 100644
index 000000000..b72796c2d
--- /dev/null
+++ b/src/java/META-INF/services/org.apache.fop.render.pdf.PDFImageHandler
@@ -0,0 +1,5 @@
+org.apache.fop.render.pdf.PDFImageHandlerRawJPEG
+org.apache.fop.render.pdf.PDFImageHandlerRawCCITTFax
+org.apache.fop.render.pdf.PDFImageHandlerGraphics2D
+org.apache.fop.render.pdf.PDFImageHandlerRenderedImage
+org.apache.fop.render.pdf.PDFImageHandlerXML \ No newline at end of file
diff --git a/src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageConverter b/src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageConverter
new file mode 100644
index 000000000..c3c688a2c
--- /dev/null
+++ b/src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageConverter
@@ -0,0 +1,2 @@
+org.apache.fop.image.loader.batik.ImageConverterSVG2G2D
+org.apache.fop.image.loader.batik.ImageConverterWMF2G2D
diff --git a/src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageLoaderFactory b/src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageLoaderFactory
new file mode 100644
index 000000000..b607a5e64
--- /dev/null
+++ b/src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageLoaderFactory
@@ -0,0 +1,2 @@
+org.apache.fop.image.loader.batik.ImageLoaderFactorySVG
+org.apache.fop.image.loader.batik.ImageLoaderFactoryWMF \ No newline at end of file
diff --git a/src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImagePreloader b/src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImagePreloader
new file mode 100644
index 000000000..c64d899b7
--- /dev/null
+++ b/src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImagePreloader
@@ -0,0 +1,2 @@
+org.apache.fop.image.loader.batik.PreloaderWMF
+org.apache.fop.image.loader.batik.PreloaderSVG
diff --git a/src/java/org/apache/fop/apps/FOURIResolver.java b/src/java/org/apache/fop/apps/FOURIResolver.java
index d68905e4c..f38be542a 100644
--- a/src/java/org/apache/fop/apps/FOURIResolver.java
+++ b/src/java/org/apache/fop/apps/FOURIResolver.java
@@ -32,13 +32,13 @@ import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.stream.StreamSource;
-// commons logging
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.fop.util.DataURIResolver;
import org.apache.xmlgraphics.util.io.Base64EncodeStream;
+import org.apache.fop.util.DataURIResolver;
+
/**
* Provides FOP specific URI resolution. This is the default URIResolver
* {@link FOUserAgent} will use unless overidden.
@@ -132,10 +132,23 @@ public class FOURIResolver implements javax.xml.transform.URIResolver {
// Fallback to default resolution mechanism
if (source == null) {
URL absoluteURL = null;
- File file = new File(href);
+ int hashPos = href.indexOf('#');
+ String fileURL, fragment;
+ if (hashPos >= 0) {
+ fileURL = href.substring(0, hashPos);
+ fragment = href.substring(hashPos);
+ } else {
+ fileURL = href;
+ fragment = null;
+ }
+ File file = new File(fileURL);
if (file.canRead() && file.isFile()) {
try {
- absoluteURL = file.toURL();
+ if (fragment != null) {
+ absoluteURL = new URL(file.toURL().toExternalForm() + fragment);
+ } else {
+ absoluteURL = file.toURL();
+ }
} catch (MalformedURLException mfue) {
handleException(mfue, "Could not convert filename '" + href
+ "' to URL", throwExceptions);
diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java
index 07928fef2..966e227fe 100644
--- a/src/java/org/apache/fop/apps/FOUserAgent.java
+++ b/src/java/org/apache/fop/apps/FOUserAgent.java
@@ -23,15 +23,18 @@ package org.apache.fop.apps;
import java.io.File;
import java.util.Date;
import java.util.Map;
+
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
-// commons logging
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-// FOP
+import org.apache.xmlgraphics.image.loader.ImageContext;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext;
+
import org.apache.fop.Version;
import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.pdf.PDFEncryptionParams;
@@ -110,6 +113,22 @@ public class FOUserAgent {
/** Set of keywords applicable to this document. */
protected String keywords = null;
+ private ImageSessionContext imageSessionContext = new AbstractImageSessionContext() {
+
+ public ImageContext getParentContext() {
+ return getFactory();
+ }
+
+ public float getTargetResolution() {
+ return FOUserAgent.this.getTargetResolution();
+ }
+
+ public Source resolveURI(String uri) {
+ return FOUserAgent.this.resolveURI(uri);
+ }
+
+ };
+
/**
* Default constructor
* @see org.apache.fop.apps.FopFactory
@@ -442,6 +461,14 @@ public class FOUserAgent {
setTargetResolution((float)dpi);
}
+ /**
+ * Returns the image session context for the image package.
+ * @return the ImageSessionContext instance for this rendering run
+ */
+ public ImageSessionContext getImageSessionContext() {
+ return this.imageSessionContext;
+ }
+
// ---------------------------------------------- environment-level stuff
// (convenience access to FopFactory methods)
diff --git a/src/java/org/apache/fop/apps/FopFactory.java b/src/java/org/apache/fop/apps/FopFactory.java
index c87a3041b..dc94d92fb 100644
--- a/src/java/org/apache/fop/apps/FopFactory.java
+++ b/src/java/org/apache/fop/apps/FopFactory.java
@@ -24,6 +24,7 @@ import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.MalformedURLException;
+import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collection;
import java.util.Collections;
@@ -36,10 +37,12 @@ import javax.xml.transform.URIResolver;
import org.xml.sax.SAXException;
import org.apache.avalon.framework.configuration.Configuration;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.xmlgraphics.image.loader.ImageContext;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+
import org.apache.fop.fo.ElementMapping;
import org.apache.fop.fo.ElementMappingRegistry;
import org.apache.fop.fonts.FontCache;
@@ -57,7 +60,7 @@ import org.apache.fop.util.ContentHandlerFactoryRegistry;
* Information that may potentially be different for each rendering run can be
* found and managed in the FOUserAgent.
*/
-public class FopFactory {
+public class FopFactory implements ImageContext {
/** logger instance */
private static Log log = LogFactory.getLog(FopFactory.class);
@@ -83,6 +86,9 @@ public class FopFactory {
/** Image factory for creating fop image objects */
private ImageFactory imageFactory;
+ /** Image manager for loading and caching image objects */
+ private ImageManager imageManager;
+
/** Configuration layer used to configure fop */
private FopFactoryConfigurator config = null;
@@ -150,7 +156,8 @@ public class FopFactory {
this.elementMappingRegistry = new ElementMappingRegistry(this);
this.foURIResolver = new FOURIResolver(validateUserConfigStrictly());
this.colorSpaceCache = new ColorSpaceCache(foURIResolver);
- this.imageFactory = new ImageFactory();
+ this.imageFactory = new ImageFactory();
+ this.imageManager = new ImageManager(this);
this.rendererFactory = new RendererFactory();
this.xmlHandlers = new XMLHandlerRegistry();
this.ignoredNamespaces = new java.util.HashSet();
@@ -293,6 +300,14 @@ public class FopFactory {
}
/**
+ * Returns the image manager.
+ * @return the image manager
+ */
+ public ImageManager getImageManager() {
+ return this.imageManager;
+ }
+
+ /**
* Add the element mapping with the given class name.
* @param elementMapping the class name representing the element mapping.
*/
@@ -748,5 +763,6 @@ public class FopFactory {
*/
public ColorSpace getColorSpace(String baseUri, String iccProfileSrc) {
return colorSpaceCache.get(baseUri, iccProfileSrc);
- }
+ }
+
}
diff --git a/src/java/org/apache/fop/area/AreaTreeHandler.java b/src/java/org/apache/fop/area/AreaTreeHandler.java
index a107da833..7454f4667 100644
--- a/src/java/org/apache/fop/area/AreaTreeHandler.java
+++ b/src/java/org/apache/fop/area/AreaTreeHandler.java
@@ -189,12 +189,12 @@ public class AreaTreeHandler extends FOEventHandler {
}
}
- /**
- * {@inheritDoc}
- * @param pageSequence
- * is the pageSequence being started
- */
+ /** {@inheritDoc} */
public void startPageSequence(PageSequence pageSequence) {
+ startAbstractPageSequence(pageSequence);
+ }
+
+ private void startAbstractPageSequence(AbstractPageSequence pageSequence) {
rootFObj = pageSequence.getRoot();
finishPrevPageSequence(pageSequence.getInitialPageNumber());
pageSequence.initPageNumber();
@@ -238,18 +238,12 @@ public class AreaTreeHandler extends FOEventHandler {
}
}
- /**
- * @see org.apache.fop.fo.FOEventHandler#startExternalDocument(org.apache.fop.fo.extensions.ExternalDocument)
- */
+ /** {@inheritDoc} */
public void startExternalDocument(ExternalDocument document) {
- rootFObj = document.getRoot();
- finishPrevPageSequence(document.getInitialPageNumber());
- document.initPageNumber();
+ startAbstractPageSequence(document);
}
- /**
- * @see org.apache.fop.fo.FOEventHandler#endExternalDocument(org.apache.fop.fo.extensions.ExternalDocument)
- */
+ /** {@inheritDoc} */
public void endExternalDocument(ExternalDocument document) {
if (statistics != null) {
statistics.end();
diff --git a/src/java/org/apache/fop/area/AreaTreeParser.java b/src/java/org/apache/fop/area/AreaTreeParser.java
index b4a804712..d4cdf5239 100644
--- a/src/java/org/apache/fop/area/AreaTreeParser.java
+++ b/src/java/org/apache/fop/area/AreaTreeParser.java
@@ -47,6 +47,10 @@ import org.xml.sax.helpers.DefaultHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.area.Trait.Background;
import org.apache.fop.area.Trait.InternalLink;
@@ -69,8 +73,6 @@ import org.apache.fop.fo.expr.PropertyException;
import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.image.ImageFactory;
import org.apache.fop.traits.BorderProps;
import org.apache.fop.util.ColorUtil;
import org.apache.fop.util.ContentHandlerFactory;
@@ -1048,22 +1050,19 @@ public class AreaTreeParser {
} catch (PropertyException e) {
throw new IllegalArgumentException(e.getMessage());
}
- String url = attributes.getValue("bkg-img");
- if (url != null) {
- bkg.setURL(url);
-
- ImageFactory fact = userAgent.getFactory().getImageFactory();
- FopImage img = fact.getImage(url, userAgent);
- if (img == null) {
- log.error("Background image not available: " + url);
- } else {
- // load dimensions
- if (!img.load(FopImage.DIMENSIONS)) {
- log.error("Cannot read background image dimensions: "
- + url);
- }
+ String uri = attributes.getValue("bkg-img");
+ if (uri != null) {
+ bkg.setURL(uri);
+
+ try {
+ ImageManager manager = userAgent.getFactory().getImageManager();
+ ImageSessionContext sessionContext
+ = userAgent.getImageSessionContext();
+ ImageInfo info = manager.getImageInfo(uri, sessionContext);
+ bkg.setImageInfo(info);
+ } catch (Exception e) {
+ log.error("Background image not available: " + uri, e);
}
- bkg.setFopImage(img);
String repeat = attributes.getValue("bkg-repeat");
if (repeat != null) {
diff --git a/src/java/org/apache/fop/area/Trait.java b/src/java/org/apache/fop/area/Trait.java
index b3c3d3947..98bed098c 100644
--- a/src/java/org/apache/fop/area/Trait.java
+++ b/src/java/org/apache/fop/area/Trait.java
@@ -22,9 +22,10 @@ package org.apache.fop.area;
import java.awt.Color;
import java.io.Serializable;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+
import org.apache.fop.fo.Constants;
import org.apache.fop.fonts.FontTriplet;
-import org.apache.fop.image.FopImage;
import org.apache.fop.traits.BorderProps;
import org.apache.fop.util.ColorUtil;
@@ -559,7 +560,7 @@ public class Trait implements Serializable {
private String url = null;
/** The background image if any. */
- private FopImage fopimage = null;
+ private ImageInfo imageInfo = null;
/** Background repeat enum for images. */
private int repeat;
@@ -603,11 +604,11 @@ public class Trait implements Serializable {
}
/**
- * Returns the FopImage representing the background image
+ * Returns the ImageInfo object representing the background image
* @return the background image, null if n/a
*/
- public FopImage getFopImage() {
- return fopimage;
+ public ImageInfo getImageInfo() {
+ return imageInfo;
}
/**
@@ -659,11 +660,11 @@ public class Trait implements Serializable {
}
/**
- * Sets the FopImage to use as the background image.
- * @param fopimage The FopImage to use
+ * Sets the ImageInfo of the image to use as the background image.
+ * @param info The background image's info object
*/
- public void setFopImage(FopImage fopimage) {
- this.fopimage = fopimage;
+ public void setImageInfo(ImageInfo info) {
+ this.imageInfo = info;
}
/**
diff --git a/src/java/org/apache/fop/cli/CommandLineOptions.java b/src/java/org/apache/fop/cli/CommandLineOptions.java
index 63a817071..3bb0aae7f 100644
--- a/src/java/org/apache/fop/cli/CommandLineOptions.java
+++ b/src/java/org/apache/fop/cli/CommandLineOptions.java
@@ -29,6 +29,11 @@ import java.util.Vector;
import javax.swing.UIManager;
+import org.xml.sax.SAXException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
import org.apache.fop.Version;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
@@ -38,19 +43,12 @@ import org.apache.fop.pdf.PDFAMode;
import org.apache.fop.pdf.PDFEncryptionManager;
import org.apache.fop.pdf.PDFEncryptionParams;
import org.apache.fop.pdf.PDFXMode;
-import org.apache.fop.render.awt.AWTRenderer;
import org.apache.fop.render.Renderer;
+import org.apache.fop.render.awt.AWTRenderer;
import org.apache.fop.render.pdf.PDFRenderer;
import org.apache.fop.render.xml.XMLRenderer;
import org.apache.fop.util.CommandLineLogger;
-// commons logging
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-// SAX
-import org.xml.sax.SAXException;
-
/**
* Options parses the commandline arguments
*/
@@ -71,6 +69,8 @@ public class CommandLineOptions {
public static final int XSLT_INPUT = 2;
/** input: Area Tree XML file */
public static final int AREATREE_INPUT = 3;
+ /** input: Image file */
+ public static final int IMAGE_INPUT = 4;
/* show configuration information */
private Boolean showConfiguration = Boolean.FALSE;
@@ -86,6 +86,8 @@ public class CommandLineOptions {
private File xmlfile = null;
/* area tree input file */
private File areatreefile = null;
+ /* area tree input file */
+ private File imagefile = null;
/* output file */
private File outfile = null;
/* input mode */
@@ -249,6 +251,8 @@ public class CommandLineOptions {
i = i + parseXMLInputOption(args, i);
} else if (args[i].equals("-atin")) {
i = i + parseAreaTreeInputOption(args, i);
+ } else if (args[i].equals("-imagein")) {
+ i = i + parseImageInputOption(args, i);
} else if (args[i].equals("-awt")) {
i = i + parseAWTOutputOption(args, i);
} else if (args[i].equals("-pdf")) {
@@ -594,6 +598,17 @@ public class CommandLineOptions {
}
}
+ private int parseImageInputOption(String[] args, int i) throws FOPException {
+ inputmode = IMAGE_INPUT;
+ if ((i + 1 == args.length)
+ || (args[i + 1].charAt(0) == '-')) {
+ throw new FOPException("you must specify the image file for the '-imagein' option");
+ } else {
+ imagefile = new File(args[i + 1]);
+ return 1;
+ }
+ }
+
private PDFEncryptionParams getPDFEncryptionParams() throws FOPException {
PDFEncryptionParams params = (PDFEncryptionParams)renderingOptions.get(
PDFRenderer.ENCRYPTION_PARAMS);
@@ -768,6 +783,20 @@ public class CommandLineOptions {
+ areatreefile.getAbsolutePath()
+ " not found ");
}
+ } else if (inputmode == IMAGE_INPUT) {
+ if (outputmode.equals(MimeConstants.MIME_XSL_FO)) {
+ throw new FOPException(
+ "FO output mode is only available if you use -xml and -xsl");
+ }
+ if (xmlfile != null) {
+ log.warn("image input mode, but XML file is set:");
+ log.error("XML file: " + xmlfile.toString());
+ }
+ if (!imagefile.exists()) {
+ throw new FileNotFoundException("Error: image file "
+ + imagefile.getAbsolutePath()
+ + " not found ");
+ }
}
} // end checkSettings
@@ -814,6 +843,8 @@ public class CommandLineOptions {
return new AreaTreeInputHandler(areatreefile);
case XSLT_INPUT:
return new InputHandler(xmlfile, xsltfile, xsltParams);
+ case IMAGE_INPUT:
+ return new ImageInputHandler(imagefile, xsltfile, xsltParams);
default:
throw new IllegalArgumentException("Error creating InputHandler object.");
}
@@ -920,6 +951,7 @@ public class CommandLineOptions {
+ " -fo infile xsl:fo input file \n"
+ " -xml infile xml input file, must be used together with -xsl \n"
+ " -atin infile area tree input file \n"
+ + " -imagein infile image input file \n"
+ " -xsl stylesheet xslt stylesheet \n \n"
+ " -param name value <value> to use for parameter <name> in xslt stylesheet\n"
+ " (repeat '-param name value' for each parameter)\n \n"
diff --git a/src/java/org/apache/fop/cli/ImageInputHandler.java b/src/java/org/apache/fop/cli/ImageInputHandler.java
new file mode 100644
index 000000000..fe3d5021f
--- /dev/null
+++ b/src/java/org/apache/fop/cli/ImageInputHandler.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.cli;
+
+import java.io.File;
+import java.io.StringReader;
+import java.util.Vector;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+
+/**
+ * InputHandler for the images (for example TIFF) as input.
+ */
+public class ImageInputHandler extends InputHandler {
+
+ /**
+ * Main constructor.
+ * @param imagefile the image file
+ * @param xsltfile XSLT file (may be null in which case the default stylesheet is used)
+ * @param params Vector of command-line parameters (name, value,
+ * name, value, ...) for XSL stylesheet, null if none
+ */
+ public ImageInputHandler(File imagefile, File xsltfile, Vector params) {
+ super(imagefile, xsltfile, params);
+ }
+
+ /** {@inheritDoc} */
+ protected Source createMainSource() {
+ return new StreamSource(new StringReader(
+ "<image>" + this.sourcefile.toURI().toASCIIString() + "</image>"));
+ }
+
+ /** {@inheritDoc} */
+ protected Source createXSLTSource() {
+ Source src = super.createXSLTSource();
+ if (src == null) {
+ src = new StreamSource(getClass().getResource("image2fo.xsl").toExternalForm());
+ }
+ return src;
+ }
+
+}
diff --git a/src/java/org/apache/fop/cli/InputHandler.java b/src/java/org/apache/fop/cli/InputHandler.java
index bfbce269d..89977beb7 100644
--- a/src/java/org/apache/fop/cli/InputHandler.java
+++ b/src/java/org/apache/fop/cli/InputHandler.java
@@ -24,7 +24,6 @@ import java.io.File;
import java.io.OutputStream;
import java.util.Vector;
-// Imported TraX classes
import javax.xml.transform.ErrorListener;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
@@ -37,6 +36,7 @@ import javax.xml.transform.stream.StreamSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
@@ -50,7 +50,8 @@ import org.apache.fop.render.awt.viewer.Renderable;
*/
public class InputHandler implements ErrorListener, Renderable {
- private File sourcefile = null; // either FO or XML/XSLT usage
+ /** original source file */
+ protected File sourcefile = null;
private File stylesheet = null; // for XML/XSLT usage
private Vector xsltParams = null; // for XML/XSLT usage
@@ -132,6 +133,26 @@ public class InputHandler implements ErrorListener, Renderable {
}
/**
+ * Creates a Source for the main input file.
+ * @return the Source for the main input file
+ */
+ protected Source createMainSource() {
+ return new StreamSource(this.sourcefile);
+ }
+
+ /**
+ * Creates a Source for the selected stylesheet.
+ * @return the Source for the selected stylesheet or null if there's no stylesheet
+ */
+ protected Source createXSLTSource() {
+ if (this.stylesheet != null) {
+ return new StreamSource(this.stylesheet);
+ } else {
+ return null;
+ }
+ }
+
+ /**
* Transforms the input document to the input format expected by FOP using XSLT.
* @param result the Result object where the result of the XSL transformation is sent to
* @throws FOPException in case of an error during processing
@@ -142,11 +163,11 @@ public class InputHandler implements ErrorListener, Renderable {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer;
- if (stylesheet == null) { // FO Input
+ Source xsltSource = createXSLTSource();
+ if (xsltSource == null) { // FO Input
transformer = factory.newTransformer();
} else { // XML/XSLT input
- transformer = factory.newTransformer(new StreamSource(
- stylesheet));
+ transformer = factory.newTransformer(xsltSource);
// Set the value of parameters, if any, defined for stylesheet
if (xsltParams != null) {
@@ -159,7 +180,7 @@ public class InputHandler implements ErrorListener, Renderable {
transformer.setErrorListener(this);
// Create a SAXSource from the input Source file
- Source src = new StreamSource(sourcefile);
+ Source src = createMainSource();
// Start XSLT transformation and FOP processing
transformer.transform(src, result);
diff --git a/src/java/org/apache/fop/cli/image2fo.xsl b/src/java/org/apache/fop/cli/image2fo.xsl
new file mode 100644
index 000000000..3a2610230
--- /dev/null
+++ b/src/java/org/apache/fop/cli/image2fo.xsl
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- $Id$ -->
+<xsl:stylesheet
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"
+ version="1.0">
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template name="masters">
+ <fo:layout-master-set>
+ <!-- not really used but mandatory -->
+ <fo:simple-page-master master-name="dummy" page-height="29.7cm" page-width="21cm">
+ <fo:region-body/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+ </xsl:template>
+
+ <xsl:template match="/image">
+ <fo:root>
+ <xsl:call-template name="masters"/>
+ <fox:external-document>
+ <xsl:attribute name="src"><xsl:value-of select="."/></xsl:attribute>
+ </fox:external-document>
+ </fo:root>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/java/org/apache/fop/fo/FOTreeBuilder.java b/src/java/org/apache/fop/fo/FOTreeBuilder.java
index 980404ffd..63fc5cb5b 100644
--- a/src/java/org/apache/fop/fo/FOTreeBuilder.java
+++ b/src/java/org/apache/fop/fo/FOTreeBuilder.java
@@ -276,9 +276,7 @@ public class FOTreeBuilder extends DefaultHandler {
*/
private int nestedMarkerDepth = 0;
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public void startElement(String namespaceURI, String localName, String rawName,
Attributes attlist) throws SAXException {
@@ -359,19 +357,16 @@ public class FOTreeBuilder extends DefaultHandler {
}
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public void endElement(String uri, String localName, String rawName)
throws SAXException {
if (currentFObj == null) {
- throw new IllegalStateException(
+ throw new SAXException(
"endElement() called for " + rawName
+ " where there is no current element.");
- } else
- if (!currentFObj.getLocalName().equals(localName)
+ } else if (!currentFObj.getLocalName().equals(localName)
|| !currentFObj.getNamespaceURI().equals(uri)) {
- log.warn("Mismatch: " + currentFObj.getLocalName()
+ throw new SAXException("Mismatch: " + currentFObj.getLocalName()
+ " (" + currentFObj.getNamespaceURI()
+ ") vs. " + localName + " (" + uri + ")");
}
diff --git a/src/java/org/apache/fop/fo/flow/ExternalGraphic.java b/src/java/org/apache/fop/fo/flow/ExternalGraphic.java
index f0285e6f4..dd45f585c 100644
--- a/src/java/org/apache/fop/fo/flow/ExternalGraphic.java
+++ b/src/java/org/apache/fop/fo/flow/ExternalGraphic.java
@@ -19,15 +19,22 @@
package org.apache.fop.fo.flow;
+import java.io.IOException;
+
+import org.xml.sax.Locator;
+
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.datatypes.Length;
+import org.apache.fop.datatypes.URISpecification;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.image.ImageFactory;
-import org.xml.sax.Locator;
+import org.apache.fop.fo.properties.FixedLength;
/**
* Class modelling the fo:external-graphic object.
@@ -63,21 +70,25 @@ public class ExternalGraphic extends AbstractGraphics {
super.bind(pList);
src = pList.get(PR_SRC).getString();
- //Additional processing: preload image
- url = ImageFactory.getURL(getSrc());
+ //Additional processing: obtain the image's intrinsic size and baseline information
+ url = URISpecification.getURL(src);
FOUserAgent userAgent = getUserAgent();
- ImageFactory fact = userAgent.getFactory().getImageFactory();
- FopImage fopimage = fact.getImage(url, userAgent);
- if (fopimage == null) {
- log.error("Image not available: " + getSrc());
- } else {
- // load dimensions
- if (!fopimage.load(FopImage.DIMENSIONS)) {
- log.error("Cannot read image dimensions: " + getSrc());
+ ImageManager manager = userAgent.getFactory().getImageManager();
+ ImageInfo info = null;
+ try {
+ info = manager.getImageInfo(url, userAgent.getImageSessionContext());
+ } catch (ImageException e) {
+ log.error("Image not available: " + e.getMessage());
+ } catch (IOException ioe) {
+ log.error("I/O error while loading image: " + ioe.getMessage());
+ }
+ if (info != null) {
+ this.intrinsicWidth = info.getSize().getWidthMpt();
+ this.intrinsicHeight = info.getSize().getHeightMpt();
+ int baseline = info.getSize().getBaselinePositionFromBottom();
+ if (baseline != 0) {
+ this.intrinsicAlignmentAdjust = new FixedLength(-baseline);
}
- this.intrinsicWidth = fopimage.getIntrinsicWidth();
- this.intrinsicHeight = fopimage.getIntrinsicHeight();
- this.intrinsicAlignmentAdjust = fopimage.getIntrinsicAlignmentAdjust();
}
//TODO Report to caller so he can decide to throw an exception
}
diff --git a/src/java/org/apache/fop/fo/pagination/Root.java b/src/java/org/apache/fop/fo/pagination/Root.java
index 139f7606a..6e079cf47 100644
--- a/src/java/org/apache/fop/fo/pagination/Root.java
+++ b/src/java/org/apache/fop/fo/pagination/Root.java
@@ -31,8 +31,8 @@ import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
-import org.apache.fop.fo.pagination.bookmarks.BookmarkTree;
import org.apache.fop.fo.extensions.destination.Destination;
+import org.apache.fop.fo.pagination.bookmarks.BookmarkTree;
/**
* The fo:root formatting object. Contains page masters, page-sequences.
@@ -73,20 +73,16 @@ public class Root extends FObj {
}
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public void bind(PropertyList pList) throws FOPException {
mediaUsage = pList.get(PR_MEDIA_USAGE).getEnum();
}
- /**
- * Signal end of this xml element.
- */
+ /** {@inheritDoc} */
protected void endOfNode() throws FOPException {
if (!pageSequenceFound || layoutMasterSet == null) {
- missingChildElementError("(layout-master-set, declarations?, " +
- "bookmark-tree?, (page-sequence+|fox:external-document))");
+ missingChildElementError("(layout-master-set, declarations?, "
+ + "bookmark-tree?, (page-sequence|fox:external-document)+)");
}
}
diff --git a/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java b/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
index 866a020e2..68d4bcab1 100755
--- a/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
+++ b/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
@@ -21,13 +21,16 @@ package org.apache.fop.fo.properties;
import java.awt.Color;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.datatypes.Length;
import org.apache.fop.datatypes.PercentBaseContext;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.expr.PropertyException;
-import org.apache.fop.image.FopImage;
import org.apache.fop.image.ImageFactory;
/**
@@ -66,7 +69,7 @@ public class CommonBorderPaddingBackground {
public Length backgroundPositionVertical;
- private FopImage fopimage;
+ private ImageInfo backgroundImageInfo;
/** the "before" edge */
@@ -232,18 +235,16 @@ public class CommonBorderPaddingBackground {
Constants.PR_BACKGROUND_POSITION_VERTICAL).getLength();
//Additional processing: preload image
- String url = ImageFactory.getURL(backgroundImage);
+ String uri = ImageFactory.getURL(backgroundImage);
FOUserAgent userAgent = pList.getFObj().getUserAgent();
- ImageFactory fact = userAgent.getFactory().getImageFactory();
- fopimage = fact.getImage(url, userAgent);
- if (fopimage == null) {
- Property.log.error("Background image not available: " + backgroundImage);
- } else {
- // load dimensions
- if (!fopimage.load(FopImage.DIMENSIONS)) {
- Property.log.error("Cannot read background image dimensions: "
- + backgroundImage);
- }
+ ImageManager manager = userAgent.getFactory().getImageManager();
+ ImageSessionContext sessionContext = userAgent.getImageSessionContext();
+ ImageInfo info;
+ try {
+ info = manager.getImageInfo(uri, sessionContext);
+ this.backgroundImageInfo = info;
+ } catch (Exception e) {
+ Property.log.error("Background image not available: " + uri);
}
//TODO Report to caller so he can decide to throw an exception
}
@@ -315,11 +316,11 @@ public class CommonBorderPaddingBackground {
}
/**
- * @return the background image as a preloaded FopImage, null if there is
+ * @return the background image info object, null if there is
* no background image.
*/
- public FopImage getFopImage() {
- return this.fopimage;
+ public ImageInfo getImageInfo() {
+ return this.backgroundImageInfo;
}
/**
@@ -455,7 +456,7 @@ public class CommonBorderPaddingBackground {
* @return true if there is any kind of background to be painted
*/
public boolean hasBackground() {
- return ((backgroundColor != null || getFopImage() != null));
+ return ((backgroundColor != null || getImageInfo() != null));
}
/** @return true if border is non-zero. */
diff --git a/src/java/org/apache/fop/image/loader/batik/BatikUtil.java b/src/java/org/apache/fop/image/loader/batik/BatikUtil.java
new file mode 100644
index 000000000..1ae2a9917
--- /dev/null
+++ b/src/java/org/apache/fop/image/loader/batik/BatikUtil.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.image.loader.batik;
+
+/**
+ * Helper utilities for Apache Batik.
+ */
+public class BatikUtil {
+
+ /**
+ * Checks whether Apache Batik is available in the classpath.
+ * @return true if Apache Batik is available
+ */
+ public static boolean isBatikAvailable() {
+ try {
+ Class.forName("org.apache.batik.dom.svg.SVGDOMImplementation");
+ return true;
+ } catch (Exception e) {
+ //ignore
+ }
+ return false;
+ }
+
+}
diff --git a/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java b/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java
new file mode 100644
index 000000000..81b3b4c07
--- /dev/null
+++ b/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.image.loader.batik;
+
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.util.Map;
+
+import org.apache.batik.bridge.BridgeContext;
+import org.apache.batik.bridge.GVTBuilder;
+import org.apache.batik.dom.svg.SVGDOMImplementation;
+import org.apache.batik.gvt.GraphicsNode;
+
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.ImageProcessingHints;
+import org.apache.xmlgraphics.image.loader.impl.AbstractImageConverter;
+import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
+import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
+import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
+import org.apache.xmlgraphics.util.UnitConv;
+
+import org.apache.fop.svg.SVGUserAgent;
+
+/**
+ * This ImageConverter converts SVG images to Java2D.
+ * <p>
+ * Note: The target flavor is "generic" Java2D. No Batik-specific bridges are hooked into the
+ * conversion process. Specialized renderers may want to provide specialized adapters to profit
+ * from target-format features (for example with PDF or PS). This converter is mainly for formats
+ * which only support bitmap images or rudimentary Java2D support.
+ */
+public class ImageConverterSVG2G2D extends AbstractImageConverter {
+
+ /** {@inheritDoc} */
+ public Image convert(Image src, Map hints) throws ImageException {
+ checkSourceFlavor(src);
+ final ImageXMLDOM svg = (ImageXMLDOM)src;
+ if (!SVGDOMImplementation.SVG_NAMESPACE_URI.equals(svg.getRootNamespace())) {
+ throw new IllegalArgumentException("XML DOM is not in the SVG namespace: "
+ + svg.getRootNamespace());
+ }
+
+ //Prepare
+ float pxToMillimeter = (float)UnitConv.mm2in(72); //default: 72dpi
+ Number ptm = (Number)hints.get(ImageProcessingHints.SOURCE_RESOLUTION);
+ if (ptm != null) {
+ pxToMillimeter = (float)UnitConv.mm2in(ptm.doubleValue());
+ }
+ SVGUserAgent ua = new SVGUserAgent(
+ pxToMillimeter,
+ new AffineTransform());
+ GVTBuilder builder = new GVTBuilder();
+ final BridgeContext ctx = new BridgeContext(ua);
+
+ //Build the GVT tree
+ final GraphicsNode root;
+ try {
+ root = builder.build(ctx, svg.getDocument());
+ } catch (Exception e) {
+ throw new ImageException("GVT tree could not be built for SVG graphic", e);
+ }
+
+ //Create the painter
+ Graphics2DImagePainter painter = new Graphics2DImagePainter() {
+
+ public void paint(Graphics2D g2d, Rectangle2D area) {
+ // If no viewbox is defined in the svg file, a viewbox of 100x100 is
+ // assumed, as defined in SVGUserAgent.getViewportSize()
+ float iw = (float) ctx.getDocumentSize().getWidth();
+ float ih = (float) ctx.getDocumentSize().getHeight();
+ float w = (float) area.getWidth();
+ float h = (float) area.getHeight();
+ g2d.translate(area.getX(), area.getY());
+ g2d.scale(w / iw, h / ih);
+
+ root.paint(g2d);
+ }
+
+ public Dimension getImageSize() {
+ return new Dimension(svg.getSize().getWidthMpt(), svg.getSize().getHeightMpt());
+ }
+
+ };
+
+ ImageGraphics2D g2dImage = new ImageGraphics2D(src.getInfo(), painter);
+ return g2dImage;
+ }
+
+ /** {@inheritDoc} */
+ public ImageFlavor getSourceFlavor() {
+ return ImageFlavor.XML_DOM;
+ }
+
+ /** {@inheritDoc} */
+ public ImageFlavor getTargetFlavor() {
+ return ImageFlavor.GRAPHICS2D;
+ }
+
+}
diff --git a/src/java/org/apache/fop/image/loader/batik/ImageConverterWMF2G2D.java b/src/java/org/apache/fop/image/loader/batik/ImageConverterWMF2G2D.java
new file mode 100644
index 000000000..6babe4523
--- /dev/null
+++ b/src/java/org/apache/fop/image/loader/batik/ImageConverterWMF2G2D.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.image.loader.batik;
+
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Map;
+
+import org.apache.batik.transcoder.wmf.tosvg.WMFPainter;
+import org.apache.batik.transcoder.wmf.tosvg.WMFRecordStore;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.impl.AbstractImageConverter;
+import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
+import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
+
+/**
+ * This ImageConverter converts WMF (Windows Metafile) images (represented by Batik's
+ * WMFRecordStore) to Java2D.
+ */
+public class ImageConverterWMF2G2D extends AbstractImageConverter {
+
+ /** logger */
+ private static Log log = LogFactory.getLog(ImageConverterWMF2G2D.class);
+
+ /** {@inheritDoc} */
+ public Image convert(Image src, Map hints) {
+ checkSourceFlavor(src);
+ ImageWMF wmf = (ImageWMF)src;
+
+ Graphics2DImagePainter painter;
+ painter = new Graphics2DImagePainterWMF(wmf);
+
+ ImageGraphics2D g2dImage = new ImageGraphics2D(src.getInfo(), painter);
+ return g2dImage;
+ }
+
+ /** {@inheritDoc} */
+ public ImageFlavor getSourceFlavor() {
+ return ImageWMF.WMF_IMAGE;
+ }
+
+ /** {@inheritDoc} */
+ public ImageFlavor getTargetFlavor() {
+ return ImageFlavor.GRAPHICS2D;
+ }
+
+ private static class Graphics2DImagePainterWMF implements Graphics2DImagePainter {
+
+ private ImageWMF wmf;
+
+ public Graphics2DImagePainterWMF(ImageWMF wmf) {
+ this.wmf = wmf;
+ }
+
+ /** {@inheritDoc} */
+ public Dimension getImageSize() {
+ return wmf.getSize().getDimensionMpt();
+ }
+
+ /** {@inheritDoc} */
+ public void paint(Graphics2D g2d, Rectangle2D area) {
+ WMFRecordStore wmfStore = wmf.getRecordStore();
+ double w = area.getWidth();
+ double h = area.getHeight();
+
+ //Fit in paint area
+ g2d.translate(area.getX(), area.getY());
+ double sx = w / wmfStore.getWidthPixels();
+ double sy = h / wmfStore.getHeightPixels();
+ if (sx != 1.0 || sy != 1.0) {
+ g2d.scale(sx, sy);
+ }
+
+ WMFPainter painter = new WMFPainter(wmfStore, 1.0f);
+ long start = System.currentTimeMillis();
+ painter.paint(g2d);
+ if (log.isDebugEnabled()) {
+ long duration = System.currentTimeMillis() - start;
+ log.debug("Painting WMF took " + duration + " ms.");
+ }
+ }
+
+ }
+
+}
diff --git a/src/java/org/apache/fop/image/loader/batik/ImageLoaderFactorySVG.java b/src/java/org/apache/fop/image/loader/batik/ImageLoaderFactorySVG.java
new file mode 100644
index 000000000..fa58d8e4a
--- /dev/null
+++ b/src/java/org/apache/fop/image/loader/batik/ImageLoaderFactorySVG.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.image.loader.batik;
+
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.impl.AbstractImageLoaderFactory;
+import org.apache.xmlgraphics.image.loader.spi.ImageLoader;
+import org.apache.xmlgraphics.util.MimeConstants;
+
+/**
+ * Factory class for the ImageLoader for SVG.
+ */
+public class ImageLoaderFactorySVG extends AbstractImageLoaderFactory {
+
+ private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
+ ImageFlavor.XML_DOM};
+
+ private static final String[] MIMES = new String[] {
+ MimeConstants.MIME_SVG};
+
+ /** {@inheritDoc} */
+ public String[] getSupportedMIMETypes() {
+ return MIMES;
+ }
+
+ /** {@inheritDoc} */
+ public ImageFlavor[] getSupportedFlavors(String mime) {
+ return FLAVORS;
+ }
+
+ /** {@inheritDoc} */
+ public ImageLoader newImageLoader(ImageFlavor targetFlavor) {
+ return new ImageLoaderSVG(targetFlavor);
+ }
+
+ /** {@inheritDoc} */
+ public int getUsagePenalty(String mime, ImageFlavor flavor) {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isAvailable() {
+ return BatikUtil.isBatikAvailable();
+ }
+
+}
diff --git a/src/java/org/apache/fop/image/loader/batik/ImageLoaderFactoryWMF.java b/src/java/org/apache/fop/image/loader/batik/ImageLoaderFactoryWMF.java
new file mode 100644
index 000000000..bfa004d7e
--- /dev/null
+++ b/src/java/org/apache/fop/image/loader/batik/ImageLoaderFactoryWMF.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.image.loader.batik;
+
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.impl.AbstractImageLoaderFactory;
+import org.apache.xmlgraphics.image.loader.spi.ImageLoader;
+
+/**
+ * Factory class for the ImageLoader for WMF (Windows Metafile).
+ */
+public class ImageLoaderFactoryWMF extends AbstractImageLoaderFactory {
+
+ private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
+ ImageWMF.WMF_IMAGE};
+
+ private static final String[] MIMES = new String[] {
+ ImageWMF.MIME_WMF};
+
+ /** {@inheritDoc} */
+ public String[] getSupportedMIMETypes() {
+ return MIMES;
+ }
+
+ /** {@inheritDoc} */
+ public ImageFlavor[] getSupportedFlavors(String mime) {
+ return FLAVORS;
+ }
+
+ /** {@inheritDoc} */
+ public ImageLoader newImageLoader(ImageFlavor targetFlavor) {
+ return new ImageLoaderWMF(targetFlavor);
+ }
+
+ /** {@inheritDoc} */
+ public int getUsagePenalty(String mime, ImageFlavor flavor) {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isAvailable() {
+ return BatikUtil.isBatikAvailable();
+ }
+
+}
diff --git a/src/java/org/apache/fop/image/loader/batik/ImageLoaderSVG.java b/src/java/org/apache/fop/image/loader/batik/ImageLoaderSVG.java
new file mode 100644
index 000000000..64aff962b
--- /dev/null
+++ b/src/java/org/apache/fop/image/loader/batik/ImageLoaderSVG.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.image.loader.batik;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.batik.dom.svg.SVGDOMImplementation;
+
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+import org.apache.xmlgraphics.image.loader.impl.AbstractImageLoader;
+import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
+import org.apache.xmlgraphics.util.MimeConstants;
+
+/**
+ * ImageLoader for SVG (using Apache Batik).
+ */
+public class ImageLoaderSVG extends AbstractImageLoader {
+
+ private ImageFlavor targetFlavor;
+
+ /**
+ * Main constructor.
+ * @param targetFlavor the target flavor
+ */
+ public ImageLoaderSVG(ImageFlavor targetFlavor) {
+ if (!(ImageFlavor.XML_DOM.equals(targetFlavor))) {
+ throw new IllegalArgumentException("Unsupported target ImageFlavor: " + targetFlavor);
+ }
+ this.targetFlavor = targetFlavor;
+ }
+
+ /** {@inheritDoc} */
+ public ImageFlavor getTargetFlavor() {
+ return this.targetFlavor;
+ }
+
+ /** {@inheritDoc} */
+ public Image loadImage(ImageInfo info, Map hints, ImageSessionContext session)
+ throws ImageException, IOException {
+ if (!MimeConstants.MIME_SVG.equals(info.getMimeType())) {
+ throw new IllegalArgumentException("ImageInfo must be from an SVG image");
+ }
+ Image img = info.getOriginalImage();
+ if (!(img instanceof ImageXMLDOM)) {
+ throw new IllegalArgumentException(
+ "ImageInfo was expected to contain the SVG document as DOM");
+ }
+ ImageXMLDOM svgImage = (ImageXMLDOM)img;
+ if (!SVGDOMImplementation.SVG_NAMESPACE_URI.equals(svgImage.getRootNamespace())) {
+ throw new IllegalArgumentException(
+ "The Image is not in the SVG namespace: " + svgImage.getRootNamespace());
+ }
+ return svgImage;
+ }
+
+}
diff --git a/src/java/org/apache/fop/image/loader/batik/ImageLoaderWMF.java b/src/java/org/apache/fop/image/loader/batik/ImageLoaderWMF.java
new file mode 100644
index 000000000..e7f3e0f0a
--- /dev/null
+++ b/src/java/org/apache/fop/image/loader/batik/ImageLoaderWMF.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.image.loader.batik;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+import org.apache.xmlgraphics.image.loader.impl.AbstractImageLoader;
+
+/**
+ * ImageLoader for WMF (Windows Metafile). Depends on the WMF preloader based on Apache Batik.
+ */
+public class ImageLoaderWMF extends AbstractImageLoader {
+
+ private ImageFlavor targetFlavor;
+
+ /**
+ * Main constructor.
+ * @param targetFlavor the target flavor
+ */
+ public ImageLoaderWMF(ImageFlavor targetFlavor) {
+ if (!(ImageWMF.WMF_IMAGE.equals(targetFlavor))) {
+ throw new IllegalArgumentException("Unsupported target ImageFlavor: " + targetFlavor);
+ }
+ this.targetFlavor = targetFlavor;
+ }
+
+ /** {@inheritDoc} */
+ public ImageFlavor getTargetFlavor() {
+ return this.targetFlavor;
+ }
+
+ /** {@inheritDoc} */
+ public Image loadImage(ImageInfo info, Map hints, ImageSessionContext session)
+ throws ImageException, IOException {
+ if (!ImageWMF.MIME_WMF.equals(info.getMimeType())) {
+ throw new IllegalArgumentException("ImageInfo must be from a WMF image");
+ }
+ Image img = info.getOriginalImage();
+ if (!(img instanceof ImageWMF)) {
+ throw new IllegalArgumentException(
+ "ImageInfo was expected to contain the Windows Metafile (WMF)");
+ }
+ ImageWMF wmfImage = (ImageWMF)img;
+ return wmfImage;
+ }
+
+}
diff --git a/src/java/org/apache/fop/image/loader/batik/ImageWMF.java b/src/java/org/apache/fop/image/loader/batik/ImageWMF.java
new file mode 100644
index 000000000..f785d27cc
--- /dev/null
+++ b/src/java/org/apache/fop/image/loader/batik/ImageWMF.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.image.loader.batik;
+
+import org.apache.batik.transcoder.wmf.tosvg.WMFRecordStore;
+
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.impl.AbstractImage;
+
+/**
+ * This class is an implementation of the Image interface exposing a RenderedImage.
+ */
+public class ImageWMF extends AbstractImage {
+
+ /** MIME type for WMF */
+ public static final String MIME_WMF = "image/x-wmf";
+
+ /** ImageFlavor for Batik's WMFRecordStore */
+ public static final ImageFlavor WMF_IMAGE = new ImageFlavor("WMFRecordStore");
+
+ private WMFRecordStore store;
+
+ /**
+ * Main constructor.
+ * @param info the image info object
+ * @param store the WMF record store containing the loaded WMF file
+ */
+ public ImageWMF(ImageInfo info, WMFRecordStore store) {
+ super(info);
+ this.store = store;
+ }
+
+ /** {@inheritDoc} */
+ public ImageFlavor getFlavor() {
+ return WMF_IMAGE;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isCacheable() {
+ return true;
+ }
+
+ /**
+ * Returns the contained WMF record store.
+ * @return the WMFRecordStore
+ */
+ public WMFRecordStore getRecordStore() {
+ return this.store;
+ }
+
+}
diff --git a/src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java b/src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java
new file mode 100644
index 000000000..e83a302da
--- /dev/null
+++ b/src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.image.loader.batik;
+
+import java.awt.geom.AffineTransform;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.Source;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.svg.SVGDocument;
+
+import org.apache.batik.bridge.BridgeContext;
+import org.apache.batik.bridge.UnitProcessor;
+import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
+import org.apache.batik.dom.svg.SVGDOMImplementation;
+import org.apache.batik.dom.svg.SVGOMDocument;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.xmlgraphics.image.loader.ImageContext;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageSize;
+import org.apache.xmlgraphics.image.loader.impl.AbstractImagePreloader;
+import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
+import org.apache.xmlgraphics.image.loader.util.ImageUtil;
+import org.apache.xmlgraphics.util.MimeConstants;
+
+import org.apache.fop.svg.SVGUserAgent;
+import org.apache.fop.util.UnclosableInputStream;
+
+/**
+ * Image preloader for SVG images.
+ */
+public class PreloaderSVG extends AbstractImagePreloader {
+
+ /** Logger instance */
+ private static Log log = LogFactory.getLog(PreloaderSVG.class);
+
+ private boolean batikAvailable = true;
+
+ /** {@inheritDoc} */
+ public ImageInfo preloadImage(String uri, Source src, ImageContext context)
+ throws IOException {
+ if (!ImageUtil.hasInputStream(src)) {
+ //TODO Remove this and support DOMSource and possibly SAXSource
+ return null;
+ }
+ ImageInfo info = null;
+ if (batikAvailable) {
+ try {
+ Loader loader = new Loader();
+ info = loader.getImage(uri, src, context);
+ } catch (NoClassDefFoundError e) {
+ batikAvailable = false;
+ log.warn("Batik not in class path", e);
+ return null;
+ }
+ }
+ if (info != null) {
+ ImageUtil.closeQuietly(src); //Image is fully read
+ }
+ return info;
+ }
+
+ /**
+ * Returns the fully qualified classname of an XML parser for
+ * Batik classes that apparently need it (error messages, perhaps)
+ * @return an XML parser classname
+ */
+ public static String getParserName() {
+ try {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ return factory.newSAXParser().getXMLReader().getClass().getName();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * This method is put in another class so that the class loader does not
+ * attempt to load Batik related classes when constructing the SVGPreloader
+ * class.
+ */
+ class Loader {
+ private ImageInfo getImage(String uri, Source src,
+ ImageContext context) {
+ // parse document and get the size attributes of the svg element
+
+ InputStream in = new UnclosableInputStream(ImageUtil.needInputStream(src));
+ try {
+ int length = in.available();
+ in.mark(length + 1);
+ SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(
+ getParserName());
+ SVGDocument doc = (SVGDocument) factory.createSVGDocument(src.getSystemId(), in);
+
+ Element e = doc.getRootElement();
+ float pxUnitToMillimeter = 25.4f / context.getSourceResolution();
+ SVGUserAgent userAg = new SVGUserAgent(pxUnitToMillimeter,
+ new AffineTransform());
+ BridgeContext ctx = new BridgeContext(userAg);
+ UnitProcessor.Context uctx = UnitProcessor.createContext(ctx, e);
+
+ String s;
+ // 'width' attribute - default is 100%
+ s = e.getAttributeNS(null, SVGOMDocument.SVG_WIDTH_ATTRIBUTE);
+ if (s.length() == 0) {
+ s = SVGOMDocument.SVG_SVG_WIDTH_DEFAULT_VALUE;
+ }
+ float width = UnitProcessor.svgHorizontalLengthToUserSpace(
+ s, SVGOMDocument.SVG_WIDTH_ATTRIBUTE, uctx);
+
+ // 'height' attribute - default is 100%
+ s = e.getAttributeNS(null, SVGOMDocument.SVG_HEIGHT_ATTRIBUTE);
+ if (s.length() == 0) {
+ s = SVGOMDocument.SVG_SVG_HEIGHT_DEFAULT_VALUE;
+ }
+ float height = UnitProcessor.svgVerticalLengthToUserSpace(
+ s, SVGOMDocument.SVG_HEIGHT_ATTRIBUTE, uctx);
+
+ ImageInfo info = new ImageInfo(uri, MimeConstants.MIME_SVG);
+ ImageSize size = new ImageSize();
+ size.setSizeInMillipoints(Math.round(width * 1000), Math.round(height * 1000));
+ //Set the resolution to that of the FOUserAgent
+ size.setResolution(context.getSourceResolution());
+ size.calcPixelsFromSize();
+ info.setSize(size);
+
+ //The whole image had to be loaded for this, so keep it
+ ImageXMLDOM xmlImage = new ImageXMLDOM(info,
+ doc, SVGDOMImplementation.SVG_NAMESPACE_URI);
+ info.getCustomObjects().put(ImageInfo.ORIGINAL_IMAGE, xmlImage);
+
+ return info;
+ } catch (NoClassDefFoundError ncdfe) {
+ try {
+ in.reset();
+ } catch (IOException ioe) {
+ // we're more interested in the original exception
+ }
+ batikAvailable = false;
+ log.warn("Batik not in class path", ncdfe);
+ return null;
+ } catch (IOException e) {
+ // If the svg is invalid then it throws an IOException
+ // so there is no way of knowing if it is an svg document
+
+ log.debug("Error while trying to load stream as an SVG file: "
+ + e.getMessage());
+ // assuming any exception means this document is not svg
+ // or could not be loaded for some reason
+ try {
+ in.reset();
+ } catch (IOException ioe) {
+ // we're more interested in the original exception
+ }
+ return null;
+ }
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java b/src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java
new file mode 100644
index 000000000..abb740411
--- /dev/null
+++ b/src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.image.loader.batik;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.transform.Source;
+
+import org.apache.batik.transcoder.wmf.WMFConstants;
+import org.apache.batik.transcoder.wmf.tosvg.WMFRecordStore;
+import org.apache.commons.io.EndianUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.xmlgraphics.image.loader.ImageContext;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageSize;
+import org.apache.xmlgraphics.image.loader.impl.AbstractImagePreloader;
+import org.apache.xmlgraphics.image.loader.util.ImageUtil;
+
+import org.apache.fop.util.UnclosableInputStream;
+
+/**
+ * Image preloader for WMF images (Windows Metafile).
+ */
+public class PreloaderWMF extends AbstractImagePreloader {
+
+ /** Logger instance */
+ private static Log log = LogFactory.getLog(PreloaderWMF.class);
+
+ private boolean batikAvailable = true;
+
+ /** {@inheritDoc} */
+ public ImageInfo preloadImage(String uri, Source src, ImageContext context)
+ throws IOException {
+ if (!ImageUtil.hasInputStream(src)) {
+ return null;
+ }
+ ImageInfo info = null;
+ if (batikAvailable) {
+ try {
+ Loader loader = new Loader();
+ info = loader.getImage(uri, src, context);
+ } catch (NoClassDefFoundError e) {
+ batikAvailable = false;
+ log.warn("Batik not in class path", e);
+ return null;
+ }
+ }
+ if (info != null) {
+ ImageUtil.closeQuietly(src); //Image is fully read
+ }
+ return info;
+ }
+
+ /**
+ * This method is put in another class so that the class loader does not
+ * attempt to load Batik related classes when constructing the WMFPreloader
+ * class.
+ */
+ class Loader {
+ private ImageInfo getImage(String uri, Source src,
+ ImageContext context) {
+ // parse document and get the size attributes of the svg element
+
+ InputStream in = new UnclosableInputStream(ImageUtil.needInputStream(src));
+ try {
+ in.mark(4 + 1);
+
+ DataInputStream din = new DataInputStream(in);
+ int magic = EndianUtils.swapInteger(din.readInt());
+ din.reset();
+ if (magic != WMFConstants.META_ALDUS_APM) {
+ return null; //Not a WMF file
+ }
+
+ WMFRecordStore wmfStore = new WMFRecordStore();
+ wmfStore.read(din);
+ IOUtils.closeQuietly(din);
+
+ int width = wmfStore.getWidthUnits();
+ int height = wmfStore.getHeightUnits();
+ int dpi = wmfStore.getMetaFileUnitsPerInch();
+
+ ImageInfo info = new ImageInfo(uri, "image/x-wmf");
+ ImageSize size = new ImageSize();
+ size.setSizeInPixels(width, height);
+ size.setResolution(dpi);
+ size.calcSizeFromPixels();
+ info.setSize(size);
+ ImageWMF img = new ImageWMF(info, wmfStore);
+ info.getCustomObjects().put(ImageInfo.ORIGINAL_IMAGE, img);
+
+ return info;
+ } catch (NoClassDefFoundError ncdfe) {
+ try {
+ in.reset();
+ } catch (IOException ioe) {
+ // we're more interested in the original exception
+ }
+ batikAvailable = false;
+ log.warn("Batik not in class path", ncdfe);
+ return null;
+ } catch (IOException e) {
+ // If the svg is invalid then it throws an IOException
+ // so there is no way of knowing if it is an svg document
+
+ log.debug("Error while trying to load stream as an WMF file: "
+ + e.getMessage());
+ // assuming any exception means this document is not svg
+ // or could not be loaded for some reason
+ try {
+ in.reset();
+ } catch (IOException ioe) {
+ // we're more interested in the original exception
+ }
+ return null;
+ }
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/image/loader/batik/package.html b/src/java/org/apache/fop/image/loader/batik/package.html
new file mode 100644
index 000000000..f664913d7
--- /dev/null
+++ b/src/java/org/apache/fop/image/loader/batik/package.html
@@ -0,0 +1,26 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- $Id$ -->
+<HTML>
+<TITLE>org.apache.fop.image2.impl.batik Package</TITLE>
+<BODY>
+<P>
+ Contains implementations of image loaders and converters which are dependent
+ on Apache Batik (SVG and WMF).
+</P>
+</BODY>
+</HTML> \ No newline at end of file
diff --git a/src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java
index 5668f81ef..0e51517f2 100644
--- a/src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java
@@ -21,10 +21,18 @@ package org.apache.fop.layoutmgr;
import java.awt.Dimension;
import java.awt.Rectangle;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.util.ImageUtil;
+
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.area.AreaTreeHandler;
import org.apache.fop.area.Block;
@@ -38,8 +46,6 @@ import org.apache.fop.area.inline.Viewport;
import org.apache.fop.datatypes.FODimension;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.extensions.ExternalDocument;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.image.ImageFactory;
import org.apache.fop.layoutmgr.inline.ImageLayout;
/**
@@ -51,14 +57,13 @@ public class ExternalDocumentLayoutManager extends AbstractPageSequenceLayoutMan
private static Log log = LogFactory.getLog(ExternalDocumentLayoutManager.class);
- private FopImage image;
private ImageLayout imageLayout;
/**
* Constructor
*
* @param ath the area tree handler object
- * @param pseq fo:page-sequence to process
+ * @param document fox:external-document to process
*/
public ExternalDocumentLayoutManager(AreaTreeHandler ath, ExternalDocument document) {
super(ath, document);
@@ -80,38 +85,78 @@ public class ExternalDocumentLayoutManager extends AbstractPageSequenceLayoutMan
public void activateLayout() {
initialize();
- String uri = getExternalDocument().getSrc();
FOUserAgent userAgent = pageSeq.getUserAgent();
- ImageFactory fact = userAgent.getFactory().getImageFactory();
- this.image = fact.getImage(uri, userAgent);
- if (this.image == null) {
- log.error("Image not available: " + uri);
- return;
- } else {
- // load dimensions
- if (!this.image.load(FopImage.DIMENSIONS)) {
- log.error("Cannot read image dimensions: " + uri);
- return;
- }
- }
- Dimension intrinsicSize = new Dimension(
- image.getIntrinsicWidth(),
- image.getIntrinsicHeight());
- this.imageLayout = new ImageLayout(getExternalDocument(), this, intrinsicSize);
+ ImageManager imageManager = userAgent.getFactory().getImageManager();
- areaTreeHandler.getAreaTreeModel().startPageSequence(null);
- if (log.isDebugEnabled()) {
- log.debug("Starting layout");
+ String uri = getExternalDocument().getSrc();
+ Integer firstPageIndex = ImageUtil.getPageIndexFromURI(uri);
+ boolean hasPageIndex = (firstPageIndex != null);
+
+ try {
+ ImageInfo info = imageManager.getImageInfo(uri, userAgent.getImageSessionContext());
+
+ Object moreImages = info.getCustomObjects().get(ImageInfo.HAS_MORE_IMAGES);
+ boolean hasMoreImages = moreImages != null && !Boolean.FALSE.equals(moreImages);
+
+ Dimension intrinsicSize = info.getSize().getDimensionMpt();
+ ImageLayout layout = new ImageLayout(getExternalDocument(), this, intrinsicSize);
+
+ areaTreeHandler.getAreaTreeModel().startPageSequence(null);
+ if (log.isDebugEnabled()) {
+ log.debug("Starting layout");
+ }
+
+ makePageForImage(info, layout);
+
+ if (!hasPageIndex && hasMoreImages) {
+ if (log.isTraceEnabled()) {
+ log.trace("Starting multi-page processing...");
+ }
+ URI originalURI;
+ try {
+ originalURI = new URI(uri);
+ int pageIndex = 1;
+ while (hasMoreImages) {
+ URI tempURI = new URI(originalURI.getScheme(),
+ originalURI.getSchemeSpecificPart(),
+ "page=" + Integer.toString(pageIndex + 1));
+ if (log.isTraceEnabled()) {
+ log.trace("Subimage: " + tempURI.toASCIIString());
+ }
+ ImageInfo subinfo = imageManager.getImageInfo(
+ tempURI.toASCIIString(), userAgent.getImageSessionContext());
+
+ moreImages = subinfo.getCustomObjects().get(ImageInfo.HAS_MORE_IMAGES);
+ hasMoreImages = moreImages != null && !Boolean.FALSE.equals(moreImages);
+
+ intrinsicSize = subinfo.getSize().getDimensionMpt();
+ layout = new ImageLayout(
+ getExternalDocument(), this, intrinsicSize);
+
+ makePageForImage(subinfo, layout);
+
+ pageIndex++;
+ }
+ } catch (URISyntaxException e) {
+ log.error("Error parsing or constructing URIs based on URI: " + uri);
+ return;
+ }
+ }
+ } catch (IOException ioe) {
+ log.error("Image not available: " + uri, ioe);
+ } catch (ImageException ie) {
+ log.error("Error while inspecting image: " + uri + " (" + ie.getMessage() + ")");
}
+ }
+ private void makePageForImage(ImageInfo info, ImageLayout layout) {
+ this.imageLayout = layout;
curPage = makeNewPage(false, false);
-
- fillPage(); //TODO Implement multi-page documents (using new image package)
-
+ fillPage(info.getOriginalURI());
finishPage();
}
-
- private void fillPage() {
+
+ private void fillPage(String uri) {
Dimension imageSize = this.imageLayout.getViewportSize();
@@ -119,7 +164,7 @@ public class ExternalDocumentLayoutManager extends AbstractPageSequenceLayoutMan
blockArea.setIPD(imageSize.width);
LineArea lineArea = new LineArea();
- Image imageArea = new Image(getExternalDocument().getSrc());
+ Image imageArea = new Image(uri);
TraitSetter.setProducerID(imageArea, fobj.getId());
transferForeignAttributes(imageArea);
diff --git a/src/java/org/apache/fop/layoutmgr/TraitSetter.java b/src/java/org/apache/fop/layoutmgr/TraitSetter.java
index b50167b16..f1e5ffdc6 100644
--- a/src/java/org/apache/fop/layoutmgr/TraitSetter.java
+++ b/src/java/org/apache/fop/layoutmgr/TraitSetter.java
@@ -21,20 +21,19 @@ package org.apache.fop.layoutmgr;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.fop.traits.BorderProps;
-import org.apache.fop.traits.MinOptMax;
+
import org.apache.fop.area.Area;
import org.apache.fop.area.Trait;
import org.apache.fop.datatypes.LengthBase;
import org.apache.fop.datatypes.PercentBaseContext;
import org.apache.fop.datatypes.SimplePercentBaseContext;
import org.apache.fop.fo.Constants;
-import org.apache.fop.fo.properties.CommonMarginBlock;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
+import org.apache.fop.fo.properties.CommonMarginBlock;
import org.apache.fop.fo.properties.CommonTextDecoration;
import org.apache.fop.fonts.Font;
-import org.apache.fop.fonts.FontInfo;
-import org.apache.fop.fonts.FontTriplet;
+import org.apache.fop.traits.BorderProps;
+import org.apache.fop.traits.MinOptMax;
/**
* This is a helper class used for setting common traits on areas.
@@ -303,9 +302,9 @@ public class TraitSetter {
Trait.Background back = new Trait.Background();
back.setColor(backProps.backgroundColor);
- if (backProps.getFopImage() != null) {
+ if (backProps.getImageInfo() != null) {
back.setURL(backProps.backgroundImage);
- back.setFopImage(backProps.getFopImage());
+ back.setImageInfo(backProps.getImageInfo());
back.setRepeat(backProps.backgroundRepeat);
if (backProps.backgroundPositionHorizontal != null) {
if (back.getRepeat() == Constants.EN_NOREPEAT
@@ -317,7 +316,7 @@ public class TraitSetter {
back.setHoriz(backProps.backgroundPositionHorizontal.getValue(
new SimplePercentBaseContext(context,
LengthBase.IMAGE_BACKGROUND_POSITION_HORIZONTAL,
- (width - back.getFopImage().getIntrinsicWidth())
+ (width - back.getImageInfo().getSize().getHeightMpt())
)
));
} else {
@@ -338,7 +337,7 @@ public class TraitSetter {
back.setVertical(backProps.backgroundPositionVertical.getValue(
new SimplePercentBaseContext(context,
LengthBase.IMAGE_BACKGROUND_POSITION_VERTICAL,
- (height - back.getFopImage().getIntrinsicHeight())
+ (height - back.getImageInfo().getSize().getHeightMpt())
)
));
} else {
diff --git a/src/java/org/apache/fop/layoutmgr/inline/ImageLayout.java b/src/java/org/apache/fop/layoutmgr/inline/ImageLayout.java
index b3ccea628..60247af39 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/ImageLayout.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/ImageLayout.java
@@ -29,7 +29,11 @@ import org.apache.fop.datatypes.Length;
import org.apache.fop.datatypes.PercentBaseContext;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.GraphicsProperties;
+import org.apache.fop.fo.properties.LengthRangeProperty;
+/**
+ * Helper class which calculates the size and position in the viewport of an image.
+ */
public class ImageLayout implements Constants {
/** logging instance */
@@ -45,6 +49,12 @@ public class ImageLayout implements Constants {
private Dimension viewportSize = new Dimension(-1, -1);
private boolean clip;
+ /**
+ * Main constructor
+ * @param props the properties for the image
+ * @param percentBaseContext the context object for percentage calculations
+ * @param intrinsicSize the image's intrinsic size
+ */
public ImageLayout(GraphicsProperties props, PercentBaseContext percentBaseContext,
Dimension intrinsicSize) {
this.props = props;
@@ -54,6 +64,9 @@ public class ImageLayout implements Constants {
doLayout();
}
+ /**
+ * Does the actual calculations for the image.
+ */
protected void doLayout() {
Length len;
@@ -63,25 +76,26 @@ public class ImageLayout implements Constants {
len = props.getBlockProgressionDimension().getOptimum(percentBaseContext).getLength();
if (len.getEnum() != EN_AUTO) {
bpd = len.getValue(percentBaseContext);
- } else {
- len = props.getHeight();
- if (len.getEnum() != EN_AUTO) {
- bpd = len.getValue(percentBaseContext);
- }
+ }
+ len = props.getBlockProgressionDimension().getMinimum(percentBaseContext).getLength();
+ if (bpd == -1 && len.getEnum() != EN_AUTO) {
+ //Establish minimum viewport size
+ bpd = len.getValue(percentBaseContext);
}
len = props.getInlineProgressionDimension().getOptimum(percentBaseContext).getLength();
if (len.getEnum() != EN_AUTO) {
ipd = len.getValue(percentBaseContext);
- } else {
- len = props.getWidth();
- if (len.getEnum() != EN_AUTO) {
- ipd = len.getValue(percentBaseContext);
- }
+ }
+ len = props.getInlineProgressionDimension().getMinimum(percentBaseContext).getLength();
+ if (ipd == -1 && len.getEnum() != EN_AUTO) {
+ //Establish minimum viewport size
+ ipd = len.getValue(percentBaseContext);
}
// if auto then use the intrinsic size of the content scaled
// to the content-height and content-width
+ boolean constrainIntrinsicSize = false;
int cwidth = -1;
int cheight = -1;
len = props.getContentWidth();
@@ -91,16 +105,19 @@ public class ImageLayout implements Constants {
if (ipd != -1) {
cwidth = ipd;
}
+ constrainIntrinsicSize = true;
break;
case EN_SCALE_DOWN_TO_FIT:
if (ipd != -1 && intrinsicSize.width > ipd) {
cwidth = ipd;
}
+ constrainIntrinsicSize = true;
break;
case EN_SCALE_UP_TO_FIT:
if (ipd != -1 && intrinsicSize.width < ipd) {
cwidth = ipd;
}
+ constrainIntrinsicSize = true;
break;
default:
cwidth = len.getValue(percentBaseContext);
@@ -113,64 +130,43 @@ public class ImageLayout implements Constants {
if (bpd != -1) {
cheight = bpd;
}
+ constrainIntrinsicSize = true;
break;
case EN_SCALE_DOWN_TO_FIT:
if (bpd != -1 && intrinsicSize.height > bpd) {
cheight = bpd;
}
+ constrainIntrinsicSize = true;
break;
case EN_SCALE_UP_TO_FIT:
if (bpd != -1 && intrinsicSize.height < bpd) {
cheight = bpd;
}
+ constrainIntrinsicSize = true;
break;
default:
cheight = len.getValue(percentBaseContext);
}
}
- int scaling = props.getScaling();
- if ((scaling == EN_UNIFORM) || (cwidth == -1) || cheight == -1) {
- if (cwidth == -1 && cheight == -1) {
- cwidth = intrinsicSize.width;
- cheight = intrinsicSize.height;
- } else if (cwidth == -1) {
- if (intrinsicSize.height == 0) {
- cwidth = 0;
- } else {
- cwidth = (int)(intrinsicSize.width * (double)cheight
- / intrinsicSize.height);
- }
- } else if (cheight == -1) {
- if (intrinsicSize.width == 0) {
- cheight = 0;
- } else {
- cheight = (int)(intrinsicSize.height * (double)cwidth
- / intrinsicSize.width);
- }
- } else {
- // adjust the larger
- if (intrinsicSize.width == 0 || intrinsicSize.height == 0) {
- cwidth = 0;
- cheight = 0;
- } else {
- double rat1 = (double) cwidth / intrinsicSize.width;
- double rat2 = (double) cheight / intrinsicSize.height;
- if (rat1 < rat2) {
- // reduce cheight
- cheight = (int)(rat1 * intrinsicSize.height);
- } else if (rat1 > rat2) {
- cwidth = (int)(rat2 * intrinsicSize.width);
- }
- }
- }
+ Dimension constrainedIntrinsicSize;
+ if (constrainIntrinsicSize) {
+ constrainedIntrinsicSize = constrain(intrinsicSize);
+ } else {
+ constrainedIntrinsicSize = intrinsicSize;
}
+
+ //Derive content extents where not explicit
+ Dimension adjustedDim = adjustContentSize(cwidth, cheight, constrainedIntrinsicSize);
+ cwidth = adjustedDim.width;
+ cheight = adjustedDim.height;
+ //Adjust viewport if not explicit
if (ipd == -1) {
- ipd = cwidth;
+ ipd = constrainExtent(cwidth, props.getInlineProgressionDimension());
}
if (bpd == -1) {
- bpd = cheight;
+ bpd = constrainExtent(cheight, props.getBlockProgressionDimension());
}
this.clip = false;
@@ -193,6 +189,90 @@ public class ImageLayout implements Constants {
this.placement = new Rectangle(xoffset, yoffset, cwidth, cheight);
}
+ private int constrainExtent(int extent, LengthRangeProperty range) {
+ Length len;
+ len = range.getMaximum(percentBaseContext).getLength();
+ if (len.getEnum() != EN_AUTO) {
+ int max = len.getValue(percentBaseContext);
+ if (max != -1) {
+ extent = Math.min(extent, max);
+ }
+ }
+ len = range.getMinimum(percentBaseContext).getLength();
+ if (len.getEnum() != EN_AUTO) {
+ int min = len.getValue(percentBaseContext);
+ if (min != -1) {
+ extent = Math.max(extent, min);
+ }
+ }
+ return extent;
+ }
+
+ private Dimension constrain(Dimension size) {
+ Dimension adjusted = new Dimension(size);
+ int effWidth = constrainExtent(size.width, props.getInlineProgressionDimension());
+ int effHeight = constrainExtent(size.height, props.getBlockProgressionDimension());
+ int scaling = props.getScaling();
+ if (scaling == EN_UNIFORM) {
+ double rat1 = (double)effWidth / size.width;
+ double rat2 = (double)effHeight / size.height;
+ if (rat1 < rat2) {
+ adjusted.width = effWidth;
+ adjusted.height = (int)(rat1 * size.height);
+ } else if (rat1 > rat2) {
+ adjusted.width = (int)(rat2 * size.width);
+ adjusted.height = effHeight;
+ }
+ } else {
+ adjusted.width = effWidth;
+ adjusted.height = effHeight;
+ }
+ return adjusted;
+ }
+
+ private Dimension adjustContentSize(
+ final int cwidth, final int cheight,
+ Dimension defaultSize) {
+ Dimension dim = new Dimension(cwidth, cheight);
+ int scaling = props.getScaling();
+ if ((scaling == EN_UNIFORM) || (cwidth == -1) || cheight == -1) {
+ if (cwidth == -1 && cheight == -1) {
+ dim.width = defaultSize.width;
+ dim.height = defaultSize.height;
+ } else if (cwidth == -1) {
+ if (defaultSize.height == 0) {
+ dim.width = 0;
+ } else {
+ dim.width = (int)(defaultSize.width * (double)cheight
+ / defaultSize.height);
+ }
+ } else if (cheight == -1) {
+ if (defaultSize.width == 0) {
+ dim.height = 0;
+ } else {
+ dim.height = (int)(defaultSize.height * (double)cwidth
+ / defaultSize.width);
+ }
+ } else {
+ // adjust the larger
+ if (defaultSize.width == 0 || defaultSize.height == 0) {
+ dim.width = 0;
+ dim.height = 0;
+ } else {
+ double rat1 = (double)cwidth / defaultSize.width;
+ double rat2 = (double)cheight / defaultSize.height;
+ if (rat1 < rat2) {
+ // reduce height
+ dim.height = (int)(rat1 * defaultSize.height);
+ } else if (rat1 > rat2) {
+ dim.width = (int)(rat2 * defaultSize.width);
+ }
+ }
+ }
+ }
+ return dim;
+ }
+
/**
* Given the ipd and the content width calculates the
* required x offset based on the text-align property
@@ -243,18 +323,34 @@ public class ImageLayout implements Constants {
return yoffset;
}
+ /**
+ * Returns the placement of the image inside the viewport.
+ * @return the placement of the image inside the viewport (coordinates in millipoints)
+ */
public Rectangle getPlacement() {
return this.placement;
}
+ /**
+ * Returns the size of the image's viewport.
+ * @return the viewport size (in millipoints)
+ */
public Dimension getViewportSize() {
return this.viewportSize;
}
+ /**
+ * Returns the size of the image's intrinsic (natural) size.
+ * @return the intrinsic size (in millipoints)
+ */
public Dimension getIntrinsicSize() {
return this.intrinsicSize;
}
+ /**
+ * Indicates whether the image is clipped.
+ * @return true if the image shall be clipped
+ */
public boolean isClipped() {
return this.clip;
}
diff --git a/src/java/org/apache/fop/pdf/AlphaRasterImage.java b/src/java/org/apache/fop/pdf/AlphaRasterImage.java
new file mode 100644
index 000000000..be476bdb2
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/AlphaRasterImage.java
@@ -0,0 +1,181 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.pdf;
+
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.xmlgraphics.image.GraphicsUtil;
+
+/**
+ * PDFImage implementation for alpha channel "images".
+ */
+public class AlphaRasterImage implements PDFImage {
+
+ private int bitsPerComponent;
+ private PDFDeviceColorSpace colorSpace;
+ private Raster alpha;
+ private String key;
+
+ /**
+ * Create a alpha channel image.
+ * Creates a new bitmap image with the given data.
+ *
+ * @param k the key to be used to lookup the image
+ * @param alpha the alpha channel raster
+ */
+ public AlphaRasterImage(String k, Raster alpha) {
+ this.key = k;
+ this.bitsPerComponent = 8;
+ this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_GRAY);
+ if (alpha == null) {
+ throw new NullPointerException("Parameter alpha must not be null");
+ }
+ this.alpha = alpha;
+ }
+
+ /**
+ * Create a alpha channel image.
+ * Extracts the alpha channel from the RenderedImage and creates a new bitmap image
+ * with the given data.
+ *
+ * @param k the key to be used to lookup the image
+ * @param image the image (must have an alpha channel)
+ */
+ public AlphaRasterImage(String k, RenderedImage image) {
+ this(k, GraphicsUtil.getAlphaRaster(image));
+ }
+
+ /** {@inheritDoc} */
+ public void setup(PDFDocument doc) {
+ //nop
+ }
+
+ /** {@inheritDoc} */
+ public String getKey() {
+ return key;
+ }
+
+ /** {@inheritDoc} */
+ public int getWidth() {
+ return alpha.getWidth();
+ }
+
+ /** {@inheritDoc} */
+ public int getHeight() {
+ return alpha.getHeight();
+ }
+
+ /** {@inheritDoc} */
+ public PDFDeviceColorSpace getColorSpace() {
+ return colorSpace;
+ }
+
+ /** {@inheritDoc} */
+ public int getBitsPerComponent() {
+ return bitsPerComponent;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isTransparent() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public PDFColor getTransparentColor() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public String getMask() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public String getSoftMask() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public PDFReference getSoftMaskReference() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isInverted() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public void outputContents(OutputStream out) throws IOException {
+ int w = getWidth();
+ int h = getHeight();
+
+ //Check Raster
+ int nbands = alpha.getNumBands();
+ if (nbands != 1) {
+ throw new UnsupportedOperationException(
+ "Expected only one band/component for the alpha channel");
+ }
+ int dataType = alpha.getDataBuffer().getDataType();
+ if (dataType != DataBuffer.TYPE_BYTE) {
+ throw new UnsupportedOperationException("Unsupported DataBuffer type: "
+ + alpha.getDataBuffer().getClass().getName());
+ }
+
+ //...and write the Raster line by line with a reusable buffer
+ byte[] line = new byte[nbands * w];
+ for (int y = 0; y < h; y++) {
+ alpha.getDataElements(0, y, w, 1, line);
+ out.write(line);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void populateXObjectDictionary(PDFDictionary dict) {
+ //nop
+ }
+
+ /** {@inheritDoc} */
+ public PDFICCStream getICCStream() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isPS() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public String getFilterHint() {
+ return PDFFilterList.IMAGE_FILTER;
+ }
+
+ /** {@inheritDoc} */
+ public PDFFilter getPDFFilter() {
+ return null;
+ }
+
+}
+
+
diff --git a/src/java/org/apache/fop/pdf/BitmapImage.java b/src/java/org/apache/fop/pdf/BitmapImage.java
index 34c78ffe3..69b51dac3 100644
--- a/src/java/org/apache/fop/pdf/BitmapImage.java
+++ b/src/java/org/apache/fop/pdf/BitmapImage.java
@@ -30,7 +30,7 @@ import java.io.OutputStream;
public class BitmapImage implements PDFImage {
private int height;
private int width;
- private int bitsPerPixel;
+ private int bitsPerComponent;
private PDFDeviceColorSpace colorSpace;
private byte[] bitmaps;
private PDFReference maskRef;
@@ -53,10 +53,12 @@ public class BitmapImage implements PDFImage {
this.key = k;
this.height = height;
this.width = width;
- this.bitsPerPixel = 8;
+ this.bitsPerComponent = 8;
this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB);
this.bitmaps = data;
- maskRef = new PDFReference(mask);
+ if (mask != null) {
+ maskRef = new PDFReference(mask);
+ }
}
/**
@@ -117,13 +119,9 @@ public class BitmapImage implements PDFImage {
return colorSpace;
}
- /**
- * Get the number of bits per pixel.
- *
- * @return the number of bits per pixel
- */
- public int getBitsPerPixel() {
- return bitsPerPixel;
+ /** {@inheritDoc} */
+ public int getBitsPerComponent() {
+ return bitsPerComponent;
}
/**
@@ -173,13 +171,16 @@ public class BitmapImage implements PDFImage {
return false;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public void outputContents(OutputStream out) throws IOException {
out.write(bitmaps);
}
+ /** {@inheritDoc} */
+ public void populateXObjectDictionary(PDFDictionary dict) {
+ //nop
+ }
+
/**
* Get the ICC stream.
* @return always returns null since this has no icc color space
diff --git a/src/java/org/apache/fop/pdf/FlateFilter.java b/src/java/org/apache/fop/pdf/FlateFilter.java
index d7dc81d1f..a652c4534 100644
--- a/src/java/org/apache/fop/pdf/FlateFilter.java
+++ b/src/java/org/apache/fop/pdf/FlateFilter.java
@@ -19,8 +19,8 @@
package org.apache.fop.pdf;
-import java.io.OutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import org.apache.xmlgraphics.util.io.FlateEncodeOutputStream;
@@ -98,13 +98,13 @@ public class FlateFilter extends PDFFilter {
if (predictor > PREDICTION_NONE) {
PDFDictionary dict = new PDFDictionary();
dict.put("Predictor", predictor);
- if (colors > 0) {
+ if (colors > 1) {
dict.put("Colors", colors);
}
- if (bitsPerComponent > 0) {
+ if (bitsPerComponent > 0 && bitsPerComponent != 8) {
dict.put("BitsPerComponent", bitsPerComponent);
}
- if (columns > 0) {
+ if (columns > 1) {
dict.put("Columns", columns);
}
return dict;
diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java
index f3069e85e..d0c48ee39 100644
--- a/src/java/org/apache/fop/pdf/PDFFactory.java
+++ b/src/java/org/apache/fop/pdf/PDFFactory.java
@@ -1490,9 +1490,6 @@ public class PDFFactory {
*/
public PDFICCStream makePDFICCStream() {
PDFICCStream iccStream = new PDFICCStream();
- iccStream.getFilterList().addDefaultFilters(
- getDocument().getFilterMap(),
- PDFFilterList.CONTENT_FILTER);
getDocument().registerObject(iccStream);
//getDocument().applyEncryption(iccStream);
diff --git a/src/java/org/apache/fop/pdf/PDFFilterList.java b/src/java/org/apache/fop/pdf/PDFFilterList.java
index 607ae174b..84131707b 100644
--- a/src/java/org/apache/fop/pdf/PDFFilterList.java
+++ b/src/java/org/apache/fop/pdf/PDFFilterList.java
@@ -34,6 +34,8 @@ public class PDFFilterList {
public static final String DEFAULT_FILTER = "default";
/** Key for the filter used for normal content*/
public static final String CONTENT_FILTER = "content";
+ /** Key for the filter used for precompressed content */
+ public static final String PRECOMPRESSED_FILTER = "precompressed";
/** Key for the filter used for images */
public static final String IMAGE_FILTER = "image";
/** Key for the filter used for JPEG images */
@@ -178,6 +180,9 @@ public class PDFFilterList {
} else if (TIFF_FILTER.equals(type)) {
//CCITT-encoded images are already well compressed
addFilter(new NullFilter());
+ } else if (PRECOMPRESSED_FILTER.equals(type)) {
+ //precompressed content doesn't need further compression
+ addFilter(new NullFilter());
} else {
// built-in default to flate
addFilter(new FlateFilter());
diff --git a/src/java/org/apache/fop/pdf/PDFICCStream.java b/src/java/org/apache/fop/pdf/PDFICCStream.java
index da1e8353c..f242c0cae 100644
--- a/src/java/org/apache/fop/pdf/PDFICCStream.java
+++ b/src/java/org/apache/fop/pdf/PDFICCStream.java
@@ -66,9 +66,7 @@ public class PDFICCStream extends PDFStream {
return length;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
protected void outputRawStreamData(OutputStream out) throws IOException {
cp.write(out);
}
diff --git a/src/java/org/apache/fop/pdf/PDFImage.java b/src/java/org/apache/fop/pdf/PDFImage.java
index f880fa6ac..e0aaa44fa 100644
--- a/src/java/org/apache/fop/pdf/PDFImage.java
+++ b/src/java/org/apache/fop/pdf/PDFImage.java
@@ -69,11 +69,11 @@ public interface PDFImage {
PDFDeviceColorSpace getColorSpace();
/**
- * Get the bits per pixel for this image.
+ * Get the bits per color component for this image.
*
- * @return the bits per pixel
+ * @return the bits per component
*/
- int getBitsPerPixel();
+ int getBitsPerComponent();
/**
* Check if this image is a PostScript image.
@@ -130,6 +130,14 @@ public interface PDFImage {
void outputContents(OutputStream out) throws IOException;
/**
+ * Populates the XObject's dictionary with additional values. The values are added to the
+ * dictionary after all the values obtained from other methods from this interface have
+ * been put into the dictionary. That allows to override certain values.
+ * @param dict the dictionary to fill
+ */
+ void populateXObjectDictionary(PDFDictionary dict);
+
+ /**
* Get the ICC stream for this image.
*
* @return the ICC stream for this image if any
diff --git a/src/java/org/apache/fop/pdf/PDFImageXObject.java b/src/java/org/apache/fop/pdf/PDFImageXObject.java
index 35f3e543d..14fbeed4d 100644
--- a/src/java/org/apache/fop/pdf/PDFImageXObject.java
+++ b/src/java/org/apache/fop/pdf/PDFImageXObject.java
@@ -90,7 +90,7 @@ public class PDFImageXObject extends PDFXObject {
put("Subtype", new PDFName("Image"));
put("Width", new Integer(pdfimage.getWidth()));
put("Height", new Integer(pdfimage.getHeight()));
- put("BitsPerComponent", new Integer(pdfimage.getBitsPerPixel()));
+ put("BitsPerComponent", new Integer(pdfimage.getBitsPerComponent()));
PDFICCStream pdfICCStream = pdfimage.getICCStream();
if (pdfICCStream != null) {
@@ -119,18 +119,25 @@ public class PDFImageXObject extends PDFXObject {
if (pdfimage.isTransparent()) {
PDFColor transp = pdfimage.getTransparentColor();
PDFArray mask = new PDFArray(this);
- mask.add(new Integer(transp.red255()));
- mask.add(new Integer(transp.red255()));
- mask.add(new Integer(transp.green255()));
- mask.add(new Integer(transp.green255()));
- mask.add(new Integer(transp.blue255()));
- mask.add(new Integer(transp.blue255()));
+ if (pdfimage.getColorSpace().isGrayColorSpace()) {
+ mask.add(new Integer(transp.red255()));
+ mask.add(new Integer(transp.red255()));
+ } else {
+ mask.add(new Integer(transp.red255()));
+ mask.add(new Integer(transp.red255()));
+ mask.add(new Integer(transp.green255()));
+ mask.add(new Integer(transp.green255()));
+ mask.add(new Integer(transp.blue255()));
+ mask.add(new Integer(transp.blue255()));
+ }
put("Mask", mask);
}
PDFReference ref = pdfimage.getSoftMaskReference();
if (ref != null) {
put("SMask", ref);
}
+ //Important: do this at the end so previous values can be overwritten.
+ pdfimage.populateXObjectDictionary(this);
}
/** {@inheritDoc} */
diff --git a/src/java/org/apache/fop/pdf/PDFObject.java b/src/java/org/apache/fop/pdf/PDFObject.java
index f53183574..4bfd805f4 100644
--- a/src/java/org/apache/fop/pdf/PDFObject.java
+++ b/src/java/org/apache/fop/pdf/PDFObject.java
@@ -276,14 +276,23 @@ public abstract class PDFObject implements PDFWritable {
*/
protected byte[] encodeString(String string) {
return encodeText(string);
- /*
- final byte[] buf = encode(PDFText.escapeString(string));
+ }
+
+ /**
+ * Encodes binary data as hexadecimal string object.
+ * @param data the binary data
+ * @param out the OutputStream to write the encoded object to
+ * @throws IOException if an I/O error occurs
+ */
+ protected void encodeBinaryToHexString(byte[] data, OutputStream out) throws IOException {
+ out.write('<');
if (getDocumentSafely().isEncryptionActive()) {
- return PDFText.escapeByteArray(
- getDocument().getEncryption().encrypt(buf, this));
- } else {
- return buf;
- }*/
+ data = getDocument().getEncryption().encrypt(data, this);
+ }
+ String hex = PDFText.toHex(data, false);
+ byte[] encoded = hex.getBytes("US-ASCII");
+ out.write(encoded);
+ out.write('>');
}
/**
@@ -307,6 +316,9 @@ public abstract class PDFObject implements PDFWritable {
}
} else if (obj instanceof Boolean) {
writer.write(obj.toString());
+ } else if (obj instanceof byte[]) {
+ writer.flush();
+ encodeBinaryToHexString((byte[])obj, out);
} else {
writer.flush();
out.write(encodeText(obj.toString()));
diff --git a/src/java/org/apache/fop/pdf/PDFReference.java b/src/java/org/apache/fop/pdf/PDFReference.java
index 3b615735a..da388d368 100644
--- a/src/java/org/apache/fop/pdf/PDFReference.java
+++ b/src/java/org/apache/fop/pdf/PDFReference.java
@@ -51,6 +51,9 @@ public class PDFReference implements PDFWritable {
* @param ref an object reference
*/
public PDFReference(String ref) {
+ if (ref == null) {
+ throw new NullPointerException("ref must not be null");
+ }
this.indirectReference = ref;
}
diff --git a/src/java/org/apache/fop/pdf/PDFText.java b/src/java/org/apache/fop/pdf/PDFText.java
index 4c17148c1..d380ac8dd 100644
--- a/src/java/org/apache/fop/pdf/PDFText.java
+++ b/src/java/org/apache/fop/pdf/PDFText.java
@@ -25,12 +25,12 @@ import org.apache.avalon.framework.CascadingRuntimeException;
/**
* This class represents a simple number object. It also contains contains some
- * utility methods for outputing numbers to PDF.
+ * utility methods for outputting numbers to PDF.
*/
public class PDFText extends PDFObject {
- private static final char[] DIGITS =
- {'0', '1', '2', '3', '4', '5', '6', '7',
+ private static final char[] DIGITS
+ = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
private String text;
@@ -145,20 +145,34 @@ public class PDFText extends PDFObject {
/**
* Converts a byte array to a Hexadecimal String (3.2.3 in PDF 1.4 specs)
* @param data the data to encode
+ * @param brackets true if enclosing brackets should be included
* @return String the resulting string
*/
- public static final String toHex(byte[] data) {
+ public static final String toHex(byte[] data, boolean brackets) {
final StringBuffer sb = new StringBuffer(data.length * 2);
- sb.append("<");
+ if (brackets) {
+ sb.append("<");
+ }
for (int i = 0; i < data.length; i++) {
sb.append(DIGITS[(data[i] >>> 4) & 0x0F]);
sb.append(DIGITS[data[i] & 0x0F]);
}
- sb.append(">");
+ if (brackets) {
+ sb.append(">");
+ }
return sb.toString();
}
/**
+ * Converts a byte array to a Hexadecimal String (3.2.3 in PDF 1.4 specs)
+ * @param data the data to encode
+ * @return String the resulting string
+ */
+ public static final String toHex(byte[] data) {
+ return toHex(data, true);
+ }
+
+ /**
* Converts a String to UTF-16 (big endian).
* @param text text to convert
* @return byte[] UTF-16 stream
diff --git a/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java b/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java
index 7d21d78c0..f74699fd5 100644
--- a/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java
+++ b/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java
@@ -26,28 +26,18 @@ import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
-// DOM
import org.w3c.dom.Document;
-// Batik
-import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.BridgeContext;
+import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.gvt.GraphicsNode;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
-// FOP
-import org.apache.fop.render.Graphics2DAdapter;
-import org.apache.fop.render.Graphics2DImagePainter;
-import org.apache.fop.render.RendererContextConstants;
-import org.apache.fop.render.XMLHandler;
-import org.apache.fop.render.RendererContext;
import org.apache.fop.render.RendererContext.RendererContextWrapper;
import org.apache.fop.svg.SVGUserAgent;
-// Commons-Logging
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
/**
* Generic XML handler for SVG. Uses Apache Batik for SVG processing and simply paints to
* a Graphics2DAdapter and thus ultimatively to Graphics2D interface that is presented.
@@ -76,6 +66,7 @@ public abstract class AbstractGenericSVGHandler implements XMLHandler, RendererC
*/
protected void renderSVGDocument(final RendererContext context,
final Document doc) throws IOException {
+ updateRendererContext(context);
final RendererContextWrapper wrappedContext = RendererContext.wrapRendererContext(context);
int x = wrappedContext.getCurrentXPosition();
int y = wrappedContext.getCurrentYPosition();
@@ -123,6 +114,15 @@ public abstract class AbstractGenericSVGHandler implements XMLHandler, RendererC
x, y, wrappedContext.getWidth(), wrappedContext.getHeight());
}
+ /**
+ * Override this method to update the renderer context if it needs special settings for
+ * certain conditions.
+ * @param context the renderer context
+ */
+ protected void updateRendererContext(RendererContext context) {
+ //nop
+ }
+
/** {@inheritDoc} */
public String getNamespace() {
return SVGDOMImplementation.SVG_NAMESPACE_URI;
diff --git a/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java b/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java
index b51b71d61..bc7bb95a1 100644
--- a/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java
+++ b/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java
@@ -33,8 +33,6 @@ import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
-import org.apache.fop.render.Graphics2DAdapter;
-import org.apache.fop.render.Graphics2DImagePainter;
import org.apache.fop.render.RendererContext.RendererContextWrapper;
import org.apache.fop.util.UnitConv;
@@ -49,9 +47,11 @@ public abstract class AbstractGraphics2DAdapter implements Graphics2DAdapter {
* @param context the renderer context for the current renderer
* @param resolution the requested bitmap resolution
* @param gray true if the generated image should be in grayscales
+ * @param withAlpha true if an alpha channel should be created
* @return the generated BufferedImage
*/
- protected BufferedImage paintToBufferedImage(Graphics2DImagePainter painter,
+ protected BufferedImage paintToBufferedImage(
+ org.apache.xmlgraphics.java2d.Graphics2DImagePainter painter,
RendererContextWrapper context, int resolution, boolean gray, boolean withAlpha) {
int bmw = (int)Math.ceil(UnitConv.mpt2px(context.getWidth(), resolution));
int bmh = (int)Math.ceil(UnitConv.mpt2px(context.getHeight(), resolution));
diff --git a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java
index 4e5edece6..ac11d56d5 100644
--- a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java
+++ b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java
@@ -25,6 +25,10 @@ import java.awt.geom.Rectangle2D;
import java.util.List;
import java.util.Map;
+import org.w3c.dom.Document;
+
+import org.apache.xmlgraphics.image.loader.ImageSize;
+
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.area.BlockViewport;
@@ -36,9 +40,7 @@ import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.Viewport;
import org.apache.fop.fo.Constants;
import org.apache.fop.fonts.FontMetrics;
-import org.apache.fop.image.FopImage;
import org.apache.fop.traits.BorderProps;
-import org.w3c.dom.Document;
/**
* Abstract base class for renderers like PDF and PostScript where many painting operations
@@ -151,51 +153,47 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer {
updateColor(back.getColor(), true);
fillRect(sx, sy, paddRectWidth, paddRectHeight);
}
- if (back.getFopImage() != null) {
- FopImage fopimage = back.getFopImage();
- if (fopimage != null && fopimage.load(FopImage.DIMENSIONS)) {
- saveGraphicsState();
- clipRect(sx, sy, paddRectWidth, paddRectHeight);
- int horzCount = (int)((paddRectWidth
- * 1000 / fopimage.getIntrinsicWidth()) + 1.0f);
- int vertCount = (int)((paddRectHeight
- * 1000 / fopimage.getIntrinsicHeight()) + 1.0f);
- if (back.getRepeat() == EN_NOREPEAT) {
- horzCount = 1;
- vertCount = 1;
- } else if (back.getRepeat() == EN_REPEATX) {
- vertCount = 1;
- } else if (back.getRepeat() == EN_REPEATY) {
- horzCount = 1;
- }
- //change from points to millipoints
- sx *= 1000;
- sy *= 1000;
- if (horzCount == 1) {
- sx += back.getHoriz();
- }
- if (vertCount == 1) {
- sy += back.getVertical();
- }
- for (int x = 0; x < horzCount; x++) {
- for (int y = 0; y < vertCount; y++) {
- // place once
- Rectangle2D pos;
- // Image positions are relative to the currentIP/BP
- pos = new Rectangle2D.Float(sx - currentIPPosition
- + (x * fopimage.getIntrinsicWidth()),
- sy - currentBPPosition
- + (y * fopimage.getIntrinsicHeight()),
- fopimage.getIntrinsicWidth(),
- fopimage.getIntrinsicHeight());
- drawImage(back.getURL(), pos);
- }
+ if (back.getImageInfo() != null) {
+ ImageSize imageSize = back.getImageInfo().getSize();
+ saveGraphicsState();
+ clipRect(sx, sy, paddRectWidth, paddRectHeight);
+ int horzCount = (int)((paddRectWidth
+ * 1000 / imageSize.getWidthMpt()) + 1.0f);
+ int vertCount = (int)((paddRectHeight
+ * 1000 / imageSize.getHeightMpt()) + 1.0f);
+ if (back.getRepeat() == EN_NOREPEAT) {
+ horzCount = 1;
+ vertCount = 1;
+ } else if (back.getRepeat() == EN_REPEATX) {
+ vertCount = 1;
+ } else if (back.getRepeat() == EN_REPEATY) {
+ horzCount = 1;
+ }
+ //change from points to millipoints
+ sx *= 1000;
+ sy *= 1000;
+ if (horzCount == 1) {
+ sx += back.getHoriz();
+ }
+ if (vertCount == 1) {
+ sy += back.getVertical();
+ }
+ for (int x = 0; x < horzCount; x++) {
+ for (int y = 0; y < vertCount; y++) {
+ // place once
+ Rectangle2D pos;
+ // Image positions are relative to the currentIP/BP
+ pos = new Rectangle2D.Float(sx - currentIPPosition
+ + (x * imageSize.getWidthMpt()),
+ sy - currentBPPosition
+ + (y * imageSize.getHeightMpt()),
+ imageSize.getWidthMpt(),
+ imageSize.getHeightMpt());
+ drawImage(back.getURL(), pos);
}
-
- restoreGraphicsState();
- } else {
- log.warn("Can't find background image: " + back.getURL());
}
+
+ restoreGraphicsState();
}
}
diff --git a/src/java/org/apache/fop/render/Graphics2DAdapter.java b/src/java/org/apache/fop/render/Graphics2DAdapter.java
index 2509b3864..e9b00f103 100644
--- a/src/java/org/apache/fop/render/Graphics2DAdapter.java
+++ b/src/java/org/apache/fop/render/Graphics2DAdapter.java
@@ -43,7 +43,7 @@ public interface Graphics2DAdapter {
* @param height height of the image
* @throws IOException In case of an I/O error while writing the output format
*/
- void paintImage(Graphics2DImagePainter painter,
+ void paintImage(org.apache.xmlgraphics.java2d.Graphics2DImagePainter painter,
RendererContext context,
int x, int y, int width, int height) throws IOException;
diff --git a/src/java/org/apache/fop/render/Graphics2DImagePainter.java b/src/java/org/apache/fop/render/Graphics2DImagePainter.java
index 3039a72a7..9301a6962 100644
--- a/src/java/org/apache/fop/render/Graphics2DImagePainter.java
+++ b/src/java/org/apache/fop/render/Graphics2DImagePainter.java
@@ -19,27 +19,12 @@
package org.apache.fop.render;
-import java.awt.Dimension;
-import java.awt.Graphics2D;
-import java.awt.geom.Rectangle2D;
-
/**
* This interface is used by the Graphics2DAdapter. Components that can paint using
* a Graphics2D instance can implement this interface to paint themselves.
+ * @deprecated use {@link org.apache.xmlgraphics.java2d.Graphics2DImagePainter} directly!
*/
-public interface Graphics2DImagePainter {
-
- /**
- * Called to paint the image. Implementations should scale so the image is
- * painted fully inside the given area indicated by then Rectangle2D object.
- * @param g2d the Graphics2D instance to paint on
- * @param area the target area for the image
- */
- void paint(Graphics2D g2d, Rectangle2D area);
+public interface Graphics2DImagePainter
+ extends org.apache.xmlgraphics.java2d.Graphics2DImagePainter {
- /**
- * @return the dimensions of the image to be painted in millipoints
- */
- Dimension getImageSize();
-
} \ No newline at end of file
diff --git a/src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java b/src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java
index 8fa0d0f72..687a0373e 100644
--- a/src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java
+++ b/src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java
@@ -22,8 +22,9 @@ package org.apache.fop.render.afp;
import java.awt.image.BufferedImage;
import java.io.IOException;
+import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
+
import org.apache.fop.render.AbstractGraphics2DAdapter;
-import org.apache.fop.render.Graphics2DImagePainter;
import org.apache.fop.render.RendererContext;
/**
diff --git a/src/java/org/apache/fop/render/afp/AFPRenderer.java b/src/java/org/apache/fop/render/afp/AFPRenderer.java
index de414fa10..cdb2f2ec8 100644
--- a/src/java/org/apache/fop/render/afp/AFPRenderer.java
+++ b/src/java/org/apache/fop/render/afp/AFPRenderer.java
@@ -20,10 +20,13 @@
package org.apache.fop.render.afp;
import java.awt.Color;
+import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
+import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
@@ -32,7 +35,22 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
+
+import org.apache.xmlgraphics.image.codec.tiff.TIFFImage;
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax;
+import org.apache.xmlgraphics.image.loader.impl.ImageRendered;
+import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
+import org.apache.xmlgraphics.image.loader.util.ImageUtil;
+import org.apache.xmlgraphics.ps.ImageEncodingHelper;
+
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.area.Block;
@@ -49,6 +67,7 @@ import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.inline.WordArea;
+import org.apache.fop.datatypes.URISpecification;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.fonts.FontInfo;
@@ -56,10 +75,6 @@ import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.base14.Courier;
import org.apache.fop.fonts.base14.Helvetica;
import org.apache.fop.fonts.base14.TimesRoman;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.image.ImageFactory;
-import org.apache.fop.image.TIFFImage;
-import org.apache.fop.image.XMLImage;
import org.apache.fop.render.AbstractPathOrientedRenderer;
import org.apache.fop.render.Graphics2DAdapter;
import org.apache.fop.render.RendererContext;
@@ -74,7 +89,6 @@ import org.apache.fop.render.afp.modca.AFPConstants;
import org.apache.fop.render.afp.modca.AFPDataStream;
import org.apache.fop.render.afp.modca.ImageObject;
import org.apache.fop.render.afp.modca.PageObject;
-import org.w3c.dom.Document;
/**
* This is an implementation of a FOP Renderer that renders areas to AFP.
@@ -735,20 +749,117 @@ public class AFPRenderer extends AbstractPathOrientedRenderer {
return context;
}
- /**
- * {@inheritDoc}
- */
- public void drawImage(String url, Rectangle2D pos, Map foreignAttributes) {
+ private static final ImageFlavor[] FLAVORS = new ImageFlavor[]
+ {ImageFlavor.RAW_CCITTFAX,
+ ImageFlavor.GRAPHICS2D,
+ ImageFlavor.BUFFERED_IMAGE,
+ ImageFlavor.RENDERED_IMAGE,
+ ImageFlavor.XML_DOM};
+
+ /** {@inheritDoc} */
+ public void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) {
+ uri = URISpecification.getURL(uri);
+ Rectangle posInt = new Rectangle(
+ (int)pos.getX(),
+ (int)pos.getY(),
+ (int)pos.getWidth(),
+ (int)pos.getHeight());
+ Point origin = new Point(currentIPPosition, currentBPPosition);
+ int x = origin.x + posInt.x;
+ int y = origin.y + posInt.y;
+
String name = null;
if (pageSegmentsMap != null) {
- name = (String) pageSegmentsMap.get(url);
+ name = (String) pageSegmentsMap.get(uri);
}
if (name != null) {
- int x = mpts2units(pos.getX() + currentIPPosition);
- int y = mpts2units(pos.getY() + currentBPPosition);
- afpDataStream.createIncludePageSegment(name, x, y);
+ afpDataStream.createIncludePageSegment(name, mpts2units(x), mpts2units(y));
} else {
- url = ImageFactory.getURL(url);
+ ImageManager manager = getUserAgent().getFactory().getImageManager();
+ ImageInfo info = null;
+ try {
+ ImageSessionContext sessionContext = getUserAgent().getImageSessionContext();
+ info = manager.getImageInfo(uri, sessionContext);
+
+ //Only now fully load/prepare the image
+ Map hints = ImageUtil.getDefaultHints(sessionContext);
+ org.apache.xmlgraphics.image.loader.Image img = manager.getImage(
+ info, FLAVORS, hints, sessionContext);
+
+ //...and process the image
+ if (img instanceof ImageGraphics2D) {
+ ImageGraphics2D imageG2D = (ImageGraphics2D)img;
+ RendererContext context = createRendererContext(
+ posInt.x, posInt.y,
+ posInt.width, posInt.height, foreignAttributes);
+ getGraphics2DAdapter().paintImage(imageG2D.getGraphics2DImagePainter(),
+ context,
+ origin.x + posInt.x, origin.y + posInt.y,
+ posInt.width, posInt.height);
+ } else if (img instanceof ImageRendered) {
+ ImageRendered imgRend = (ImageRendered)img;
+ RenderedImage ri = imgRend.getRenderedImage();
+
+ drawBufferedImage(ri, getResolution(),
+ posInt.x + currentIPPosition,
+ posInt.y + currentBPPosition,
+ posInt.width,
+ posInt.height);
+ } else if (img instanceof ImageRawCCITTFax) {
+ ImageRawCCITTFax ccitt = (ImageRawCCITTFax)img;
+ int afpx = mpts2units(posInt.x + currentIPPosition);
+ int afpy = mpts2units(posInt.y + currentBPPosition);
+ int afpw = mpts2units(posInt.getWidth());
+ int afph = mpts2units(posInt.getHeight());
+ int afpres = getResolution();
+ ImageObject io = afpDataStream.getImageObject(afpx, afpy, afpw, afph,
+ afpres, afpres);
+ io.setImageParameters(
+ (int) (ccitt.getSize().getDpiHorizontal() * 10),
+ (int) (ccitt.getSize().getDpiVertical() * 10),
+ ccitt.getSize().getWidthPx(),
+ ccitt.getSize().getHeightPx());
+ int compression = ccitt.getCompression();
+ switch (compression) {
+ case TIFFImage.COMP_FAX_G3_1D :
+ io.setImageEncoding((byte) 0x80);
+ break;
+ case TIFFImage.COMP_FAX_G3_2D :
+ io.setImageEncoding((byte) 0x81);
+ break;
+ case TIFFImage.COMP_FAX_G4_2D :
+ io.setImageEncoding((byte) 0x82);
+ break;
+ default:
+ throw new IllegalStateException(
+ "Invalid compression scheme: " + compression);
+ }
+ InputStream in = ccitt.createInputStream();
+ try {
+ byte[] buf = IOUtils.toByteArray(in);
+ io.setImageData(buf);
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ } else if (img instanceof ImageXMLDOM) {
+ ImageXMLDOM imgXML = (ImageXMLDOM)img;
+ renderDocument(imgXML.getDocument(), imgXML.getRootNamespace(),
+ pos, foreignAttributes);
+ } else {
+ throw new UnsupportedOperationException("Unsupported image type: " + img);
+ }
+
+ } catch (ImageException ie) {
+ log.error("Error while processing image: "
+ + (info != null ? info.toString() : uri), ie);
+ } catch (FileNotFoundException fe) {
+ log.error(fe.getMessage());
+ } catch (IOException ioe) {
+ log.error("I/O error while processing image: "
+ + (info != null ? info.toString() : uri), ioe);
+ }
+
+ /*
ImageFactory fact = userAgent.getFactory().getImageFactory();
FopImage fopimage = fact.getImage(url, userAgent);
if (fopimage == null) {
@@ -768,6 +879,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer {
renderDocument(doc, ns, pos, foreignAttributes);
} else if (MimeConstants.MIME_EPS.equals(mime)) {
log.warn("EPS images are not supported by this renderer");
+ */
/*
* } else if (MimeConstants.MIME_JPEG.equals(mime)) { if
* (!fopimage.load(FopImage.ORIGINAL_DATA)) { return; }
@@ -785,7 +897,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer {
* io.setImageIDESize((byte)fopimage.getBitsPerPixel());
* io.setImageEncoding((byte)0x83);
* io.setImageData(fopimage.getRessourceBytes());
- */
+ *//*
} else if (MimeConstants.MIME_TIFF.equals(mime)
&& fopimage instanceof TIFFImage) {
TIFFImage tiffImage = (TIFFImage) fopimage;
@@ -852,43 +964,30 @@ public class AFPRenderer extends AbstractPathOrientedRenderer {
convertToGrayScaleImage(io, fopimage.getBitmaps(), fopimage
.getWidth(), fopimage.getHeight(), this.bitsPerPixel);
}
- }
+ }*/
}
}
/**
- * Writes a BufferedImage to an OutputStream as raw sRGB bitmaps.
+ * Writes a RenderedImage to an OutputStream as raw sRGB bitmaps.
*
- * @param img
- * the BufferedImage
+ * @param image
+ * the RenderedImage
* @param out
* the OutputStream
* @throws IOException
* In case of an I/O error.
*/
- public static void writeImage(BufferedImage img, OutputStream out)
+ public static void writeImage(RenderedImage image, OutputStream out)
throws IOException {
- int w = img.getWidth();
- int h = img.getHeight();
- int[] tmpMap = img.getRGB(0, 0, w, h, null, 0, w);
- for (int i = 0; i < h; i++) {
- for (int j = 0; j < w; j++) {
- int p = tmpMap[i * w + j];
- int r = (p >> 16) & 0xFF;
- int g = (p >> 8) & 0xFF;
- int b = (p) & 0xFF;
- out.write((byte) (r & 0xFF));
- out.write((byte) (g & 0xFF));
- out.write((byte) (b & 0xFF));
- }
- }
+ ImageEncodingHelper.encodeRenderedImageAsRGB(image, out);
}
/**
* Draws a BufferedImage to AFP.
*
- * @param bi
- * the BufferedImage
+ * @param image
+ * the RenderedImage
* @param imageResolution
* the resolution of the BufferedImage
* @param x
@@ -900,7 +999,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer {
* @param h
* the height of the viewport (in mpt)
*/
- public void drawBufferedImage(BufferedImage bi, int imageResolution, int x,
+ public void drawBufferedImage(RenderedImage image, int imageResolution, int x,
int y, int w, int h) {
int afpx = mpts2units(x);
int afpy = mpts2units(y);
@@ -910,21 +1009,24 @@ public class AFPRenderer extends AbstractPathOrientedRenderer {
ByteArrayOutputStream baout = new ByteArrayOutputStream();
try {
// Serialize image
- writeImage(bi, baout);
+ //TODO Eventually, this should be changed not to buffer as this increases the
+ //memory consumption (see PostScript output)
+ writeImage(image, baout);
byte[] buf = baout.toByteArray();
// Generate image
ImageObject io = afpDataStream.getImageObject(afpx, afpy, afpw,
afph, afpres, afpres);
io.setImageParameters(imageResolution, imageResolution,
- bi.getWidth(), bi.getHeight());
+ image.getWidth(), image.getHeight());
if (colorImages) {
io.setImageIDESize((byte)24);
io.setImageData(buf);
} else {
// TODO Teach it how to handle grayscale BufferedImages directly
// because this is pretty inefficient
- convertToGrayScaleImage(io, buf, bi.getWidth(), bi.getHeight(), this.bitsPerPixel);
+ convertToGrayScaleImage(io, buf,
+ image.getWidth(), image.getHeight(), this.bitsPerPixel);
}
} catch (IOException ioe) {
log.error("Error while serializing bitmap: " + ioe.getMessage(),
diff --git a/src/java/org/apache/fop/render/java2d/Java2DGraphics2DAdapter.java b/src/java/org/apache/fop/render/java2d/Java2DGraphics2DAdapter.java
index f74df6cff..1182fe42d 100644
--- a/src/java/org/apache/fop/render/java2d/Java2DGraphics2DAdapter.java
+++ b/src/java/org/apache/fop/render/java2d/Java2DGraphics2DAdapter.java
@@ -21,12 +21,14 @@ package org.apache.fop.render.java2d;
import java.awt.Color;
import java.awt.Dimension;
+import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
+import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
+
import org.apache.fop.render.Graphics2DAdapter;
-import org.apache.fop.render.Graphics2DImagePainter;
import org.apache.fop.render.RendererContext;
/**
@@ -34,16 +36,6 @@ import org.apache.fop.render.RendererContext;
*/
public class Java2DGraphics2DAdapter implements Graphics2DAdapter {
- private Java2DGraphicsState state;
-
- /**
- * Main constructor
- * @param state the state tracker for this rendering run
- */
- public Java2DGraphics2DAdapter(Java2DGraphicsState state) {
- this.state = state;
- }
-
/** {@inheritDoc} */
public void paintImage(Graphics2DImagePainter painter,
RendererContext context,
@@ -63,26 +55,28 @@ public class Java2DGraphics2DAdapter implements Graphics2DAdapter {
float sy = fheight / (float)imh;
Java2DRenderer renderer = (Java2DRenderer)context.getRenderer();
- renderer.saveGraphicsState();
- state.getGraph().setColor(Color.black);
- state.getGraph().setBackground(Color.black);
+ Java2DGraphicsState state = renderer.state;
+
+ //Create copy and paint on that
+ Graphics2D g2d = (Graphics2D)state.getGraph().create();
+ g2d.setColor(Color.black);
+ g2d.setBackground(Color.black);
//TODO Clip to the image area.
// transform so that the coordinates (0,0) is from the top left
// and positive is down and to the right. (0,0) is where the
// viewBox puts it.
- state.getGraph().translate(fx, fy);
+ g2d.translate(fx, fy);
AffineTransform at = AffineTransform.getScaleInstance(sx, sy);
if (!at.isIdentity()) {
- state.getGraph().transform(at);
+ g2d.transform(at);
}
Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
- painter.paint(state.getGraph(), area);
+ painter.paint(g2d, area);
- renderer.restoreGraphicsState();
-
+ g2d.dispose();
}
}
diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java
index eededf13b..0f73c5761 100644
--- a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java
+++ b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java
@@ -25,7 +25,6 @@ import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
-import java.awt.color.ColorSpace;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
@@ -33,14 +32,6 @@ import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
-import java.awt.image.ColorModel;
-import java.awt.image.ComponentColorModel;
-import java.awt.image.DataBuffer;
-import java.awt.image.DataBufferByte;
-import java.awt.image.PixelInterleavedSampleModel;
-import java.awt.image.Raster;
-import java.awt.image.SampleModel;
-import java.awt.image.WritableRaster;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
@@ -51,7 +42,15 @@ import java.util.List;
import java.util.Map;
import java.util.Stack;
-import org.w3c.dom.Document;
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
+import org.apache.xmlgraphics.image.loader.impl.ImageRendered;
+import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
+import org.apache.xmlgraphics.image.loader.util.ImageUtil;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
@@ -65,13 +64,11 @@ import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.inline.WordArea;
+import org.apache.fop.datatypes.URISpecification;
import org.apache.fop.fo.Constants;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.Typeface;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.image.ImageFactory;
-import org.apache.fop.image.XMLImage;
import org.apache.fop.render.AbstractPathOrientedRenderer;
import org.apache.fop.render.Graphics2DAdapter;
import org.apache.fop.render.RendererContext;
@@ -184,7 +181,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem
/** {@inheritDoc} */
public Graphics2DAdapter getGraphics2DAdapter() {
- return new Java2DGraphics2DAdapter(state);
+ return new Java2DGraphics2DAdapter();
}
/**
@@ -884,76 +881,58 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem
/**
* {@inheritDoc}
*/
- protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) {
+ protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) {
int x = currentIPPosition + (int)Math.round(pos.getX());
int y = currentBPPosition + (int)Math.round(pos.getY());
- url = ImageFactory.getURL(url);
-
- ImageFactory fact = userAgent.getFactory().getImageFactory();
- FopImage fopimage = fact.getImage(url, userAgent);
-
- if (fopimage == null) {
- return;
- }
- if (!fopimage.load(FopImage.DIMENSIONS)) {
- return;
- }
- int w = fopimage.getWidth();
- int h = fopimage.getHeight();
- String mime = fopimage.getMimeType();
- if ("text/xml".equals(mime)) {
- if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
- return;
- }
- Document doc = ((XMLImage) fopimage).getDocument();
- String ns = ((XMLImage) fopimage).getNameSpace();
- renderDocument(doc, ns, pos, foreignAttributes);
-
- } else if ("image/svg+xml".equals(mime)) {
- if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
- return;
- }
- Document doc = ((XMLImage) fopimage).getDocument();
- String ns = ((XMLImage) fopimage).getNameSpace();
-
- renderDocument(doc, ns, pos, foreignAttributes);
- } else if ("image/eps".equals(mime)) {
- log.warn("EPS images are not supported by this renderer");
- } else {
- if (!fopimage.load(FopImage.BITMAP)) {
- log.warn("Loading of bitmap failed: " + url);
- return;
+ uri = URISpecification.getURL(uri);
+
+ ImageManager manager = getUserAgent().getFactory().getImageManager();
+ ImageInfo info = null;
+ try {
+ ImageSessionContext sessionContext = getUserAgent().getImageSessionContext();
+ info = manager.getImageInfo(uri, sessionContext);
+ final ImageFlavor[] flavors = new ImageFlavor[]
+ {ImageFlavor.GRAPHICS2D,
+ ImageFlavor.BUFFERED_IMAGE,
+ ImageFlavor.RENDERED_IMAGE,
+ ImageFlavor.XML_DOM};
+ Map hints = ImageUtil.getDefaultHints(sessionContext);
+ org.apache.xmlgraphics.image.loader.Image img = manager.getImage(
+ info, flavors, hints, sessionContext);
+ if (img instanceof ImageGraphics2D) {
+ ImageGraphics2D imageG2D = (ImageGraphics2D)img;
+ int width = (int)pos.getWidth();
+ int height = (int)pos.getHeight();
+ RendererContext context = createRendererContext(
+ x, y, width, height, foreignAttributes);
+ getGraphics2DAdapter().paintImage(imageG2D.getGraphics2DImagePainter(),
+ context, x, y, width, height);
+ } else if (img instanceof ImageRendered) {
+ ImageRendered imgRend = (ImageRendered)img;
+ AffineTransform at = new AffineTransform();
+ at.translate(x / 1000f, y / 1000f);
+ double sx = pos.getWidth() / info.getSize().getWidthMpt();
+ double sy = pos.getHeight() / info.getSize().getHeightMpt();
+ sx *= userAgent.getSourceResolution() / info.getSize().getDpiHorizontal();
+ sy *= userAgent.getSourceResolution() / info.getSize().getDpiVertical();
+ at.scale(sx, sy);
+ state.getGraph().drawRenderedImage(imgRend.getRenderedImage(), at);
+ } else if (img instanceof ImageXMLDOM) {
+ ImageXMLDOM imgXML = (ImageXMLDOM)img;
+ renderDocument(imgXML.getDocument(), imgXML.getRootNamespace(),
+ pos, foreignAttributes);
}
-
- byte[] raw = fopimage.getBitmaps();
-
- // TODO Hardcoded color and sample models, FIX ME!
- ColorModel cm = new ComponentColorModel(
- ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB),
- new int[] {8, 8, 8},
- false, false,
- ColorModel.OPAQUE, DataBuffer.TYPE_BYTE);
- SampleModel sampleModel = new PixelInterleavedSampleModel(
- DataBuffer.TYPE_BYTE, w, h, 3, w * 3, new int[] {0, 1, 2});
- DataBuffer dbuf = new DataBufferByte(raw, w * h * 3);
-
- WritableRaster raster = Raster.createWritableRaster(sampleModel,
- dbuf, null);
-
- java.awt.Image awtImage;
- // Combine the color model and raster into a buffered image
- awtImage = new BufferedImage(cm, raster, false, null);
-
- state.getGraph().drawImage(awtImage,
- (int)(x / 1000f), (int)(y / 1000f),
- (int)(pos.getWidth() / 1000f), (int)(pos.getHeight() / 1000f), null);
+ } catch (ImageException ie) {
+ log.error("Error while processing image: "
+ + (info != null ? info.toString() : uri), ie);
+ } catch (IOException ioe) {
+ log.error("I/O error while processing image: "
+ + (info != null ? info.toString() : uri), ioe);
}
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
protected RendererContext createRendererContext(int x, int y, int width, int height,
Map foreignAttributes) {
RendererContext context = super.createRendererContext(
@@ -962,9 +941,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem
return context;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public int print(Graphics g, PageFormat pageFormat, int pageIndex)
throws PrinterException {
if (pageIndex >= getNumberOfPages()) {
@@ -1004,6 +981,10 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem
//not necessary in Java2D
}
+ /**
+ * Controls the page background.
+ * @param transparentPageBackground true if the background should be transparent
+ */
public void setTransparentPageBackground(boolean transparentPageBackground) {
this.transparentPageBackground = transparentPageBackground;
}
diff --git a/src/java/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java b/src/java/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java
index 80c010afc..06a4d37a0 100644
--- a/src/java/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java
+++ b/src/java/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java
@@ -28,11 +28,13 @@ import java.io.IOException;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
+import org.apache.xmlgraphics.java2d.GraphicContext;
+import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
+
import org.apache.fop.render.AbstractGraphics2DAdapter;
-import org.apache.fop.render.Graphics2DImagePainter;
import org.apache.fop.render.RendererContext;
import org.apache.fop.util.UnitConv;
-import org.apache.xmlgraphics.java2d.GraphicContext;
/**
* Graphics2DAdapter implementation for PCL and HP GL/2.
@@ -110,7 +112,8 @@ public class PCLGraphics2DAdapter extends AbstractGraphics2DAdapter {
if (!painted) {
//Fallback solution: Paint to a BufferedImage
int resolution = (int)Math.round(context.getUserAgent().getTargetResolution());
- BufferedImage bi = paintToBufferedImage(painter, pclContext, resolution, true, false);
+ BufferedImage bi = paintToBufferedImage(painter, pclContext,
+ resolution, !pclContext.isColorCanvas(), false);
pcl.setCursorPos(x, y);
gen.paintBitmap(bi, new Dimension(width, height), pclContext.isSourceTransparency());
diff --git a/src/java/org/apache/fop/render/pcl/PCLRenderer.java b/src/java/org/apache/fop/render/pcl/PCLRenderer.java
index 732ce0f8f..b48c28089 100644
--- a/src/java/org/apache/fop/render/pcl/PCLRenderer.java
+++ b/src/java/org/apache/fop/render/pcl/PCLRenderer.java
@@ -24,24 +24,17 @@ import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
+import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
-import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
-import java.awt.image.ColorModel;
-import java.awt.image.ComponentColorModel;
-import java.awt.image.DataBuffer;
-import java.awt.image.DataBufferByte;
-import java.awt.image.PixelInterleavedSampleModel;
-import java.awt.image.Raster;
import java.awt.image.RenderedImage;
-import java.awt.image.SampleModel;
-import java.awt.image.WritableRaster;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
@@ -52,7 +45,19 @@ import org.w3c.dom.Document;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+import org.apache.xmlgraphics.image.loader.ImageSize;
+import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
+import org.apache.xmlgraphics.image.loader.impl.ImageRendered;
+import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
+import org.apache.xmlgraphics.image.loader.util.ImageUtil;
import org.apache.xmlgraphics.java2d.GraphicContext;
+import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.MimeConstants;
@@ -70,16 +75,12 @@ import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.inline.Viewport;
import org.apache.fop.area.inline.WordArea;
+import org.apache.fop.datatypes.URISpecification;
import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontMetrics;
-import org.apache.fop.image.EPSImage;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.image.ImageFactory;
-import org.apache.fop.image.XMLImage;
import org.apache.fop.render.Graphics2DAdapter;
-import org.apache.fop.render.Graphics2DImagePainter;
import org.apache.fop.render.PrintRenderer;
import org.apache.fop.render.RendererContext;
import org.apache.fop.render.RendererContextConstants;
@@ -135,6 +136,13 @@ public class PCLRenderer extends PrintRenderer {
private boolean allTextAsBitmaps = false;
/**
+ * Controls whether an RGB canvas is used when converting Java2D graphics to bitmaps.
+ * This can be used to work around problems with Apache Batik, for example, but setting
+ * this to true will increase memory consumption.
+ */
+ private boolean useColorCanvas = false;
+
+ /**
* Controls whether the generation of PJL commands gets disabled.
*/
private boolean disabledPJL = false;
@@ -991,87 +999,88 @@ public class PCLRenderer extends PrintRenderer {
}
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ protected RendererContext createRendererContext(int x, int y, int width, int height,
+ Map foreignAttributes) {
+ RendererContext context = super.createRendererContext(
+ x, y, width, height, foreignAttributes);
+ context.setProperty(PCLRendererContextConstants.PCL_COLOR_CANVAS,
+ Boolean.valueOf(this.useColorCanvas));
+ return context;
+ }
+
+ /** {@inheritDoc} */
public void renderImage(Image image, Rectangle2D pos) {
drawImage(image.getURL(), pos, image.getForeignAttributes());
}
+ private static final ImageFlavor[] FLAVORS = new ImageFlavor[]
+ {ImageFlavor.GRAPHICS2D,
+ ImageFlavor.BUFFERED_IMAGE,
+ ImageFlavor.RENDERED_IMAGE,
+ ImageFlavor.XML_DOM};
/**
* Draw an image at the indicated location.
- * @param url the URI/URL of the image
+ * @param uri the URI/URL of the image
* @param pos the position of the image
* @param foreignAttributes an optional Map with foreign attributes, may be null
*/
- protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) {
- url = ImageFactory.getURL(url);
- ImageFactory fact = userAgent.getFactory().getImageFactory();
- FopImage fopimage = fact.getImage(url, userAgent);
- if (fopimage == null) {
- return;
- }
- if (!fopimage.load(FopImage.DIMENSIONS)) {
- return;
- }
- String mime = fopimage.getMimeType();
- if ("text/xml".equals(mime)) {
- if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
- return;
- }
- Document doc = ((XMLImage) fopimage).getDocument();
- String ns = ((XMLImage) fopimage).getNameSpace();
-
- renderDocument(doc, ns, pos, foreignAttributes);
- } else if ("image/svg+xml".equals(mime)) {
- if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
- return;
- }
- Document doc = ((XMLImage) fopimage).getDocument();
- String ns = ((XMLImage) fopimage).getNameSpace();
-
- renderDocument(doc, ns, pos, foreignAttributes);
- } else if (fopimage instanceof EPSImage) {
- log.warn("EPS images are not supported by this renderer");
- } else {
- if (!fopimage.load(FopImage.BITMAP)) {
- log.error("Bitmap image could not be processed: " + fopimage);
- return;
- }
- byte[] imgmap = fopimage.getBitmaps();
+ protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) {
+ uri = URISpecification.getURL(uri);
+ Rectangle posInt = new Rectangle(
+ (int)pos.getX(),
+ (int)pos.getY(),
+ (int)pos.getWidth(),
+ (int)pos.getHeight());
+ Point origin = new Point(currentIPPosition, currentBPPosition);
+ int x = origin.x + posInt.x;
+ int y = origin.y + posInt.y;
+
+ ImageManager manager = getUserAgent().getFactory().getImageManager();
+ ImageInfo info = null;
+ try {
+ ImageSessionContext sessionContext = getUserAgent().getImageSessionContext();
+ info = manager.getImageInfo(uri, sessionContext);
- ColorModel cm = new ComponentColorModel(
- ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB),
- new int[] {8, 8, 8},
- false, false,
- ColorModel.OPAQUE, DataBuffer.TYPE_BYTE);
- int imgw = fopimage.getWidth();
- int imgh = fopimage.getHeight();
- SampleModel sampleModel = new PixelInterleavedSampleModel(
- DataBuffer.TYPE_BYTE, imgw, imgh, 3, imgw * 3, new int[] {0, 1, 2});
- DataBuffer dbuf = new DataBufferByte(imgmap, imgw * imgh * 3);
-
- WritableRaster raster = Raster.createWritableRaster(sampleModel,
- dbuf, null);
-
- // Combine the color model and raster into a buffered image
- RenderedImage img = new BufferedImage(cm, raster, false, null);
-
- try {
- setCursorPos(this.currentIPPosition + (int)pos.getX(),
- this.currentBPPosition + (int)pos.getY());
- gen.paintBitmap(img,
- new Dimension((int)pos.getWidth(), (int)pos.getHeight()),
+ //Only now fully load/prepare the image
+ Map hints = ImageUtil.getDefaultHints(sessionContext);
+ org.apache.xmlgraphics.image.loader.Image img = manager.getImage(
+ info, FLAVORS, hints, sessionContext);
+
+ //...and process the image
+ if (img instanceof ImageGraphics2D) {
+ ImageGraphics2D imageG2D = (ImageGraphics2D)img;
+ RendererContext context = createRendererContext(
+ posInt.x, posInt.y,
+ posInt.width, posInt.height, foreignAttributes);
+ getGraphics2DAdapter().paintImage(imageG2D.getGraphics2DImagePainter(),
+ context, x, y, posInt.width, posInt.height);
+ } else if (img instanceof ImageRendered) {
+ ImageRendered imgRend = (ImageRendered)img;
+ RenderedImage ri = imgRend.getRenderedImage();
+ setCursorPos(x, y);
+ gen.paintBitmap(ri,
+ new Dimension(posInt.width, posInt.height),
false);
- } catch (IOException ioe) {
- handleIOTrouble(ioe);
+ } else if (img instanceof ImageXMLDOM) {
+ ImageXMLDOM imgXML = (ImageXMLDOM)img;
+ renderDocument(imgXML.getDocument(), imgXML.getRootNamespace(),
+ pos, foreignAttributes);
+ } else {
+ throw new UnsupportedOperationException("Unsupported image type: " + img);
}
+
+ } catch (ImageException ie) {
+ log.error("Error while processing image: "
+ + (info != null ? info.toString() : uri), ie);
+ } catch (FileNotFoundException fe) {
+ log.error(fe.getMessage());
+ } catch (IOException ioe) {
+ handleIOTrouble(ioe);
}
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public void renderForeignObject(ForeignObject fo, Rectangle2D pos) {
Document doc = fo.getDocument();
String ns = fo.getNameSpace();
@@ -1153,52 +1162,45 @@ public class PCLRenderer extends PrintRenderer {
}
// background image
- if (back.getFopImage() != null) {
- FopImage fopimage = back.getFopImage();
- if (fopimage != null && fopimage.load(FopImage.DIMENSIONS)) {
- saveGraphicsState();
- clipRect(sx, sy, paddRectWidth, paddRectHeight);
- int horzCount = (int) ((paddRectWidth * 1000 / fopimage
- .getIntrinsicWidth()) + 1.0f);
- int vertCount = (int) ((paddRectHeight * 1000 / fopimage
- .getIntrinsicHeight()) + 1.0f);
- if (back.getRepeat() == EN_NOREPEAT) {
- horzCount = 1;
- vertCount = 1;
- } else if (back.getRepeat() == EN_REPEATX) {
- vertCount = 1;
- } else if (back.getRepeat() == EN_REPEATY) {
- horzCount = 1;
- }
- // change from points to millipoints
- sx *= 1000;
- sy *= 1000;
- if (horzCount == 1) {
- sx += back.getHoriz();
- }
- if (vertCount == 1) {
- sy += back.getVertical();
- }
- for (int x = 0; x < horzCount; x++) {
- for (int y = 0; y < vertCount; y++) {
- // place once
- Rectangle2D pos;
- // Image positions are relative to the currentIP/BP
- pos = new Rectangle2D.Float(
- sx - currentIPPosition
- + (x * fopimage.getIntrinsicWidth()),
- sy - currentBPPosition
- + (y * fopimage.getIntrinsicHeight()),
- fopimage.getIntrinsicWidth(),
- fopimage.getIntrinsicHeight());
- drawImage(back.getURL(), pos, null);
- }
+ if (back.getImageInfo() != null) {
+ ImageSize imageSize = back.getImageInfo().getSize();
+ saveGraphicsState();
+ clipRect(sx, sy, paddRectWidth, paddRectHeight);
+ int horzCount = (int) ((paddRectWidth * 1000 / imageSize.getWidthMpt()) + 1.0f);
+ int vertCount = (int) ((paddRectHeight * 1000 / imageSize.getHeightMpt()) + 1.0f);
+ if (back.getRepeat() == EN_NOREPEAT) {
+ horzCount = 1;
+ vertCount = 1;
+ } else if (back.getRepeat() == EN_REPEATX) {
+ vertCount = 1;
+ } else if (back.getRepeat() == EN_REPEATY) {
+ horzCount = 1;
+ }
+ // change from points to millipoints
+ sx *= 1000;
+ sy *= 1000;
+ if (horzCount == 1) {
+ sx += back.getHoriz();
+ }
+ if (vertCount == 1) {
+ sy += back.getVertical();
+ }
+ for (int x = 0; x < horzCount; x++) {
+ for (int y = 0; y < vertCount; y++) {
+ // place once
+ Rectangle2D pos;
+ // Image positions are relative to the currentIP/BP
+ pos = new Rectangle2D.Float(
+ sx - currentIPPosition
+ + (x * imageSize.getWidthMpt()),
+ sy - currentBPPosition
+ + (y * imageSize.getHeightMpt()),
+ imageSize.getWidthMpt(),
+ imageSize.getHeightMpt());
+ drawImage(back.getURL(), pos, null);
}
- restoreGraphicsState();
- } else {
- log.warn(
- "Can't find background image: " + back.getURL());
}
+ restoreGraphicsState();
}
}
@@ -1508,6 +1510,11 @@ public class PCLRenderer extends PrintRenderer {
}
}
+ /**
+ * Controls whether all text should be generated as bitmaps or only text for which there's
+ * no native font.
+ * @param allTextAsBitmaps true if all text should be painted as bitmaps
+ */
public void setAllTextAsBitmaps(boolean allTextAsBitmaps) {
this.allTextAsBitmaps = allTextAsBitmaps;
}
diff --git a/src/java/org/apache/fop/render/pcl/PCLRendererContext.java b/src/java/org/apache/fop/render/pcl/PCLRendererContext.java
index 32510137b..62d4bcaa4 100644
--- a/src/java/org/apache/fop/render/pcl/PCLRendererContext.java
+++ b/src/java/org/apache/fop/render/pcl/PCLRendererContext.java
@@ -62,11 +62,28 @@ public class PCLRendererContext extends RendererContext.RendererContextWrapper {
&& "true".equalsIgnoreCase((String)getForeignAttributes().get(qName));
}
+ /**
+ * Indicates whether the background should not be erased prior to painting.
+ * @return true if the background shouldn't be erased
+ */
public boolean isSourceTransparency() {
QName qName = new QName(ExtensionElementMapping.URI, null, "source-transparency");
return getForeignAttributes() != null
&& "true".equalsIgnoreCase((String)getForeignAttributes().get(qName));
}
+ /**
+ * Indicates whether an RGB canvas should be used rather than one with grayscales.
+ * This can be used to work around limitations of Apache Batik if you get error while
+ * processing SVG graphics. Note, however, that RGB mode will use more memory.
+ * @return true if an EGB canvas should be used
+ */
+ public boolean isColorCanvas() {
+ QName qName = new QName(ExtensionElementMapping.URI, null, "color-canvas");
+ Boolean prop = (Boolean)context.getProperty(PCLRendererContextConstants.PCL_COLOR_CANVAS);
+ return Boolean.TRUE.equals(prop)
+ || (getForeignAttributes() != null
+ && "true".equalsIgnoreCase((String)getForeignAttributes().get(qName)));
+ }
} \ No newline at end of file
diff --git a/src/java/org/apache/fop/render/pcl/PCLRendererContextConstants.java b/src/java/org/apache/fop/render/pcl/PCLRendererContextConstants.java
new file mode 100644
index 000000000..66ce40f5e
--- /dev/null
+++ b/src/java/org/apache/fop/render/pcl/PCLRendererContextConstants.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl;
+
+import org.apache.fop.render.RendererContextConstants;
+
+/**
+ * Defines a number of standard constants (keys) for use by the RendererContext class.
+ */
+public interface PCLRendererContextConstants extends RendererContextConstants {
+
+ /** The PDF document that this image is being drawn into. */
+ String PCL_COLOR_CANVAS = "color-canvas";
+
+}
diff --git a/src/java/org/apache/fop/render/pcl/PCLSVGHandler.java b/src/java/org/apache/fop/render/pcl/PCLSVGHandler.java
index 8c9179063..a016c692f 100644
--- a/src/java/org/apache/fop/render/pcl/PCLSVGHandler.java
+++ b/src/java/org/apache/fop/render/pcl/PCLSVGHandler.java
@@ -22,6 +22,7 @@ package org.apache.fop.render.pcl;
// FOP
import org.apache.fop.render.AbstractGenericSVGHandler;
import org.apache.fop.render.Renderer;
+import org.apache.fop.render.RendererContext;
/**
* PCL XML handler for SVG. Uses Apache Batik for SVG processing.
@@ -36,5 +37,12 @@ public class PCLSVGHandler extends AbstractGenericSVGHandler {
return (renderer instanceof PCLRenderer);
}
+ /** {@inheritDoc} */
+ protected void updateRendererContext(RendererContext context) {
+ //Work around a problem in Batik: Gradients cannot be done in ColorSpace.CS_GRAY
+ context.setProperty(PCLRendererContextConstants.PCL_COLOR_CANVAS,
+ Boolean.TRUE);
+ }
+
}
diff --git a/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java b/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java
new file mode 100644
index 000000000..cd80a6797
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf;
+import java.awt.color.ColorSpace;
+import java.awt.color.ICC_Profile;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.xmlgraphics.image.loader.Image;
+
+import org.apache.fop.pdf.PDFColor;
+import org.apache.fop.pdf.PDFConformanceException;
+import org.apache.fop.pdf.PDFDeviceColorSpace;
+import org.apache.fop.pdf.PDFDictionary;
+import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFICCBasedColorSpace;
+import org.apache.fop.pdf.PDFICCStream;
+import org.apache.fop.pdf.PDFImage;
+import org.apache.fop.pdf.PDFReference;
+import org.apache.fop.util.ColorProfileUtil;
+
+/**
+ * Abstract PDFImage implementation for the PDF renderer.
+ */
+public abstract class AbstractImageAdapter implements PDFImage {
+
+ /** logging instance */
+ private static Log log = LogFactory.getLog(AbstractImageAdapter.class);
+
+ private String key;
+ /** the image */
+ protected Image image;
+
+ private PDFICCStream pdfICCStream = null;
+
+ /**
+ * Creates a new PDFImage from an Image instance.
+ * @param image the image
+ * @param key XObject key
+ */
+ public AbstractImageAdapter(Image image, String key) {
+ this.image = image;
+ this.key = key;
+ }
+
+ /** {@inheritDoc} */
+ public String getKey() {
+ // key to look up XObject
+ return this.key;
+ }
+
+ /**
+ * Returns the image's color space.
+ * @return the color space
+ */
+ protected ColorSpace getImageColorSpace() {
+ return image.getColorSpace();
+ }
+
+ /** {@inheritDoc} */
+ public void setup(PDFDocument doc) {
+
+ ICC_Profile prof = image.getICCProfile();
+ PDFDeviceColorSpace pdfCS = toPDFColorSpace(getImageColorSpace());
+ if (prof != null) {
+ boolean defaultsRGB = ColorProfileUtil.isDefaultsRGB(prof);
+ String desc = ColorProfileUtil.getICCProfileDescription(prof);
+ if (log.isDebugEnabled()) {
+ log.debug("Image returns ICC profile: " + desc + ", default sRGB=" + defaultsRGB);
+ }
+ PDFICCBasedColorSpace cs = doc.getResources().getICCColorSpaceByProfileName(desc);
+ if (!defaultsRGB) {
+ if (cs == null) {
+ pdfICCStream = doc.getFactory().makePDFICCStream();
+ pdfICCStream.setColorSpace(prof, pdfCS);
+ cs = doc.getFactory().makeICCBasedColorSpace(null, null, pdfICCStream);
+ } else {
+ pdfICCStream = cs.getICCStream();
+ }
+ } else {
+ if (cs == null && "sRGB".equals(desc)) {
+ //It's the default sRGB profile which we mapped to DefaultRGB in PDFRenderer
+ cs = doc.getResources().getColorSpace("DefaultRGB");
+ }
+ pdfICCStream = cs.getICCStream();
+ }
+ }
+ if (doc.getProfile().getPDFAMode().isPDFA1LevelB()) {
+ if (pdfCS != null
+ && pdfCS.getColorSpace() != PDFDeviceColorSpace.DEVICE_RGB
+ && pdfCS.getColorSpace() != PDFDeviceColorSpace.DEVICE_GRAY
+ && prof == null) {
+ //See PDF/A-1, ISO 19005:1:2005(E), 6.2.3.3
+ //FOP is currently restricted to DeviceRGB if PDF/A-1 is active.
+ throw new PDFConformanceException(
+ "PDF/A-1 does not allow mixing DeviceRGB and DeviceCMYK: "
+ + image.getInfo());
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ public int getWidth() {
+ return image.getSize().getWidthPx();
+ }
+
+ /** {@inheritDoc} */
+ public int getHeight() {
+ return image.getSize().getHeightPx();
+ }
+
+ /** {@inheritDoc} */
+ public boolean isTransparent() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public PDFColor getTransparentColor() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public String getMask() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public String getSoftMask() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public PDFReference getSoftMaskReference() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isInverted() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isPS() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public PDFICCStream getICCStream() {
+ return pdfICCStream;
+ }
+
+ /** {@inheritDoc} */
+ public void populateXObjectDictionary(PDFDictionary dict) {
+ //nop
+ }
+
+ /**
+ * Converts a ColorSpace object to a PDFColorSpace object.
+ * @param cs ColorSpace instance
+ * @return PDFColorSpace new converted object
+ */
+ public static PDFDeviceColorSpace toPDFColorSpace(ColorSpace cs) {
+ if (cs == null) {
+ return null;
+ }
+
+ PDFDeviceColorSpace pdfCS = new PDFDeviceColorSpace(0);
+ switch (cs.getType()) {
+ case ColorSpace.TYPE_CMYK:
+ pdfCS.setColorSpace(PDFDeviceColorSpace.DEVICE_CMYK);
+ break;
+ case ColorSpace.TYPE_GRAY:
+ pdfCS.setColorSpace(PDFDeviceColorSpace.DEVICE_GRAY);
+ break;
+ default:
+ pdfCS.setColorSpace(PDFDeviceColorSpace.DEVICE_RGB);
+ }
+ return pdfCS;
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/render/pdf/FopPDFImage.java b/src/java/org/apache/fop/render/pdf/FopPDFImage.java
deleted file mode 100644
index e60c207d6..000000000
--- a/src/java/org/apache/fop/render/pdf/FopPDFImage.java
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.render.pdf;
-import java.awt.color.ColorSpace;
-import java.awt.color.ICC_Profile;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.apache.fop.image.EPSImage;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.image.TIFFImage;
-import org.apache.fop.pdf.BitmapImage;
-import org.apache.fop.pdf.CCFFilter;
-import org.apache.fop.pdf.DCTFilter;
-import org.apache.fop.pdf.PDFColor;
-import org.apache.fop.pdf.PDFConformanceException;
-import org.apache.fop.pdf.PDFDeviceColorSpace;
-import org.apache.fop.pdf.PDFDictionary;
-import org.apache.fop.pdf.PDFDocument;
-import org.apache.fop.pdf.PDFFilter;
-import org.apache.fop.pdf.PDFFilterList;
-import org.apache.fop.pdf.PDFICCBasedColorSpace;
-import org.apache.fop.pdf.PDFICCStream;
-import org.apache.fop.pdf.PDFImage;
-import org.apache.fop.pdf.PDFReference;
-import org.apache.fop.util.ColorProfileUtil;
-
-/**
- * PDFImage implementation for the PDF renderer.
- */
-public class FopPDFImage implements PDFImage {
-
- /** logging instance */
- private static Log log = LogFactory.getLog(FopPDFImage.class);
-
- private FopImage fopImage;
- private PDFICCStream pdfICCStream = null;
- private PDFFilter pdfFilter = null;
- private String maskRef;
- private PDFReference softMask;
- private boolean isPS = false;
- private boolean isCCF = false;
- private boolean isDCT = false;
- private String key;
-
- /**
- * Creates a new PDFImage from a FopImage
- * @param image Image
- * @param key XObject key
- */
- public FopPDFImage(FopImage image, String key) {
- fopImage = image;
- this.key = key;
- isPS = (fopImage instanceof EPSImage);
- }
-
- /**
- * {@inheritDoc}
- */
- public String getKey() {
- // key to look up XObject
- return this.key;
- }
-
- /**
- * {@inheritDoc}
- */
- public void setup(PDFDocument doc) {
- if ("image/jpeg".equals(fopImage.getMimeType())) {
- pdfFilter = new DCTFilter();
- pdfFilter.setApplied(true);
- isDCT = true;
-
- } else if ("image/tiff".equals(fopImage.getMimeType())
- && fopImage instanceof TIFFImage) {
- TIFFImage tiffImage = (TIFFImage) fopImage;
- if (tiffImage.getStripCount() == 1) {
- int comp = tiffImage.getCompression();
- if (comp == 1) {
- // Nothing to do
- } else if (comp == 3) {
- pdfFilter = new CCFFilter();
- pdfFilter.setApplied(true);
- isCCF = true;
- } else if (comp == 4) {
- pdfFilter = new CCFFilter();
- pdfFilter.setApplied(true);
- PDFDictionary dict = new PDFDictionary();
- dict.put("K", -1);
- dict.put("Columns", tiffImage.getWidth());
- ((CCFFilter)pdfFilter).setDecodeParms(dict);
- isCCF = true;
- } else if (comp == 6) {
- pdfFilter = new DCTFilter();
- pdfFilter.setApplied(true);
- isDCT = true;
- }
- }
- }
- if (isPS || isDCT || isCCF) {
- fopImage.load(FopImage.ORIGINAL_DATA);
- } else {
- fopImage.load(FopImage.BITMAP);
- }
- ICC_Profile prof = fopImage.getICCProfile();
- PDFDeviceColorSpace pdfCS = toPDFColorSpace(fopImage.getColorSpace());
- if (prof != null) {
- boolean defaultsRGB = ColorProfileUtil.isDefaultsRGB(prof);
- String desc = ColorProfileUtil.getICCProfileDescription(prof);
- if (log.isDebugEnabled()) {
- log.debug("Image returns ICC profile: " + desc + ", default sRGB=" + defaultsRGB);
- }
- PDFICCBasedColorSpace cs = doc.getResources().getICCColorSpaceByProfileName(desc);
- if (!defaultsRGB) {
- if (cs == null) {
- pdfICCStream = doc.getFactory().makePDFICCStream();
- pdfICCStream.setColorSpace(prof, pdfCS);
- cs = doc.getFactory().makeICCBasedColorSpace(null, null, pdfICCStream);
- } else {
- pdfICCStream = cs.getICCStream();
- }
- } else {
- if (cs == null && "sRGB".equals(desc)) {
- //It's the default sRGB profile which we mapped to DefaultRGB in PDFRenderer
- cs = doc.getResources().getColorSpace("DefaultRGB");
- }
- pdfICCStream = cs.getICCStream();
- }
- }
- //Handle transparency mask if applicable
- if (fopImage.hasSoftMask()) {
- doc.getProfile().verifyTransparencyAllowed(fopImage.getOriginalURI());
- //TODO Implement code to combine image with background color if transparency is not
- //allowed (need BufferedImage support for that)
- byte [] softMaskBitmap = fopImage.getSoftMask();
- if (softMaskBitmap == null) {
- return;
- }
- BitmapImage fopimg = new BitmapImage
- ("Mask:" + key, fopImage.getWidth(), fopImage.getHeight(),
- softMaskBitmap, null);
- fopimg.setColorSpace(new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_GRAY));
- softMask = doc.addImage(null, fopimg).makeReference();
- }
- if (doc.getProfile().getPDFAMode().isPDFA1LevelB()) {
- if (pdfCS != null
- && pdfCS.getColorSpace() != PDFDeviceColorSpace.DEVICE_RGB
- && pdfCS.getColorSpace() != PDFDeviceColorSpace.DEVICE_GRAY
- && prof == null) {
- //See PDF/A-1, ISO 19005:1:2005(E), 6.2.3.3
- //FOP is currently restricted to DeviceRGB if PDF/A-1 is active.
- throw new PDFConformanceException(
- "PDF/A-1 does not allow mixing DeviceRGB and DeviceCMYK: "
- + fopImage.getOriginalURI());
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public int getWidth() {
- return fopImage.getWidth();
- }
-
- /**
- * {@inheritDoc}
- */
- public int getHeight() {
- return fopImage.getHeight();
- }
-
- /**
- * {@inheritDoc}
- */
- public PDFDeviceColorSpace getColorSpace() {
- // DeviceGray, DeviceRGB, or DeviceCMYK
- if (isCCF || isDCT || isPS) {
- return toPDFColorSpace(fopImage.getColorSpace());
- } else {
- return toPDFColorSpace(ColorSpace.getInstance(ColorSpace.CS_sRGB));
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public int getBitsPerPixel() {
- if (isCCF) {
- return fopImage.getBitsPerPixel();
- } else {
- return 8; //TODO This is suboptimal, handling everything as RGB
- //The image wrappers can mostly only return RGB bitmaps right now. This should
- //be improved so the renderers can deal directly with RenderedImage instances.
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isTransparent() {
- return fopImage.isTransparent();
- }
-
- /**
- * {@inheritDoc}
- */
- public PDFColor getTransparentColor() {
- return new PDFColor(fopImage.getTransparentColor().getRed(),
- fopImage.getTransparentColor().getGreen(),
- fopImage.getTransparentColor().getBlue());
- }
-
- /**
- * {@inheritDoc}
- */
- public String getMask() {
- return maskRef;
- }
-
- /** {@inheritDoc} */
- public PDFReference getSoftMaskReference() {
- return softMask;
- }
-
- /** @return true for CMYK images generated by Adobe Photoshop */
- public boolean isInverted() {
- return fopImage.isInverted();
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isPS() {
- return isPS;
- }
-
- /**
- * {@inheritDoc}
- */
- public PDFFilter getPDFFilter() {
- return pdfFilter;
- }
-
- /**
- * {@inheritDoc}
- */
- public void outputContents(OutputStream out) throws IOException {
- if (isPS) {
- outputPostScriptContents(out);
- } else {
- if (fopImage.getBitmapsSize() > 0) {
- out.write(fopImage.getBitmaps());
- } else {
- out.write(fopImage.getRessourceBytes());
- }
- }
- }
-
- /**
- * Serializes an EPS image to an OutputStream.
- * @param out OutputStream to write to
- * @throws IOException in case of an I/O problem
- */
- protected void outputPostScriptContents(OutputStream out) throws IOException {
- EPSImage epsImage = (EPSImage) fopImage;
- int[] bbox = epsImage.getBBox();
- int bboxw = bbox[2] - bbox[0];
- int bboxh = bbox[3] - bbox[1];
-
- // delegate the stream work to PDFStream
- //PDFStream imgStream = new PDFStream(0);
-
- StringBuffer preamble = new StringBuffer();
- preamble.append("%%BeginDocument: " + epsImage.getDocName() + "\n");
-
- preamble.append("userdict begin % Push userdict on dict stack\n");
- preamble.append("/PreEPS_state save def\n");
- preamble.append("/dict_stack countdictstack def\n");
- preamble.append("/ops_count count 1 sub def\n");
- preamble.append("/showpage {} def\n");
-
-
- preamble.append((double)(1f / (double) bboxw) + " "
- + (double)(1f / (double) bboxh) + " scale\n");
- preamble.append(-bbox[0] + " " + (-bbox[1]) + " translate\n");
- preamble.append(bbox[0] + " " + bbox[1] + " "
- + bboxw + " " + bboxh + " rectclip\n");
- preamble.append("newpath\n");
-
- StringBuffer post = new StringBuffer();
- post.append("%%EndDocument\n");
- post.append("count ops_count sub {pop} repeat\n");
- post.append("countdictstack dict_stack sub {end} repeat\n");
- post.append("PreEPS_state restore\n");
- post.append("end % userdict\n");
-
- //Write Preamble
- out.write(PDFDocument.encode(preamble.toString()));
- //Write EPS contents
- out.write(((EPSImage)fopImage).getEPSImage());
- //Writing trailer
- out.write(PDFDocument.encode(post.toString()));
- }
-
- /**
- * {@inheritDoc}
- */
- public PDFICCStream getICCStream() {
- return pdfICCStream;
- }
-
- /**
- * Converts a ColorSpace object to a PDFColorSpace object.
- * @param cs ColorSpace instance
- * @return PDFColorSpace new converted object
- */
- public static PDFDeviceColorSpace toPDFColorSpace(ColorSpace cs) {
- if (cs == null) {
- return null;
- }
-
- PDFDeviceColorSpace pdfCS = new PDFDeviceColorSpace(0);
- switch(cs.getType()) {
- case ColorSpace.TYPE_CMYK:
- pdfCS.setColorSpace(PDFDeviceColorSpace.DEVICE_CMYK);
- break;
- case ColorSpace.TYPE_RGB:
- pdfCS.setColorSpace(PDFDeviceColorSpace.DEVICE_RGB);
- break;
- case ColorSpace.TYPE_GRAY:
- pdfCS.setColorSpace(PDFDeviceColorSpace.DEVICE_GRAY);
- break;
- }
- return pdfCS;
- }
-
- /**
- * {@inheritDoc}
- */
- public String getFilterHint() {
- if (isPS) {
- return PDFFilterList.CONTENT_FILTER;
- } else if (isDCT) {
- return PDFFilterList.JPEG_FILTER;
- } else if (isCCF) {
- return PDFFilterList.TIFF_FILTER;
- } else {
- return PDFFilterList.IMAGE_FILTER;
- }
- }
-
-}
-
diff --git a/src/java/org/apache/fop/render/pdf/ImageRawCCITTFaxAdapter.java b/src/java/org/apache/fop/render/pdf/ImageRawCCITTFaxAdapter.java
new file mode 100644
index 000000000..b80e2c03e
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/ImageRawCCITTFaxAdapter.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf;
+import java.awt.color.ColorSpace;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.xmlgraphics.image.codec.tiff.TIFFImage;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax;
+
+import org.apache.fop.pdf.CCFFilter;
+import org.apache.fop.pdf.PDFDeviceColorSpace;
+import org.apache.fop.pdf.PDFDictionary;
+import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFFilter;
+import org.apache.fop.pdf.PDFFilterList;
+
+/**
+ * PDFImage implementation for the PDF renderer which handles raw CCITT fax images.
+ */
+public class ImageRawCCITTFaxAdapter extends AbstractImageAdapter {
+
+ private PDFFilter pdfFilter = null;
+
+ /**
+ * Creates a new PDFImage from an Image instance.
+ * @param image the CCITT encoded image
+ * @param key XObject key
+ */
+ public ImageRawCCITTFaxAdapter(ImageRawCCITTFax image, String key) {
+ super(image, key);
+ }
+
+ /**
+ * Returns the {@link ImageRawCCITTFax} instance for this adapter.
+ * @return the image instance
+ */
+ public ImageRawCCITTFax getImage() {
+ return ((ImageRawCCITTFax)this.image);
+ }
+
+ /** {@inheritDoc} */
+ public void setup(PDFDocument doc) {
+ pdfFilter = new CCFFilter();
+ pdfFilter.setApplied(true);
+ PDFDictionary dict = new PDFDictionary();
+ dict.put("Columns", this.image.getSize().getWidthPx());
+ int compression = getImage().getCompression();
+ switch (compression) {
+ case TIFFImage.COMP_FAX_G3_1D :
+ dict.put("K", 0);
+ break;
+ case TIFFImage.COMP_FAX_G3_2D :
+ dict.put("K", 1);
+ break;
+ case TIFFImage.COMP_FAX_G4_2D :
+ dict.put("K", -1);
+ break;
+ default:
+ throw new IllegalStateException("Invalid compression scheme: " + compression);
+ }
+ ((CCFFilter)pdfFilter).setDecodeParms(dict);
+
+ super.setup(doc);
+ }
+
+ /** {@inheritDoc} */
+ public PDFDeviceColorSpace getColorSpace() {
+ return toPDFColorSpace(ColorSpace.getInstance(ColorSpace.CS_GRAY));
+ }
+
+ /** {@inheritDoc} */
+ public int getBitsPerComponent() {
+ return 1;
+ }
+
+ /** {@inheritDoc} */
+ public PDFFilter getPDFFilter() {
+ return pdfFilter;
+ }
+
+ /** {@inheritDoc} */
+ public void outputContents(OutputStream out) throws IOException {
+ getImage().writeTo(out);
+ }
+
+ /** {@inheritDoc} */
+ public String getFilterHint() {
+ return PDFFilterList.TIFF_FILTER;
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/render/pdf/ImageRawJPEGAdapter.java b/src/java/org/apache/fop/render/pdf/ImageRawJPEGAdapter.java
new file mode 100644
index 000000000..4b0ce4a85
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/ImageRawJPEGAdapter.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG;
+
+import org.apache.fop.pdf.DCTFilter;
+import org.apache.fop.pdf.PDFDeviceColorSpace;
+import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFFilter;
+import org.apache.fop.pdf.PDFFilterList;
+
+/**
+ * PDFImage implementation for the PDF renderer which handles raw JPEG images.
+ */
+public class ImageRawJPEGAdapter extends AbstractImageAdapter {
+
+ private PDFFilter pdfFilter = null;
+
+ /**
+ * Creates a new PDFImage from an Image instance.
+ * @param image the JPEG image
+ * @param key XObject key
+ */
+ public ImageRawJPEGAdapter(ImageRawJPEG image, String key) {
+ super(image, key);
+ }
+
+ /**
+ * Returns the {@link ImageRawJPEG} instance for this adapter.
+ * @return the image instance
+ */
+ public ImageRawJPEG getImage() {
+ return ((ImageRawJPEG)this.image);
+ }
+
+ /** {@inheritDoc} */
+ public void setup(PDFDocument doc) {
+ pdfFilter = new DCTFilter();
+ pdfFilter.setApplied(true);
+
+ super.setup(doc);
+ }
+
+ /** {@inheritDoc} */
+ public PDFDeviceColorSpace getColorSpace() {
+ // DeviceGray, DeviceRGB, or DeviceCMYK
+ return toPDFColorSpace(getImageColorSpace());
+ }
+
+ /** {@inheritDoc} */
+ public int getBitsPerComponent() {
+ return 8;
+ }
+
+ /** @return true for CMYK images generated by Adobe Photoshop */
+ public boolean isInverted() {
+ return getImage().isInverted();
+ }
+
+ /** {@inheritDoc} */
+ public PDFFilter getPDFFilter() {
+ return pdfFilter;
+ }
+
+ /** {@inheritDoc} */
+ public void outputContents(OutputStream out) throws IOException {
+ getImage().writeTo(out);
+ }
+
+ /** {@inheritDoc} */
+ public String getFilterHint() {
+ return PDFFilterList.JPEG_FILTER;
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java b/src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java
new file mode 100644
index 000000000..62e83da81
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java
@@ -0,0 +1,249 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf;
+import java.awt.color.ColorSpace;
+import java.awt.image.ColorModel;
+import java.awt.image.IndexColorModel;
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.xmlgraphics.image.loader.impl.ImageRendered;
+import org.apache.xmlgraphics.ps.ImageEncodingHelper;
+
+import org.apache.fop.pdf.AlphaRasterImage;
+import org.apache.fop.pdf.PDFArray;
+import org.apache.fop.pdf.PDFColor;
+import org.apache.fop.pdf.PDFDeviceColorSpace;
+import org.apache.fop.pdf.PDFDictionary;
+import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFFilter;
+import org.apache.fop.pdf.PDFFilterList;
+import org.apache.fop.pdf.PDFName;
+import org.apache.fop.pdf.PDFReference;
+
+/**
+ * PDFImage implementation for the PDF renderer which handles RenderedImages.
+ */
+public class ImageRenderedAdapter extends AbstractImageAdapter {
+
+ /** logging instance */
+ private static Log log = LogFactory.getLog(ImageRenderedAdapter.class);
+
+ private ImageEncodingHelper encodingHelper;
+
+ private PDFFilter pdfFilter = null;
+ private String maskRef;
+ private PDFReference softMask;
+
+ /**
+ * Creates a new PDFImage from an Image instance.
+ * @param image the image
+ * @param key XObject key
+ */
+ public ImageRenderedAdapter(ImageRendered image, String key) {
+ super(image, key);
+ this.encodingHelper = new ImageEncodingHelper(image.getRenderedImage());
+ }
+
+ /**
+ * Returns the ImageRendered instance for this adapter.
+ * @return the ImageRendered instance
+ */
+ public ImageRendered getImage() {
+ return ((ImageRendered)this.image);
+ }
+
+ private ColorModel getEffectiveColorModel() {
+ return encodingHelper.getEncodedColorModel();
+ }
+
+ /** {@inheritDoc} */
+ protected ColorSpace getImageColorSpace() {
+ return getEffectiveColorModel().getColorSpace();
+ }
+
+ /** {@inheritDoc} */
+ public void setup(PDFDocument doc) {
+ RenderedImage ri = getImage().getRenderedImage();
+ ColorModel cm = getEffectiveColorModel();
+
+ super.setup(doc);
+
+ //Handle transparency mask if applicable
+ ColorModel orgcm = ri.getColorModel();
+ if (orgcm.hasAlpha() && orgcm.getTransparency() == ColorModel.TRANSLUCENT) {
+ doc.getProfile().verifyTransparencyAllowed(image.getInfo().getOriginalURI());
+ //TODO Implement code to combine image with background color if transparency is not
+ //allowed (need BufferedImage support for that)
+
+ AlphaRasterImage alphaImage = new AlphaRasterImage("Mask:" + getKey(), ri);
+ this.softMask = doc.addImage(null, alphaImage).makeReference();
+ }
+ }
+
+ /** {@inheritDoc} */
+ public PDFDeviceColorSpace getColorSpace() {
+ // DeviceGray, DeviceRGB, or DeviceCMYK
+ return toPDFColorSpace(getEffectiveColorModel().getColorSpace());
+ }
+
+ /** {@inheritDoc} */
+ public int getBitsPerComponent() {
+ ColorModel cm = getEffectiveColorModel();
+ if (cm instanceof IndexColorModel) {
+ IndexColorModel icm = (IndexColorModel)cm;
+ return icm.getComponentSize(0);
+ } else {
+ return cm.getComponentSize(0);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public boolean isTransparent() {
+ ColorModel cm = getEffectiveColorModel();
+ if (cm instanceof IndexColorModel) {
+ if (cm.getTransparency() == IndexColorModel.TRANSLUCENT) {
+ return true;
+ }
+ }
+ return (getImage().getTransparentColor() != null);
+ }
+
+ private static Integer getIndexOfFirstTransparentColorInPalette(RenderedImage image) {
+ ColorModel cm = image.getColorModel();
+ if (cm instanceof IndexColorModel) {
+ IndexColorModel icm = (IndexColorModel)cm;
+ //Identify the transparent color in the palette
+ byte[] alphas = new byte[icm.getMapSize()];
+ byte[] reds = new byte[icm.getMapSize()];
+ byte[] greens = new byte[icm.getMapSize()];
+ byte[] blues = new byte[icm.getMapSize()];
+ icm.getAlphas(alphas);
+ icm.getReds(reds);
+ icm.getGreens(greens);
+ icm.getBlues(blues);
+ for (int i = 0;
+ i < ((IndexColorModel) cm).getMapSize();
+ i++) {
+ if ((alphas[i] & 0xFF) == 0) {
+ return new Integer(i);
+ }
+ }
+ }
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public PDFColor getTransparentColor() {
+ ColorModel cm = getEffectiveColorModel();
+ if (cm instanceof IndexColorModel) {
+ IndexColorModel icm = (IndexColorModel)cm;
+ if (cm.getTransparency() == IndexColorModel.TRANSLUCENT) {
+ int transPixel = icm.getTransparentPixel();
+ return new PDFColor(
+ icm.getRed(transPixel),
+ icm.getGreen(transPixel),
+ icm.getBlue(transPixel));
+ }
+ }
+ return new PDFColor(getImage().getTransparentColor());
+ }
+
+ /** {@inheritDoc} */
+ public String getMask() {
+ return maskRef;
+ }
+
+ /** {@inheritDoc} */
+ public PDFReference getSoftMaskReference() {
+ return softMask;
+ }
+
+ /** {@inheritDoc} */
+ public PDFFilter getPDFFilter() {
+ return pdfFilter;
+ }
+
+ /** {@inheritDoc} */
+ public void outputContents(OutputStream out) throws IOException {
+ encodingHelper.encode(out);
+ }
+
+ private static final int MAX_HIVAL = 255;
+
+ /** {@inheritDoc} */
+ public void populateXObjectDictionary(PDFDictionary dict) {
+ ColorModel cm = getEffectiveColorModel();
+ if (cm instanceof IndexColorModel) {
+ IndexColorModel icm = (IndexColorModel)cm;
+ PDFArray indexed = new PDFArray(dict);
+ indexed.add(new PDFName("Indexed"));
+
+ if (icm.getColorSpace().getType() != ColorSpace.TYPE_RGB) {
+ log.warn("Indexed color space is not using RGB as base color space."
+ + " The image may not be handled correctly."
+ + " Base color space: " + icm.getColorSpace()
+ + " Image: " + image.getInfo());
+ }
+ indexed.add(new PDFName(toPDFColorSpace(icm.getColorSpace()).getName()));
+ int c = icm.getMapSize();
+ int hival = c - 1;
+ if (hival > MAX_HIVAL) {
+ throw new UnsupportedOperationException("hival must not go beyond " + MAX_HIVAL);
+ }
+ indexed.add(new Integer(hival));
+ int[] palette = new int[c];
+ icm.getRGBs(palette);
+ ByteArrayOutputStream baout = new ByteArrayOutputStream();
+ for (int i = 0; i < c; i++) {
+ //TODO Probably doesn't work for non RGB based color spaces
+ //See log warning above
+ int entry = palette[i];
+ baout.write((entry & 0xFF0000) >> 16);
+ baout.write((entry & 0xFF00) >> 8);
+ baout.write(entry & 0xFF);
+ }
+ indexed.add(baout.toByteArray());
+
+ dict.put("ColorSpace", indexed);
+ dict.put("BitsPerComponent", icm.getPixelSize());
+
+ Integer index = getIndexOfFirstTransparentColorInPalette(getImage().getRenderedImage());
+ if (index != null) {
+ PDFArray mask = new PDFArray(dict);
+ mask.add(index);
+ mask.add(index);
+ dict.put("Mask", mask);
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ public String getFilterHint() {
+ return PDFFilterList.IMAGE_FILTER;
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java b/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java
index eb0e4b378..d1e0abd5c 100644
--- a/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java
+++ b/src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java
@@ -28,8 +28,9 @@ import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
+import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
+
import org.apache.fop.render.AbstractGraphics2DAdapter;
-import org.apache.fop.render.Graphics2DImagePainter;
import org.apache.fop.render.RendererContext;
import org.apache.fop.render.RendererContext.RendererContextWrapper;
import org.apache.fop.svg.PDFGraphics2D;
diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandler.java b/src/java/org/apache/fop/render/pdf/PDFImageHandler.java
index 52043b38e..d62dcbc5b 100644
--- a/src/java/org/apache/fop/render/pdf/PDFImageHandler.java
+++ b/src/java/org/apache/fop/render/pdf/PDFImageHandler.java
@@ -19,11 +19,15 @@
package org.apache.fop.render.pdf;
+import java.awt.Point;
+import java.awt.Rectangle;
import java.io.IOException;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.pdf.PDFDocument;
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+
import org.apache.fop.pdf.PDFXObject;
+import org.apache.fop.render.RendererContext;
/**
* This interface is used for handling all sorts of image type for PDF output.
@@ -31,20 +35,38 @@ import org.apache.fop.pdf.PDFXObject;
public interface PDFImageHandler {
/**
- * Returns the MIME type supported by this instance.
- * @return the MIME type
+ * Returns the priority for this image handler. A lower value means higher priority. This
+ * information is used to build the ordered/prioritized list of supported ImageFlavors for
+ * the PDF renderer. The built-in handlers use priorities between 100 and 999.
+ * @return a positive integer (>0) indicating the priority
+ */
+ int getPriority();
+
+ /**
+ * Returns the {@link ImageFlavor}s supported by this instance
+ * @return the supported image flavors
+ */
+ ImageFlavor[] getSupportedImageFlavors();
+
+ /**
+ * Returns the {@link Image} subclass supported by this instance.
+ * @return the Image type
*/
- String getSupportedMimeType();
+ Class getSupportedImageClass();
/**
- * Generates the PDF objects for the given FopImage instance and returns
- * the resulting XObject.
+ * Generates the PDF objects for the given {@link Image} instance. If the handler generates
+ * an XObject, it shall return it or otherwise return null. A generated XObject shall be
+ * placed in the current viewport according to the two parameters "origin" and "pos".
+ * @param context the PDF renderer context
* @param image the image to be handled
- * @param uri the URI of the image
- * @param pdfDoc the target PDF document
- * @return the generated XObject
+ * @param origin the current position in the current viewport (in millipoints)
+ * @param pos the position and scaling of the image relative to the origin point
+ * (in millipoints)
+ * @return the generated XObject or null if no XObject was generated
* @throws IOException if an I/O error occurs
*/
- PDFXObject generateImage(FopImage image, String uri, PDFDocument pdfDoc) throws IOException;
+ PDFXObject generateImage(RendererContext context, Image image,
+ Point origin, Rectangle pos) throws IOException;
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java
new file mode 100644
index 000000000..f1825297e
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.io.IOException;
+
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
+
+import org.apache.fop.pdf.PDFXObject;
+import org.apache.fop.render.RendererContext;
+
+/**
+ * PDFImageHandler implementation which handles Graphics2D images.
+ */
+public class PDFImageHandlerGraphics2D implements PDFImageHandler {
+
+ private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
+ ImageFlavor.GRAPHICS2D,
+ };
+
+ /** {@inheritDoc} */
+ public PDFXObject generateImage(RendererContext context, Image image,
+ Point origin, Rectangle pos)
+ throws IOException {
+ PDFRenderer renderer = (PDFRenderer)context.getRenderer();
+ ImageGraphics2D imageG2D = (ImageGraphics2D)image;
+ renderer.getGraphics2DAdapter().paintImage(imageG2D.getGraphics2DImagePainter(),
+ context, origin.x + pos.x, origin.y + pos.y, pos.width, pos.height);
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public int getPriority() {
+ return 200;
+ }
+
+ /** {@inheritDoc} */
+ public Class getSupportedImageClass() {
+ return ImageGraphics2D.class;
+ }
+
+ /** {@inheritDoc} */
+ public ImageFlavor[] getSupportedImageFlavors() {
+ return FLAVORS;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawCCITTFax.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawCCITTFax.java
new file mode 100644
index 000000000..65142878a
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawCCITTFax.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.io.IOException;
+
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax;
+
+import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFImage;
+import org.apache.fop.pdf.PDFResourceContext;
+import org.apache.fop.pdf.PDFXObject;
+import org.apache.fop.render.RendererContext;
+
+/**
+ * PDFImageHandler implementation which handles CCITT encoded images (CCITT fax group 3/4).
+ */
+public class PDFImageHandlerRawCCITTFax implements PDFImageHandler {
+
+ private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
+ ImageFlavor.RAW_CCITTFAX,
+ };
+
+ /** {@inheritDoc} */
+ public PDFXObject generateImage(RendererContext context, Image image,
+ Point origin, Rectangle pos)
+ throws IOException {
+ PDFRenderer renderer = (PDFRenderer)context.getRenderer();
+ ImageRawCCITTFax ccitt = (ImageRawCCITTFax)image;
+ PDFDocument pdfDoc = (PDFDocument)context.getProperty(
+ PDFRendererContextConstants.PDF_DOCUMENT);
+ PDFResourceContext resContext = (PDFResourceContext)context.getProperty(
+ PDFRendererContextConstants.PDF_CONTEXT);
+
+ PDFImage pdfimage = new ImageRawCCITTFaxAdapter(ccitt, image.getInfo().getOriginalURI());
+ PDFXObject xobj = pdfDoc.addImage(resContext, pdfimage);
+
+ float x = (float)pos.getX() / 1000f;
+ float y = (float)pos.getY() / 1000f;
+ float w = (float)pos.getWidth() / 1000f;
+ float h = (float)pos.getHeight() / 1000f;
+ renderer.placeImage(x, y, w, h, xobj);
+
+ return xobj;
+ }
+
+ /** {@inheritDoc} */
+ public int getPriority() {
+ return 100;
+ }
+
+ /** {@inheritDoc} */
+ public Class getSupportedImageClass() {
+ return ImageRawCCITTFax.class;
+ }
+
+ /** {@inheritDoc} */
+ public ImageFlavor[] getSupportedImageFlavors() {
+ return FLAVORS;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java
new file mode 100644
index 000000000..58c9f1f53
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.io.IOException;
+
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG;
+
+import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFImage;
+import org.apache.fop.pdf.PDFResourceContext;
+import org.apache.fop.pdf.PDFXObject;
+import org.apache.fop.render.RendererContext;
+
+/**
+ * PDFImageHandler implementation which handles raw JPEG images.
+ */
+public class PDFImageHandlerRawJPEG implements PDFImageHandler {
+
+ private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
+ ImageFlavor.RAW_JPEG,
+ };
+
+ /** {@inheritDoc} */
+ public PDFXObject generateImage(RendererContext context, Image image,
+ Point origin, Rectangle pos)
+ throws IOException {
+ PDFRenderer renderer = (PDFRenderer)context.getRenderer();
+ ImageRawJPEG jpeg = (ImageRawJPEG)image;
+ PDFDocument pdfDoc = (PDFDocument)context.getProperty(
+ PDFRendererContextConstants.PDF_DOCUMENT);
+ PDFResourceContext resContext = (PDFResourceContext)context.getProperty(
+ PDFRendererContextConstants.PDF_CONTEXT);
+
+ PDFImage pdfimage = new ImageRawJPEGAdapter(jpeg, image.getInfo().getOriginalURI());
+ PDFXObject xobj = pdfDoc.addImage(resContext, pdfimage);
+
+ float x = (float)pos.getX() / 1000f;
+ float y = (float)pos.getY() / 1000f;
+ float w = (float)pos.getWidth() / 1000f;
+ float h = (float)pos.getHeight() / 1000f;
+ renderer.placeImage(x, y, w, h, xobj);
+
+ return xobj;
+ }
+
+ /** {@inheritDoc} */
+ public int getPriority() {
+ return 100;
+ }
+
+ /** {@inheritDoc} */
+ public Class getSupportedImageClass() {
+ return ImageRawJPEG.class;
+ }
+
+ /** {@inheritDoc} */
+ public ImageFlavor[] getSupportedImageFlavors() {
+ return FLAVORS;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java
index 36e4ea7e1..536fc19b0 100644
--- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java
+++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java
@@ -19,11 +19,17 @@
package org.apache.fop.render.pdf;
+import java.util.Comparator;
import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.util.Service;
/**
@@ -36,8 +42,23 @@ public class PDFImageHandlerRegistry {
/** the logger */
private static Log log = LogFactory.getLog(PDFImageHandlerRegistry.class);
+ private static final Comparator HANDLER_COMPARATOR = new Comparator() {
+ public int compare(Object o1, Object o2) {
+ PDFImageHandler h1 = (PDFImageHandler)o1;
+ PDFImageHandler h2 = (PDFImageHandler)o2;
+ return h1.getPriority() - h2.getPriority();
+ }
+ };
+
/** Map containing PDF image handlers for various MIME types */
private Map handlers = new java.util.HashMap();
+ /** List containing the same handlers as above but ordered by priority */
+ private List handlerList = new java.util.LinkedList();
+
+ /** Sorted Set of registered handlers */
+ private ImageFlavor[] supportedFlavors = new ImageFlavor[0];
+ private int handlerRegistrations;
+ private int lastSync;
/**
* Default constructor.
@@ -75,25 +96,74 @@ public class PDFImageHandlerRegistry {
* Add an image handler. The handler itself is inspected to find out what it supports.
* @param handler the PDFImageHandler instance
*/
- public void addHandler(PDFImageHandler handler) {
- String mime = handler.getSupportedMimeType();
- handlers.put(mime, handler);
+ public synchronized void addHandler(PDFImageHandler handler) {
+ Class imageClass = handler.getSupportedImageClass();
+ this.handlers.put(imageClass, handler);
+
+ //Sorted insert
+ ListIterator iter = this.handlerList.listIterator();
+ while (iter.hasNext()) {
+ PDFImageHandler h = (PDFImageHandler)iter.next();
+ if (HANDLER_COMPARATOR.compare(handler, h) < 0) {
+ iter.previous();
+ break;
+ }
+ }
+ iter.add(handler);
+ this.handlerRegistrations++;
}
/**
* Returns an PDFImageHandler which handles an specific image type given the MIME type
* of the image.
- * @param mime the requested MIME type
+ * @param img the Image to be handled
* @return the PDFImageHandler responsible for handling the image or null if none is available
*/
- public PDFImageHandler getHandler(String mime) {
- PDFImageHandler handler;
+ public PDFImageHandler getHandler(Image img) {
+ return getHandler(img.getClass());
+ }
- handler = (PDFImageHandler)handlers.get(mime);
+ /**
+ * Returns an PDFImageHandler which handles an specific image type given the MIME type
+ * of the image.
+ * @param imageClass the Image subclass for which to get a handler
+ * @return the PDFImageHandler responsible for handling the image or null if none is available
+ */
+ protected synchronized PDFImageHandler getHandler(Class imageClass) {
+ PDFImageHandler handler = null;
+ Class cl = imageClass;
+ while (cl != null) {
+ handler = (PDFImageHandler)handlers.get(cl);
+ if (handler != null) {
+ break;
+ }
+ cl = cl.getSuperclass();
+ }
return handler;
}
/**
+ * Returns the ordered array of supported image flavors.
+ * @return the array of image flavors
+ */
+ public synchronized ImageFlavor[] getSupportedFlavors() {
+ if (this.lastSync != this.handlerRegistrations) {
+ //Extract all ImageFlavors into a single array
+ List flavors = new java.util.ArrayList();
+ Iterator iter = this.handlerList.iterator();
+ while (iter.hasNext()) {
+ ImageFlavor[] f = ((PDFImageHandler)iter.next()).getSupportedImageFlavors();
+ for (int i = 0; i < f.length; i++) {
+ flavors.add(f[i]);
+ }
+ }
+ this.supportedFlavors = (ImageFlavor[])flavors.toArray(new ImageFlavor[flavors.size()]);
+ this.lastSync = this.handlerRegistrations;
+ }
+ return this.supportedFlavors;
+ }
+
+ /**
* Discovers PDFImageHandler implementations through the classpath and dynamically
* registers them.
*/
diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java
new file mode 100644
index 000000000..628883b9f
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.io.IOException;
+
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.impl.ImageRendered;
+
+import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFImage;
+import org.apache.fop.pdf.PDFResourceContext;
+import org.apache.fop.pdf.PDFXObject;
+import org.apache.fop.render.RendererContext;
+
+/**
+ * PDFImageHandler implementation which handles RenderedImage instances.
+ */
+public class PDFImageHandlerRenderedImage implements PDFImageHandler {
+
+ private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
+ ImageFlavor.BUFFERED_IMAGE,
+ ImageFlavor.RENDERED_IMAGE
+ };
+
+ /** {@inheritDoc} */
+ public PDFXObject generateImage(RendererContext context, Image image,
+ Point origin, Rectangle pos)
+ throws IOException {
+ PDFRenderer renderer = (PDFRenderer)context.getRenderer();
+ ImageRendered imageRend = (ImageRendered)image;
+ PDFDocument pdfDoc = (PDFDocument)context.getProperty(
+ PDFRendererContextConstants.PDF_DOCUMENT);
+ PDFResourceContext resContext = (PDFResourceContext)context.getProperty(
+ PDFRendererContextConstants.PDF_CONTEXT);
+
+ PDFImage pdfimage = new ImageRenderedAdapter(imageRend, image.getInfo().getOriginalURI());
+ PDFXObject xobj = pdfDoc.addImage(resContext, pdfimage);
+
+ float x = (float)pos.getX() / 1000f;
+ float y = (float)pos.getY() / 1000f;
+ float w = (float)pos.getWidth() / 1000f;
+ float h = (float)pos.getHeight() / 1000f;
+ renderer.placeImage(x, y, w, h, xobj);
+
+ return xobj;
+ }
+
+ /** {@inheritDoc} */
+ public int getPriority() {
+ return 300;
+ }
+
+ /** {@inheritDoc} */
+ public Class getSupportedImageClass() {
+ return ImageRendered.class;
+ }
+
+ /** {@inheritDoc} */
+ public ImageFlavor[] getSupportedImageFlavors() {
+ return FLAVORS;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerXML.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerXML.java
new file mode 100644
index 000000000..ba47cce69
--- /dev/null
+++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerXML.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.io.IOException;
+import java.util.Map;
+
+import org.w3c.dom.Document;
+
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
+
+import org.apache.fop.pdf.PDFXObject;
+import org.apache.fop.render.RendererContext;
+
+/**
+ * PDFImageHandler implementation which handles XML-based images.
+ */
+public class PDFImageHandlerXML implements PDFImageHandler {
+
+ private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
+ ImageFlavor.XML_DOM,
+ };
+
+ /** {@inheritDoc} */
+ public PDFXObject generateImage(RendererContext context, Image image,
+ Point origin, Rectangle pos)
+ throws IOException {
+ PDFRenderer renderer = (PDFRenderer)context.getRenderer();
+ ImageXMLDOM imgXML = (ImageXMLDOM)image;
+ Document doc = imgXML.getDocument();
+ String ns = imgXML.getRootNamespace();
+ Map foreignAttributes = (Map)context.getProperty(
+ PDFRendererContextConstants.FOREIGN_ATTRIBUTES);
+ renderer.renderDocument(doc, ns, pos, foreignAttributes);
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public int getPriority() {
+ return 400;
+ }
+
+ /** {@inheritDoc} */
+ public Class getSupportedImageClass() {
+ return ImageXMLDOM.class;
+ }
+
+ /** {@inheritDoc} */
+ public ImageFlavor[] getSupportedImageFlavors() {
+ return FLAVORS;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java
index f4aa5ee90..3b28cc34c 100644
--- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java
+++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java
@@ -21,6 +21,8 @@ package org.apache.fop.render.pdf;
// Java
import java.awt.Color;
+import java.awt.Point;
+import java.awt.Rectangle;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.geom.AffineTransform;
@@ -37,11 +39,13 @@ import java.util.Map;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
-import org.w3c.dom.Document;
-
import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.output.CountingOutputStream;
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+import org.apache.xmlgraphics.image.loader.util.ImageUtil;
import org.apache.xmlgraphics.xmp.Metadata;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;
@@ -68,14 +72,12 @@ import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.inline.WordArea;
+import org.apache.fop.datatypes.URISpecification;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.fo.extensions.xmp.XMPMetadata;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.Typeface;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.image.ImageFactory;
-import org.apache.fop.image.XMLImage;
import org.apache.fop.pdf.PDFAMode;
import org.apache.fop.pdf.PDFAction;
import org.apache.fop.pdf.PDFAnnotList;
@@ -1661,29 +1663,44 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
}
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public void renderImage(Image image, Rectangle2D pos) {
endTextObject();
String url = image.getURL();
- putImage(url, pos);
+ putImage(url, pos, image.getForeignAttributes());
}
/** {@inheritDoc} */
protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) {
endTextObject();
- putImage(url, pos);
+ putImage(url, pos, foreignAttributes);
}
/**
* Adds a PDF XObject (a bitmap or form) to the PDF that will later be referenced.
- * @param url URL of the bitmap
+ * @param uri URL of the bitmap
* @param pos Position of the bitmap
+ * @deprecated Use {@link @putImage(String, Rectangle2D, Map)} instead.
*/
- protected void putImage(String url, Rectangle2D pos) {
- url = ImageFactory.getURL(url);
- PDFXObject xobject = pdfDoc.getXObject(url);
+ protected void putImage(String uri, Rectangle2D pos) {
+ putImage(uri, pos, null);
+ }
+
+ /**
+ * Adds a PDF XObject (a bitmap or form) to the PDF that will later be referenced.
+ * @param uri URL of the bitmap
+ * @param pos Position of the bitmap
+ * @param foreignAttributes foreign attributes associated with the image
+ */
+ protected void putImage(String uri, Rectangle2D pos, Map foreignAttributes) {
+ Rectangle posInt = new Rectangle(
+ (int)pos.getX(),
+ (int)pos.getY(),
+ (int)pos.getWidth(),
+ (int)pos.getHeight());
+
+ uri = URISpecification.getURL(uri);
+ PDFXObject xobject = pdfDoc.getXObject(uri);
if (xobject != null) {
float w = (float) pos.getWidth() / 1000f;
float h = (float) pos.getHeight() / 1000f;
@@ -1691,79 +1708,47 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
(float)pos.getY() / 1000f, w, h, xobject);
return;
}
+ Point origin = new Point(currentIPPosition, currentBPPosition);
+ int x = origin.x + posInt.x;
+ int y = origin.y + posInt.y;
- ImageFactory fact = userAgent.getFactory().getImageFactory();
- FopImage fopimage = fact.getImage(url, userAgent);
- if (fopimage == null) {
- return;
- }
- if (!fopimage.load(FopImage.DIMENSIONS)) {
- return;
- }
- String mime = fopimage.getMimeType();
-
- //First check for a dynamically registered handler
- PDFImageHandler handler = imageHandlerRegistry.getHandler(mime);
- if (handler != null) {
- PDFXObject xobj;
- try {
- xobj = handler.generateImage(fopimage, url, pdfDoc);
- } catch (IOException ioe) {
- log.error("I/O error while handling " + mime + " image", ioe);
- return;
- }
- fact.releaseImage(url, userAgent);
+ ImageManager manager = getUserAgent().getFactory().getImageManager();
+ ImageInfo info = null;
+ try {
+ ImageSessionContext sessionContext = getUserAgent().getImageSessionContext();
+ info = manager.getImageInfo(uri, sessionContext);
- float w = (float)pos.getWidth() / 1000f;
- float h = (float)pos.getHeight() / 1000f;
- placeImage((float) pos.getX() / 1000,
- (float) pos.getY() / 1000, w, h, xobj);
- } else if ("text/xml".equals(mime)) {
- if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
- return;
- }
- Document doc = ((XMLImage) fopimage).getDocument();
- String ns = ((XMLImage) fopimage).getNameSpace();
-
- renderDocument(doc, ns, pos, null);
- } else if ("image/svg+xml".equals(mime)) {
- if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
- return;
- }
- Document doc = ((XMLImage) fopimage).getDocument();
- String ns = ((XMLImage) fopimage).getNameSpace();
-
- renderDocument(doc, ns, pos, null);
- } else if ("image/eps".equals(mime)) {
- FopPDFImage pdfimage = new FopPDFImage(fopimage, url);
- PDFXObject xobj = pdfDoc.addImage(currentContext, pdfimage);
- fact.releaseImage(url, userAgent);
- float w = (float)pos.getWidth() / 1000f;
- float h = (float)pos.getHeight() / 1000f;
- placeImage((float) pos.getX() / 1000,
- (float) pos.getY() / 1000, w, h, xobj);
- } else if ("image/jpeg".equals(mime) || "image/tiff".equals(mime)) {
- FopPDFImage pdfimage = new FopPDFImage(fopimage, url);
- PDFXObject xobj = pdfDoc.addImage(currentContext, pdfimage);
- fact.releaseImage(url, userAgent);
-
- float w = (float)pos.getWidth() / 1000f;
- float h = (float)pos.getHeight() / 1000f;
- placeImage((float) pos.getX() / 1000,
- (float) pos.getY() / 1000, w, h, xobj);
- } else {
- if (!fopimage.load(FopImage.BITMAP)) {
- return;
+
+ Map hints = ImageUtil.getDefaultHints(sessionContext);
+ org.apache.xmlgraphics.image.loader.Image img = manager.getImage(
+ info, imageHandlerRegistry.getSupportedFlavors(), hints, sessionContext);
+
+ //First check for a dynamically registered handler
+ PDFImageHandler handler = imageHandlerRegistry.getHandler(img.getClass());
+ if (handler != null) {
+ if (log.isDebugEnabled()) {
+ log.debug("Using PDFImageHandler: " + handler.getClass().getName());
+ }
+ try {
+ RendererContext context = createRendererContext(
+ x, y, posInt.width, posInt.height, foreignAttributes);
+ handler.generateImage(context, img, origin, posInt);
+ } catch (IOException ioe) {
+ log.error("I/O error while handling image: " + info, ioe);
+ return;
+ }
+ } else {
+ throw new UnsupportedOperationException(
+ "No PDFImageHandler available for image: "
+ + info + " (" + img.getClass().getName() + ")");
}
- FopPDFImage pdfimage = new FopPDFImage(fopimage, url);
- PDFXObject xobj = pdfDoc.addImage(currentContext, pdfimage);
- fact.releaseImage(url, userAgent);
-
- float w = (float) pos.getWidth() / 1000f;
- float h = (float) pos.getHeight() / 1000f;
- placeImage((float) pos.getX() / 1000f,
- (float) pos.getY() / 1000f, w, h, xobj);
+ } catch (ImageException ie) {
+ log.error("Error while processing image: "
+ + (info != null ? info.toString() : uri), ie);
+ } catch (IOException ioe) {
+ log.error("I/O error while processing image: "
+ + (info != null ? info.toString() : uri), ioe);
}
// output new data
@@ -1782,7 +1767,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
* @param h height for image
* @param xobj the image XObject
*/
- protected void placeImage(float x, float y, float w, float h, PDFXObject xobj) {
+ public void placeImage(float x, float y, float w, float h, PDFXObject xobj) {
saveGraphicsState();
currentStream.add(format(w) + " 0 0 "
+ format(-h) + " "
@@ -1792,10 +1777,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
restoreGraphicsState();
}
- /**
- * {@inheritDoc}
- * int, int, int, int, java.util.Map)
- */
+ /** {@inheritDoc} */
protected RendererContext createRendererContext(int x, int y, int width, int height,
Map foreignAttributes) {
RendererContext context = super.createRendererContext(
diff --git a/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java b/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java
index 5c5894d3b..aec094e3b 100644
--- a/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java
+++ b/src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-/* $Id: $ */
+/* $Id$ */
package org.apache.fop.render.pdf;
diff --git a/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java b/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java
index b0ae29067..cbc0a8ec9 100644
--- a/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java
+++ b/src/java/org/apache/fop/render/pdf/PDFSVGHandler.java
@@ -19,42 +19,40 @@
package org.apache.fop.render.pdf;
+import java.awt.Color;
+import java.awt.geom.AffineTransform;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
-import java.awt.Color;
-import java.awt.geom.AffineTransform;
import org.w3c.dom.Document;
-import org.apache.fop.render.AbstractGenericSVGHandler;
-import org.apache.fop.render.Renderer;
-import org.apache.fop.render.RendererContext;
-import org.apache.fop.render.RendererContextConstants;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.batik.bridge.BridgeContext;
+import org.apache.batik.bridge.GVTBuilder;
+import org.apache.batik.dom.svg.SVGDOMImplementation;
+import org.apache.batik.gvt.GraphicsNode;
+import org.apache.batik.util.SVGConstants;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.fo.extensions.ExtensionElementMapping;
+import org.apache.fop.fonts.FontInfo;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFPage;
+import org.apache.fop.pdf.PDFResourceContext;
import org.apache.fop.pdf.PDFState;
import org.apache.fop.pdf.PDFStream;
-import org.apache.fop.pdf.PDFResourceContext;
+import org.apache.fop.render.AbstractGenericSVGHandler;
+import org.apache.fop.render.Renderer;
+import org.apache.fop.render.RendererContext;
+import org.apache.fop.render.RendererContextConstants;
import org.apache.fop.svg.PDFAElementBridge;
import org.apache.fop.svg.PDFBridgeContext;
import org.apache.fop.svg.PDFGraphics2D;
import org.apache.fop.svg.SVGUserAgent;
import org.apache.fop.util.QName;
-import org.apache.fop.fo.extensions.ExtensionElementMapping;
-import org.apache.fop.fonts.FontInfo;
-
-// Commons-Logging
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.apache.avalon.framework.configuration.Configuration;
-
-import org.apache.batik.bridge.GVTBuilder;
-import org.apache.batik.bridge.BridgeContext;
-import org.apache.batik.dom.svg.SVGDOMImplementation;
-import org.apache.batik.gvt.GraphicsNode;
-import org.apache.batik.util.SVGConstants;
/**
* PDF XML handler for SVG (uses Apache Batik).
@@ -154,10 +152,15 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler
int xOffset = pdfInfo.currentXPosition;
int yOffset = pdfInfo.currentYPosition;
- final float deviceResolution = context.getUserAgent().getTargetResolution();
+ FOUserAgent userAgent = context.getUserAgent();
+ log.debug("Generating SVG at "
+ + userAgent.getTargetResolution()
+ + "dpi.");
+ final float deviceResolution = userAgent.getTargetResolution();
+ log.debug("Generating SVG at " + deviceResolution + "dpi.");
log.debug("Generating SVG at " + deviceResolution + "dpi.");
- final float uaResolution = context.getUserAgent().getSourceResolution();
+ final float uaResolution = userAgent.getSourceResolution();
SVGUserAgent ua = new SVGUserAgent(25.4f / uaResolution, new AffineTransform());
//Scale for higher resolution on-the-fly images from Batik
@@ -176,6 +179,8 @@ public class PDFSVGHandler extends AbstractGenericSVGHandler
BridgeContext ctx = new PDFBridgeContext(ua,
(strokeText ? null : pdfInfo.fi),
+ userAgent.getFactory().getImageManager(),
+ userAgent.getImageSessionContext(),
new AffineTransform());
GraphicsNode root;
diff --git a/src/java/org/apache/fop/render/ps/ImageEncoderCCITTFax.java b/src/java/org/apache/fop/render/ps/ImageEncoderCCITTFax.java
new file mode 100644
index 000000000..ab39966d4
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/ImageEncoderCCITTFax.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.ps;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.xmlgraphics.image.codec.tiff.TIFFImage;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax;
+import org.apache.xmlgraphics.ps.ImageEncoder;
+
+/**
+ * ImageEncoder implementation for CCITT encoded images.
+ */
+public class ImageEncoderCCITTFax implements ImageEncoder {
+
+ private final ImageRawCCITTFax ccitt;
+
+ /**
+ * Main constructor.
+ * @param ccitt the CCITT encoded image
+ */
+ public ImageEncoderCCITTFax(ImageRawCCITTFax ccitt) {
+ this.ccitt = ccitt;
+ }
+
+ /** {@inheritDoc} */
+ public void writeTo(OutputStream out) throws IOException {
+ ccitt.writeTo(out);
+ }
+
+ /** {@inheritDoc} */
+ public String getImplicitFilter() {
+ PSDictionary dict = new PSDictionary();
+ dict.put("/Columns", new Integer(ccitt.getSize().getWidthPx()));
+ int compression = ccitt.getCompression();
+ switch (compression) {
+ case TIFFImage.COMP_FAX_G3_1D :
+ dict.put("/K", new Integer(0));
+ break;
+ case TIFFImage.COMP_FAX_G3_2D :
+ dict.put("/K", new Integer(1));
+ break;
+ case TIFFImage.COMP_FAX_G4_2D :
+ dict.put("/K", new Integer(-1));
+ break;
+ default:
+ throw new IllegalStateException(
+ "Invalid compression scheme: " + compression);
+ }
+
+ return dict.toString() + " /CCITTFaxDecode";
+ }
+} \ No newline at end of file
diff --git a/src/java/org/apache/fop/render/ps/ImageEncoderJPEG.java b/src/java/org/apache/fop/render/ps/ImageEncoderJPEG.java
new file mode 100644
index 000000000..ef4b9f16c
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/ImageEncoderJPEG.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.ps;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG;
+import org.apache.xmlgraphics.ps.ImageEncoder;
+
+/**
+ * ImageEncoder implementation for JPEG images.
+ */
+public class ImageEncoderJPEG implements ImageEncoder {
+ private final ImageRawJPEG jpeg;
+
+ /**
+ * Main constructor
+ * @param jpeg the JPEG image
+ */
+ public ImageEncoderJPEG(ImageRawJPEG jpeg) {
+ this.jpeg = jpeg;
+ }
+
+ /** {@inheritDoc} */
+ public void writeTo(OutputStream out) throws IOException {
+ jpeg.writeTo(out);
+ }
+
+ /** {@inheritDoc} */
+ public String getImplicitFilter() {
+ return "<< >> /DCTDecode";
+ }
+} \ No newline at end of file
diff --git a/src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java b/src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java
index 286bbca80..787af69a1 100644
--- a/src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java
+++ b/src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java
@@ -24,33 +24,43 @@ import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
-import org.apache.fop.render.Graphics2DAdapter;
-import org.apache.fop.render.Graphics2DImagePainter;
-import org.apache.fop.render.RendererContext;
+import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
import org.apache.xmlgraphics.java2d.ps.PSGraphics2D;
import org.apache.xmlgraphics.ps.PSGenerator;
+import org.apache.fop.render.Graphics2DAdapter;
+import org.apache.fop.render.RendererContext;
+
/**
* Graphics2DAdapter implementation for PostScript.
*/
public class PSGraphics2DAdapter implements Graphics2DAdapter {
- private PSRenderer renderer;
+ private PSGenerator gen;
+ private boolean clip = true;
/**
* Main constructor
* @param renderer the Renderer instance to which this instance belongs
*/
public PSGraphics2DAdapter(PSRenderer renderer) {
- this.renderer = renderer;
+ this(renderer.gen, true);
+ }
+
+ /**
+ * Constructor for use without a PSRenderer instance.
+ * @param gen the PostScript generator
+ * @param clip true if the image should be clipped
+ */
+ public PSGraphics2DAdapter(PSGenerator gen, boolean clip) {
+ this.gen = gen;
+ this.clip = clip;
}
/** {@inheritDoc} */
public void paintImage(Graphics2DImagePainter painter,
RendererContext context,
int x, int y, int width, int height) throws IOException {
- PSGenerator gen = renderer.gen;
-
float fwidth = width / 1000f;
float fheight = height / 1000f;
float fx = x / 1000f;
@@ -66,10 +76,12 @@ public class PSGraphics2DAdapter implements Graphics2DAdapter {
gen.commentln("%FOPBeginGraphics2D");
gen.saveGraphicsState();
- // Clip to the image area.
- gen.writeln("newpath");
- gen.defineRect(fx, fy, fwidth, fheight);
- gen.writeln("clip");
+ if (clip) {
+ // Clip to the image area.
+ gen.writeln("newpath");
+ gen.defineRect(fx, fy, fwidth, fheight);
+ gen.writeln("clip");
+ }
// transform so that the coordinates (0,0) is from the top left
// and positive is down and to the right. (0,0) is where the
diff --git a/src/java/org/apache/fop/render/ps/PSImageUtils.java b/src/java/org/apache/fop/render/ps/PSImageUtils.java
index 0ab329077..004d5a22a 100644
--- a/src/java/org/apache/fop/render/ps/PSImageUtils.java
+++ b/src/java/org/apache/fop/render/ps/PSImageUtils.java
@@ -19,20 +19,15 @@
package org.apache.fop.render.ps;
-import java.awt.Dimension;
-import java.awt.geom.Rectangle2D;
-import java.io.IOException;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.xmlgraphics.ps.PSGenerator;
+
import org.apache.fop.image.EPSImage;
import org.apache.fop.image.FopImage;
-import org.apache.fop.image.JpegImage;
-import org.apache.xmlgraphics.ps.PSGenerator;
-import org.apache.xmlgraphics.ps.PSResource;
/**
- * Utility code for rendering images in PostScript.
+ * Utility code for rendering images in PostScript.
*/
public class PSImageUtils extends org.apache.xmlgraphics.ps.PSImageUtils {
@@ -40,93 +35,6 @@ public class PSImageUtils extends org.apache.xmlgraphics.ps.PSImageUtils {
protected static Log log = LogFactory.getLog(PSImageUtils.class);
/**
- * Renders a bitmap image to PostScript.
- * @param img image to render
- * @param x x position
- * @param y y position
- * @param w width
- * @param h height
- * @param gen PS generator
- * @throws IOException In case of an I/O problem while rendering the image
- */
- public static void renderBitmapImage(FopImage img,
- float x, float y, float w, float h, PSGenerator gen)
- throws IOException {
- boolean isJPEG = (img instanceof JpegImage && (gen.getPSLevel() >= 3));
- byte[] imgmap = convertImageToRawBitmapArray(img, isJPEG);
- if (imgmap == null) {
- gen.commentln("%Image data is not available: " + img);
- return; //Image cannot be converted
- }
-
- String imgDescription = img.getMimeType() + " " + img.getOriginalURI();
- Dimension imgDim = new Dimension(img.getWidth(), img.getHeight());
- Rectangle2D targetRect = new Rectangle2D.Double(x, y, w, h);
- writeImage(imgmap, imgDim, imgDescription, targetRect, isJPEG,
- img.getColorSpace(), gen);
- }
-
- /**
- * Renders a bitmap image (as form) to PostScript.
- * @param img image to render
- * @param form the form resource
- * @param x x position
- * @param y y position
- * @param w width
- * @param h height
- * @param gen PS generator
- * @throws IOException In case of an I/O problem while rendering the image
- */
- public static void renderForm(FopImage img, PSResource form,
- float x, float y, float w, float h, PSGenerator gen)
- throws IOException {
- Rectangle2D targetRect = new Rectangle2D.Double(x, y, w, h);
- paintForm(form, targetRect, gen);
- }
-
- /**
- * Generates a form resource for a FopImage in PostScript.
- * @param img image to render
- * @param form the form resource
- * @param gen PS generator
- * @throws IOException In case of an I/O problem while rendering the image
- */
- public static void generateFormResourceForImage(FopImage img, PSResource form,
- PSGenerator gen) throws IOException {
- boolean isJPEG = (img instanceof JpegImage && (gen.getPSLevel() >= 3));
- byte[] imgmap = convertImageToRawBitmapArray(img, isJPEG);
- if (imgmap == null) {
- gen.commentln("%Image data is not available: " + img);
- return; //Image cannot be converted
- }
-
- String imgDescription = img.getMimeType() + " " + img.getOriginalURI();
- Dimension imgDim = new Dimension(img.getWidth(), img.getHeight());
- writeReusableImage(imgmap, imgDim, form.getName(), imgDescription, isJPEG,
- img.getColorSpace(), gen);
- }
-
- private static byte[] convertImageToRawBitmapArray(FopImage img, boolean allowUndecodedJPEG)
- throws IOException {
- if (img instanceof JpegImage && allowUndecodedJPEG) {
- if (!img.load(FopImage.ORIGINAL_DATA)) {
- return null;
- }
- } else {
- if (!img.load(FopImage.BITMAP)) {
- return null;
- }
- }
- byte[] imgmap;
- if (img.getBitmapsSize() > 0) {
- imgmap = img.getBitmaps();
- } else {
- imgmap = img.getRessourceBytes();
- }
- return imgmap;
- }
-
- /**
* Renders an EPS image to PostScript.
* @param img EPS image to render
* @param x x position
@@ -134,6 +42,8 @@ public class PSImageUtils extends org.apache.xmlgraphics.ps.PSImageUtils {
* @param w width
* @param h height
* @param gen PS generator
+ * @deprecated Use {@link #renderEPS(java.io.InputStream, String, java.awt.geom.Rectangle2D,
+ * java.awt.geom.Rectangle2D, PSGenerator)} instead
*/
public static void renderEPS(EPSImage img,
float x, float y, float w, float h,
diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java
index 7580bd0d5..21ae85259 100644
--- a/src/java/org/apache/fop/render/ps/PSRenderer.java
+++ b/src/java/org/apache/fop/render/ps/PSRenderer.java
@@ -24,6 +24,7 @@ import java.awt.Color;
import java.awt.geom.Rectangle2D;
import java.awt.image.RenderedImage;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.LineNumberReader;
@@ -35,14 +36,28 @@ import java.util.Map;
import javax.xml.transform.Source;
-import org.w3c.dom.Document;
-
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawEPS;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawStream;
+import org.apache.xmlgraphics.image.loader.impl.ImageRendered;
+import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
+import org.apache.xmlgraphics.image.loader.pipeline.ImageProviderPipeline;
+import org.apache.xmlgraphics.image.loader.util.ImageUtil;
import org.apache.xmlgraphics.ps.DSCConstants;
+import org.apache.xmlgraphics.ps.ImageEncoder;
import org.apache.xmlgraphics.ps.PSGenerator;
+import org.apache.xmlgraphics.ps.PSImageUtils;
import org.apache.xmlgraphics.ps.PSProcSets;
import org.apache.xmlgraphics.ps.PSResource;
import org.apache.xmlgraphics.ps.PSState;
@@ -69,15 +84,12 @@ import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.inline.WordArea;
+import org.apache.fop.datatypes.URISpecification;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.LazyFont;
import org.apache.fop.fonts.Typeface;
-import org.apache.fop.image.EPSImage;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.image.ImageFactory;
-import org.apache.fop.image.XMLImage;
import org.apache.fop.render.AbstractPathOrientedRenderer;
import org.apache.fop.render.Graphics2DAdapter;
import org.apache.fop.render.ImageAdapter;
@@ -108,7 +120,8 @@ import org.apache.fop.util.CharUtilities;
* @author <a href="mailto:fop-dev@xmlgraphics.apache.org">Apache FOP Development Team</a>
* @version $Id$
*/
-public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAdapter {
+public class PSRenderer extends AbstractPathOrientedRenderer
+ implements ImageAdapter, PSSupportedFlavors {
/** logging instance */
private static Log log = LogFactory.getLog(PSRenderer.class);
@@ -377,58 +390,183 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda
}
}
+ /**
+ * Indicates whether an image should be inlined or added as a PostScript form.
+ * @param uri the URI of the image
+ * @return true if the image should be inlined rather than added as a form
+ */
+ protected boolean isImageInlined(String uri) {
+ return !isOptimizeResources() || uri == null || "".equals(uri);
+ }
+
+ /**
+ * Indicates whether an image should be inlined or added as a PostScript form.
+ * @param info the ImageInfo object of the image
+ * @return true if the image should be inlined rather than added as a form
+ */
+ protected boolean isImageInlined(ImageInfo info) {
+ if (isImageInlined(info.getOriginalURI())) {
+ return true;
+ }
+
+ if (!isOptimizeResources()) {
+ throw new IllegalStateException("Must not get here if form support is enabled");
+ }
+
+ //Investigate choice for inline mode
+ ImageFlavor[] inlineFlavors = getInlineFlavors();
+ ImageManager manager = getUserAgent().getFactory().getImageManager();
+ ImageProviderPipeline[] inlineCandidates
+ = manager.getPipelineFactory().determineCandidatePipelines(
+ info, inlineFlavors);
+ ImageProviderPipeline inlineChoice = manager.choosePipeline(inlineCandidates);
+ ImageFlavor inlineFlavor = (inlineChoice != null ? inlineChoice.getTargetFlavor() : null);
+
+ //Investigate choice for form mode
+ ImageFlavor[] formFlavors = getFormFlavors();
+ ImageProviderPipeline[] formCandidates
+ = manager.getPipelineFactory().determineCandidatePipelines(
+ info, formFlavors);
+ ImageProviderPipeline formChoice = manager.choosePipeline(formCandidates);
+ ImageFlavor formFlavor = (formChoice != null ? formChoice.getTargetFlavor() : null);
+
+ //Inline if form is not supported or if a better choice is available with inline mode
+ return formFlavor == null || !formFlavor.equals(inlineFlavor);
+ }
+
/** {@inheritDoc} */
protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) {
endTextObject();
- uri = ImageFactory.getURL(uri);
- ImageFactory fact = userAgent.getFactory().getImageFactory();
- FopImage fopimage = fact.getImage(uri, userAgent);
- if (fopimage == null) {
- return;
- }
- if (!fopimage.load(FopImage.DIMENSIONS)) {
- return;
+ int x = currentIPPosition + (int)Math.round(pos.getX());
+ int y = currentBPPosition + (int)Math.round(pos.getY());
+ uri = URISpecification.getURL(uri);
+ if (log.isDebugEnabled()) {
+ log.debug("Handling image: " + uri);
}
- float x = (float)pos.getX() / 1000f;
- x += currentIPPosition / 1000f;
- float y = (float)pos.getY() / 1000f;
- y += currentBPPosition / 1000f;
- float w = (float)pos.getWidth() / 1000f;
- float h = (float)pos.getHeight() / 1000f;
+
+ ImageManager manager = getUserAgent().getFactory().getImageManager();
+ ImageInfo info = null;
try {
- String mime = fopimage.getMimeType();
- if ("text/xml".equals(mime)) {
- if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
- return;
+ ImageSessionContext sessionContext = getUserAgent().getImageSessionContext();
+ info = manager.getImageInfo(uri, sessionContext);
+ int width = (int)pos.getWidth();
+ int height = (int)pos.getHeight();
+
+ //millipoints --> points for PostScript
+ float ptx = x / 1000f;
+ float pty = y / 1000f;
+ float ptw = width / 1000f;
+ float pth = height / 1000f;
+
+ if (isImageInlined(info)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Image " + info + " is inlined");
}
- Document doc = ((XMLImage) fopimage).getDocument();
- String ns = ((XMLImage) fopimage).getNameSpace();
-
- renderDocument(doc, ns, pos, foreignAttributes);
- } else if ("image/svg+xml".equals(mime)) {
- if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
- return;
+ //Only now fully load/prepare the image
+ Map hints = ImageUtil.getDefaultHints(sessionContext);
+ org.apache.xmlgraphics.image.loader.Image img = manager.getImage(
+ info, getInlineFlavors(), hints, sessionContext);
+
+ //...and embed as inline image
+ if (img instanceof ImageGraphics2D) {
+ ImageGraphics2D imageG2D = (ImageGraphics2D)img;
+ RendererContext context = createRendererContext(
+ x, y, width, height, foreignAttributes);
+ getGraphics2DAdapter().paintImage(imageG2D.getGraphics2DImagePainter(),
+ context, x, y, width, height);
+ } else if (img instanceof ImageRendered) {
+ ImageRendered imgRend = (ImageRendered)img;
+ RenderedImage ri = imgRend.getRenderedImage();
+ PSImageUtils.renderBitmapImage(ri, ptx, pty, ptw, pth, gen);
+ } else if (img instanceof ImageXMLDOM) {
+ ImageXMLDOM imgXML = (ImageXMLDOM)img;
+ renderDocument(imgXML.getDocument(), imgXML.getRootNamespace(),
+ pos, foreignAttributes);
+ } else if (img instanceof ImageRawStream) {
+ final ImageRawStream raw = (ImageRawStream)img;
+ if (raw instanceof ImageRawEPS) {
+ ImageRawEPS eps = (ImageRawEPS)raw;
+ Rectangle2D bbox = eps.getBoundingBox();
+ InputStream in = raw.createInputStream();
+ try {
+ PSImageUtils.renderEPS(in, uri,
+ new Rectangle2D.Float(ptx, pty, ptw, pth),
+ bbox,
+ gen);
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ } else if (raw instanceof ImageRawCCITTFax) {
+ final ImageRawCCITTFax ccitt = (ImageRawCCITTFax)raw;
+ ImageEncoder encoder = new ImageEncoderCCITTFax(ccitt);
+ Rectangle2D targetRect = new Rectangle2D.Float(
+ ptx, pty, ptw, pth);
+ PSImageUtils.writeImage(encoder, info.getSize().getDimensionPx(),
+ uri, targetRect,
+ ccitt.getColorSpace(), 1, false, gen);
+ } else if (raw instanceof ImageRawJPEG) {
+ ImageRawJPEG jpeg = (ImageRawJPEG)raw;
+ ImageEncoder encoder = new ImageEncoderJPEG(jpeg);
+ Rectangle2D targetRect = new Rectangle2D.Float(
+ ptx, pty, ptw, pth);
+ PSImageUtils.writeImage(encoder, info.getSize().getDimensionPx(),
+ uri, targetRect,
+ jpeg.getColorSpace(), 8, jpeg.isInverted(), gen);
+ } else {
+ throw new UnsupportedOperationException("Unsupported raw image: " + info);
+ }
+ } else {
+ throw new UnsupportedOperationException("Unsupported image type: " + img);
}
- Document doc = ((XMLImage) fopimage).getDocument();
- String ns = ((XMLImage) fopimage).getNameSpace();
-
- renderDocument(doc, ns, pos, foreignAttributes);
- } else if (fopimage instanceof EPSImage) {
- PSImageUtils.renderEPS((EPSImage)fopimage, x, y, w, h, gen);
} else {
- if (isImageInlined(uri, fopimage)) {
- PSImageUtils.renderBitmapImage(fopimage, x, y, w, h, gen);
- } else {
- PSResource form = getFormForImage(uri, fopimage);
- PSImageUtils.renderForm(fopimage, form, x, y, w, h, gen);
+ if (log.isDebugEnabled()) {
+ log.debug("Image " + info + " is embedded as a form later");
}
+ //Don't load image at this time, just put a form placeholder in the stream
+ PSResource form = getFormForImage(uri);
+ Rectangle2D targetRect = new Rectangle2D.Double(ptx, pty, ptw, pth);
+ PSImageUtils.paintForm(form, info.getSize().getDimensionPt(), targetRect, gen);
}
+
+ } catch (ImageException ie) {
+ log.error("Error while processing image: "
+ + (info != null ? info.toString() : uri), ie);
+ } catch (FileNotFoundException fe) {
+ log.error(fe.getMessage());
} catch (IOException ioe) {
handleIOTrouble(ioe);
}
}
- protected PSResource getFormForImage(String uri, FopImage fopimage) {
+ private ImageFlavor[] getInlineFlavors() {
+ ImageFlavor[] flavors;
+ if (gen.getPSLevel() >= 3) {
+ flavors = LEVEL_3_FLAVORS_INLINE;
+ } else {
+ flavors = LEVEL_2_FLAVORS_INLINE;
+ }
+ return flavors;
+ }
+
+ private ImageFlavor[] getFormFlavors() {
+ ImageFlavor[] flavors;
+ if (gen.getPSLevel() >= 3) {
+ flavors = LEVEL_3_FLAVORS_FORM;
+ } else {
+ flavors = LEVEL_2_FLAVORS_FORM;
+ }
+ return flavors;
+ }
+
+ /**
+ * Returns a PSResource instance representing a image as a PostScript form.
+ * @param uri the image URI
+ * @return a PSResource instance
+ */
+ protected PSResource getFormForImage(String uri) {
+ if (uri == null || "".equals(uri)) {
+ throw new IllegalArgumentException("uri must not be empty or null");
+ }
if (this.formResources == null) {
this.formResources = new java.util.HashMap();
}
@@ -439,11 +577,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda
}
return form;
}
-
- protected boolean isImageInlined(String uri, FopImage image) {
- return !isOptimizeResources();
- }
-
+
/** {@inheritDoc} */
public void paintImage(RenderedImage image, RendererContext context,
int x, int y, int width, int height) throws IOException {
diff --git a/src/java/org/apache/fop/render/ps/PSSupportedFlavors.java b/src/java/org/apache/fop/render/ps/PSSupportedFlavors.java
new file mode 100644
index 000000000..8ccfa8e26
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSSupportedFlavors.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.ps;
+
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+
+/**
+ * Defines the set of supported ImageFlavors for the PostScript renderer.
+ */
+public interface PSSupportedFlavors {
+
+ /** The flavors supported inline with PostScript level 2. */
+ ImageFlavor[] LEVEL_2_FLAVORS_INLINE = new ImageFlavor[]
+ {ImageFlavor.RAW_EPS,
+ ImageFlavor.RAW_CCITTFAX,
+ ImageFlavor.GRAPHICS2D,
+ ImageFlavor.BUFFERED_IMAGE,
+ ImageFlavor.RENDERED_IMAGE,
+ ImageFlavor.XML_DOM};
+
+ /** The flavors supported inline with PostScript level 3 and higher. */
+ ImageFlavor[] LEVEL_3_FLAVORS_INLINE = new ImageFlavor[]
+ {ImageFlavor.RAW_EPS,
+ ImageFlavor.RAW_JPEG,
+ ImageFlavor.RAW_CCITTFAX,
+ ImageFlavor.GRAPHICS2D,
+ ImageFlavor.BUFFERED_IMAGE,
+ ImageFlavor.RENDERED_IMAGE,
+ ImageFlavor.XML_DOM};
+
+ /** The flavors supported as forms with PostScript level 2. */
+ ImageFlavor[] LEVEL_2_FLAVORS_FORM = new ImageFlavor[]
+ {//ImageFlavor.RAW_EPS,
+ ImageFlavor.RAW_CCITTFAX,
+ ImageFlavor.GRAPHICS2D,
+ ImageFlavor.BUFFERED_IMAGE,
+ ImageFlavor.RENDERED_IMAGE/*,
+ ImageFlavor.XML_DOM*/};
+
+ /** The flavors supported as forms with PostScript level 3 or higher. */
+ ImageFlavor[] LEVEL_3_FLAVORS_FORM = new ImageFlavor[]
+ {//ImageFlavor.RAW_EPS,
+ ImageFlavor.RAW_JPEG,
+ ImageFlavor.RAW_CCITTFAX,
+ ImageFlavor.GRAPHICS2D,
+ ImageFlavor.BUFFERED_IMAGE,
+ ImageFlavor.RENDERED_IMAGE/*,
+ ImageFlavor.XML_DOM*/};
+
+}
diff --git a/src/java/org/apache/fop/render/ps/ResourceHandler.java b/src/java/org/apache/fop/render/ps/ResourceHandler.java
index a0762e6e0..0dfb8029f 100644
--- a/src/java/org/apache/fop/render/ps/ResourceHandler.java
+++ b/src/java/org/apache/fop/render/ps/ResourceHandler.java
@@ -19,6 +19,8 @@
package org.apache.fop.render.ps;
+import java.awt.geom.Dimension2D;
+import java.awt.image.RenderedImage;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.InputStream;
@@ -27,8 +29,25 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Set;
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawEPS;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawStream;
+import org.apache.xmlgraphics.image.loader.impl.ImageRendered;
+import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
+import org.apache.xmlgraphics.image.loader.util.ImageUtil;
import org.apache.xmlgraphics.ps.DSCConstants;
+import org.apache.xmlgraphics.ps.FormGenerator;
+import org.apache.xmlgraphics.ps.ImageEncoder;
+import org.apache.xmlgraphics.ps.ImageFormGenerator;
import org.apache.xmlgraphics.ps.PSGenerator;
+import org.apache.xmlgraphics.ps.PSProcSets;
import org.apache.xmlgraphics.ps.dsc.DSCException;
import org.apache.xmlgraphics.ps.dsc.DSCFilter;
import org.apache.xmlgraphics.ps.dsc.DSCParser;
@@ -50,8 +69,6 @@ import org.apache.xmlgraphics.ps.dsc.tools.DSCTools;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fonts.FontInfo;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.image.ImageFactory;
/**
* This class is used when two-pass production is used to generate the PostScript file (setting
@@ -59,7 +76,7 @@ import org.apache.fop.image.ImageFactory;
* temporary file generated by the PSRenderer and adds all used fonts and images as resources
* to the PostScript file.
*/
-public class ResourceHandler implements DSCParserConstants {
+public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors {
/**
* Rewrites the temporary PostScript file generated by PSRenderer adding all needed resources
@@ -208,13 +225,129 @@ public class ResourceHandler implements DSCParserConstants {
Iterator iter = formResources.values().iterator();
while (iter.hasNext()) {
PSImageFormResource form = (PSImageFormResource)iter.next();
- ImageFactory fact = userAgent.getFactory().getImageFactory();
- FopImage image = fact.getImage(form.getImageURI(), userAgent);
- if (image == null) {
- throw new NullPointerException("Image not found: " + form.getImageURI());
+ final String uri = form.getImageURI();
+
+ ImageManager manager = userAgent.getFactory().getImageManager();
+ ImageInfo info = null;
+ try {
+ ImageSessionContext sessionContext = userAgent.getImageSessionContext();
+ info = manager.getImageInfo(uri, sessionContext);
+
+ ImageFlavor[] flavors;
+ if (gen.getPSLevel() >= 3) {
+ flavors = LEVEL_3_FLAVORS_FORM;
+ } else {
+ flavors = LEVEL_2_FLAVORS_FORM;
+ }
+ Map hints = ImageUtil.getDefaultHints(sessionContext);
+ org.apache.xmlgraphics.image.loader.Image img = manager.getImage(
+ info, flavors, hints, sessionContext);
+
+ String imageDescription = info.getMimeType() + " " + info.getOriginalURI();
+ final Dimension2D dimensionsPt = info.getSize().getDimensionPt();
+ final Dimension2D dimensionsMpt = info.getSize().getDimensionMpt();
+
+ if (img instanceof ImageGraphics2D) {
+ final ImageGraphics2D imageG2D = (ImageGraphics2D)img;
+ FormGenerator formGen = new FormGenerator(
+ form.getName(), imageDescription, dimensionsPt) {
+
+ protected void generatePaintProc(PSGenerator gen)
+ throws IOException {
+ gen.getResourceTracker().notifyResourceUsageOnPage(
+ PSProcSets.EPS_PROCSET);
+ gen.writeln("BeginEPSF");
+ PSGraphics2DAdapter adapter = new PSGraphics2DAdapter(gen, false);
+ adapter.paintImage(imageG2D.getGraphics2DImagePainter(),
+ null,
+ 0, 0,
+ (int)Math.round(dimensionsMpt.getWidth()),
+ (int)Math.round(dimensionsMpt.getHeight()));
+ gen.writeln("EndEPSF");
+ }
+
+ };
+ formGen.generate(gen);
+ } else if (img instanceof ImageRendered) {
+ ImageRendered imgRend = (ImageRendered)img;
+ RenderedImage ri = imgRend.getRenderedImage();
+ FormGenerator formGen = new ImageFormGenerator(
+ form.getName(), imageDescription,
+ info.getSize().getDimensionPt(),
+ ri, false);
+ formGen.generate(gen);
+ } else if (img instanceof ImageXMLDOM) {
+ throw new UnsupportedOperationException(
+ "Embedding an ImageXMLDOM as a form isn't supported, yet");
+ } else if (img instanceof ImageRawStream) {
+ final ImageRawStream raw = (ImageRawStream)img;
+ if (raw instanceof ImageRawEPS) {
+ final ImageRawEPS eps = (ImageRawEPS)raw;
+ throw new UnsupportedOperationException(
+ "Embedding EPS as forms isn't supported, yet");
+ /*
+ InputStream in = eps.createInputStream();
+ try {
+ FormGenerator formGen = new EPSFormGenerator(form.getName(),
+ imageDescription, dimensions, in);
+ formGen.generate(gen);
+ } finally {
+ IOUtils.closeQuietly(in);
+ }*/
+ } else if (raw instanceof ImageRawCCITTFax) {
+ ImageRawCCITTFax jpeg = (ImageRawCCITTFax)raw;
+ ImageEncoder encoder = new ImageEncoderCCITTFax(jpeg);
+ FormGenerator formGen = new ImageFormGenerator(
+ form.getName(), imageDescription,
+ info.getSize().getDimensionPt(),
+ info.getSize().getDimensionPx(),
+ encoder,
+ jpeg.getColorSpace(), 1, false);
+ formGen.generate(gen);
+ } else if (raw instanceof ImageRawJPEG) {
+ ImageRawJPEG jpeg = (ImageRawJPEG)raw;
+ ImageEncoder encoder = new ImageEncoderJPEG(jpeg);
+ FormGenerator formGen = new ImageFormGenerator(
+ form.getName(), imageDescription,
+ info.getSize().getDimensionPt(),
+ info.getSize().getDimensionPx(),
+ encoder,
+ jpeg.getColorSpace(), jpeg.isInverted());
+ formGen.generate(gen);
+ } else {
+ throw new UnsupportedOperationException("Unsupported raw image: " + info);
+ }
+ } else {
+ throw new UnsupportedOperationException("Unsupported image type: " + img);
+ }
+ } catch (ImageException ie) {
+ throw new IOException("Error while generating form for image: " + ie.getMessage());
}
- PSImageUtils.generateFormResourceForImage(image, form, gen);
}
}
+ private static FormGenerator createMissingForm(String formName, final Dimension2D dimensions) {
+ FormGenerator formGen = new FormGenerator(formName, null, dimensions) {
+
+ protected void generatePaintProc(PSGenerator gen) throws IOException {
+ gen.writeln("0 setgray");
+ gen.writeln("0 setlinewidth");
+ String w = gen.formatDouble(dimensions.getWidth());
+ String h = gen.formatDouble(dimensions.getHeight());
+ gen.writeln(w + " " + h + " scale");
+ gen.writeln("0 0 1 1 rectstroke");
+ gen.writeln("newpath");
+ gen.writeln("0 0 moveto");
+ gen.writeln("1 1 lineto");
+ gen.writeln("stroke");
+ gen.writeln("newpath");
+ gen.writeln("0 1 moveto");
+ gen.writeln("1 0 lineto");
+ gen.writeln("stroke");
+ }
+
+ };
+ return formGen;
+ }
+
}
diff --git a/src/java/org/apache/fop/render/rtf/RTFHandler.java b/src/java/org/apache/fop/render/rtf/RTFHandler.java
index eb50a3ea7..333e4ab95 100644
--- a/src/java/org/apache/fop/render/rtf/RTFHandler.java
+++ b/src/java/org/apache/fop/render/rtf/RTFHandler.java
@@ -20,26 +20,33 @@
package org.apache.fop.render.rtf;
// Java
-import java.awt.color.ColorSpace;
import java.awt.geom.Point2D;
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorModel;
-import java.awt.image.ComponentColorModel;
-import java.awt.image.DataBuffer;
-import java.awt.image.DataBufferByte;
-import java.awt.image.PixelInterleavedSampleModel;
-import java.awt.image.Raster;
-import java.awt.image.SampleModel;
-import java.awt.image.WritableRaster;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Iterator;
+import java.util.Map;
-import org.apache.batik.dom.svg.SVGDOMImplementation;
-import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.w3c.dom.Document;
+
+import org.xml.sax.SAXException;
+
+import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+import org.apache.xmlgraphics.image.loader.ImageSize;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawStream;
+import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
+import org.apache.xmlgraphics.image.loader.util.ImageUtil;
+
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.datatypes.LengthBase;
@@ -79,9 +86,6 @@ import org.apache.fop.fo.pagination.SimplePageMaster;
import org.apache.fop.fo.pagination.StaticContent;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fonts.FontSetup;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.image.ImageFactory;
-import org.apache.fop.image.XMLImage;
import org.apache.fop.render.DefaultFontResolver;
import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfAfterContainer;
import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfBeforeContainer;
@@ -108,10 +112,6 @@ import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTextrun;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfListItem.RtfListItemLabel;
import org.apache.fop.render.rtf.rtflib.tools.BuilderContext;
import org.apache.fop.render.rtf.rtflib.tools.TableContext;
-import org.apache.xmlgraphics.image.writer.ImageWriter;
-import org.apache.xmlgraphics.image.writer.ImageWriterRegistry;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
/**
* RTF Handler: generates RTF output using the structure events from
@@ -1104,24 +1104,18 @@ public class RTFHandler extends FOEventHandler {
}
try {
- String url = eg.getURL();
+ String uri = eg.getURL();
//set image data
FOUserAgent userAgent = eg.getUserAgent();
- ImageFactory fact = userAgent.getFactory().getImageFactory();
- FopImage fopimage = fact.getImage(url, userAgent);
- if (fopimage == null) {
- log.error("Image could not be found: " + url);
+ ImageManager manager = userAgent.getFactory().getImageManager();
+ ImageInfo info = manager.getImageInfo(uri, userAgent.getImageSessionContext());
+ if (info == null) {
+ log.error("Image could not be found: " + uri);
return;
}
- if ("image/gif".equals(fopimage.getMimeType())) {
- //GIF is not directly supported by RTF, so it must be converted to PNG
- fopimage.load(FopImage.BITMAP);
- } else {
- fopimage.load(FopImage.ORIGINAL_DATA);
- }
- putGraphic(eg, fopimage);
+ putGraphic(eg, info);
} catch (Exception e) {
log.error("Error while handling an external-graphic: " + e.getMessage(), e);
}
@@ -1140,85 +1134,83 @@ public class RTFHandler extends FOEventHandler {
Document doc = child.getDOMDocument();
String ns = child.getNamespaceURI();
- if (SVGDOMImplementation.SVG_NAMESPACE_URI.equals(ns)) {
- // Build the image info.
- FopImage.ImageInfo info = new FopImage.ImageInfo();
- info.mimeType = "image/svg+xml";
- info.str = SVGDOMImplementation.SVG_NAMESPACE_URI;
- info.originalURI = "";
- info.data = doc;
-
- // Set the resolution to that of the FOUserAgent
- FOUserAgent ua = ifo.getUserAgent();
- info.dpiHorizontal = 25.4f / ua.getSourcePixelUnitToMillimeter();
- info.dpiVertical = info.dpiHorizontal;
-
- // Set the image size to the size of the svg.
- Point2D csize = new Point2D.Float(-1, -1);
- Point2D intrinsicDimensions = child.getDimension(csize);
- info.width = (int) intrinsicDimensions.getX();
- info.height = (int) intrinsicDimensions.getY();
-
- FopImage fopImage = new XMLImage(info);
- fopImage.load(FopImage.ORIGINAL_DATA);
-
- putGraphic(ifo, fopImage);
- } else {
- log.warn("The namespace " + ns
- + " for instream-foreign-objects is not supported.");
- }
+ ImageInfo info = new ImageInfo(null, null);
+ // Set the resolution to that of the FOUserAgent
+ FOUserAgent ua = ifo.getUserAgent();
+ ImageSize size = new ImageSize();
+ size.setResolution(ua.getSourceResolution());
+
+ // Set the image size to the size of the svg.
+ Point2D csize = new Point2D.Float(-1, -1);
+ Point2D intrinsicDimensions = child.getDimension(csize);
+ size.setSizeInMillipoints(
+ (int)Math.round(intrinsicDimensions.getX() * 1000),
+ (int)Math.round(intrinsicDimensions.getY() * 1000));
+ size.calcPixelsFromSize();
+ info.setSize(size);
+
+ ImageXMLDOM image = new ImageXMLDOM(info, doc, ns);
+ FOUserAgent userAgent = ifo.getUserAgent();
+ ImageManager manager = userAgent.getFactory().getImageManager();
+ Image converted = manager.convertImage(image, FLAVORS);
+ putGraphic(ifo, converted);
} catch (Exception e) {
log.error("Error while handling an instream-foreign-object: " + e.getMessage(), e);
}
}
- private BufferedImage createBufferedImageFromBitmaps(FopImage image) {
- // TODO Hardcoded color and sample models, FIX ME!
- ColorModel cm = new ComponentColorModel(
- ColorSpace.getInstance(ColorSpace.CS_sRGB),
- new int[] {8, 8, 8},
- false, false,
- ColorModel.OPAQUE, DataBuffer.TYPE_BYTE);
- SampleModel sampleModel = new PixelInterleavedSampleModel(
- DataBuffer.TYPE_BYTE, image.getWidth(), image.getHeight(), 3, image.getWidth() * 3,
- new int[] {0, 1, 2});
- DataBuffer dbuf = new DataBufferByte(image.getBitmaps(),
- image.getWidth() * image.getHeight() * 3);
-
- WritableRaster raster = Raster.createWritableRaster(sampleModel,
- dbuf, null);
-
- // Combine the color model and raster into a buffered image
- return new BufferedImage(cm, raster, false, null);
+ private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
+ ImageFlavor.RAW_EMF, ImageFlavor.RAW_PNG, ImageFlavor.RAW_JPEG
+ };
+
+ /**
+ * Puts a graphic/image into the generated RTF file.
+ * @param abstractGraphic the graphic (external-graphic or instream-foreign-object)
+ * @param info the image info object
+ * @throws IOException In case of an I/O error
+ */
+ private void putGraphic(AbstractGraphics abstractGraphic, ImageInfo info)
+ throws IOException {
+ try {
+ FOUserAgent userAgent = abstractGraphic.getUserAgent();
+ ImageManager manager = userAgent.getFactory().getImageManager();
+ ImageSessionContext sessionContext = userAgent.getImageSessionContext();
+ Map hints = ImageUtil.getDefaultHints(sessionContext);
+ Image image = manager.getImage(info, FLAVORS, hints, sessionContext);
+
+ putGraphic(abstractGraphic, image);
+ } catch (ImageException ie) {
+ log.error("Error while loading/processing image: " + info.getOriginalURI(), ie);
+ }
}
/**
* Puts a graphic/image into the generated RTF file.
* @param abstractGraphic the graphic (external-graphic or instream-foreign-object)
- * @param fopImage the image
+ * @param image the image
* @throws IOException In case of an I/O error
*/
- private void putGraphic(AbstractGraphics abstractGraphic, FopImage fopImage)
+ private void putGraphic(AbstractGraphics abstractGraphic, Image image)
throws IOException {
- byte[] rawData;
- if ("image/svg+xml".equals(fopImage.getMimeType())) {
- rawData = SVGConverter.convertToJPEG((XMLImage) fopImage);
- } else if (fopImage.getRessourceBytes() != null) {
- rawData = fopImage.getRessourceBytes();
- } else {
- //TODO Revisit after the image library redesign!!!
- //Convert the decoded bitmaps to a BufferedImage
- BufferedImage bufImage = createBufferedImageFromBitmaps(fopImage);
- ImageWriter writer = ImageWriterRegistry.getInstance().getWriterFor("image/png");
- ByteArrayOutputStream baout = new ByteArrayOutputStream();
- writer.writeImage(bufImage, baout);
- rawData = baout.toByteArray();
+ byte[] rawData = null;
+
+ ImageInfo info = image.getInfo();
+
+ if (image instanceof ImageRawStream) {
+ ImageRawStream rawImage = (ImageRawStream)image;
+ InputStream in = rawImage.createInputStream();
+ try {
+ rawData = IOUtils.toByteArray(in);
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
}
+
if (rawData == null) {
log.warn(FONode.decorateWithContextInfo("Image could not be embedded: "
- + fopImage.getOriginalURI(), abstractGraphic));
+ + image, abstractGraphic));
return;
}
@@ -1229,7 +1221,9 @@ public class RTFHandler extends FOEventHandler {
final RtfExternalGraphic rtfGraphic = c.getTextrun().newImage();
//set URL
- rtfGraphic.setURL(fopImage.getOriginalURI());
+ if (info.getOriginalURI() != null) {
+ rtfGraphic.setURL(info.getOriginalURI());
+ }
rtfGraphic.setImageData(rawData);
//set scaling
@@ -1240,7 +1234,7 @@ public class RTFHandler extends FOEventHandler {
//get width
int width = 0;
if (abstractGraphic.getWidth().getEnum() == Constants.EN_AUTO) {
- width = fopImage.getIntrinsicWidth();
+ width = info.getSize().getWidthMpt();
} else {
width = abstractGraphic.getWidth().getValue();
}
@@ -1248,7 +1242,7 @@ public class RTFHandler extends FOEventHandler {
//get height
int height = 0;
if (abstractGraphic.getWidth().getEnum() == Constants.EN_AUTO) {
- height = fopImage.getIntrinsicHeight();
+ height = info.getSize().getHeightMpt();
} else {
height = abstractGraphic.getHeight().getValue();
}
@@ -1257,7 +1251,7 @@ public class RTFHandler extends FOEventHandler {
int contentwidth = 0;
if (abstractGraphic.getContentWidth().getEnum()
== Constants.EN_AUTO) {
- contentwidth = fopImage.getIntrinsicWidth();
+ contentwidth = info.getSize().getWidthMpt();
} else if (abstractGraphic.getContentWidth().getEnum()
== Constants.EN_SCALE_TO_FIT) {
contentwidth = width;
@@ -1271,7 +1265,7 @@ public class RTFHandler extends FOEventHandler {
if (abstractGraphic.getContentHeight().getEnum()
== Constants.EN_AUTO) {
- contentheight = fopImage.getIntrinsicHeight();
+ contentheight = info.getSize().getHeightMpt();
} else if (abstractGraphic.getContentHeight().getEnum()
== Constants.EN_SCALE_TO_FIT) {
diff --git a/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfExternalGraphic.java b/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfExternalGraphic.java
index a79679450..932198676 100644
--- a/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfExternalGraphic.java
+++ b/src/java/org/apache/fop/render/rtf/rtflib/rtfdoc/RtfExternalGraphic.java
@@ -26,19 +26,17 @@ package org.apache.fop.render.rtf.rtflib.rtfdoc;
* the FOP project.
*/
-import org.apache.commons.io.IOUtils;
-import org.apache.fop.render.rtf.rtflib.tools.ImageConstants;
-import org.apache.fop.render.rtf.rtflib.tools.ImageUtil;
-//import org.apache.fop.render.rtf.rtflib.tools.jpeg.Encoder;
-//import org.apache.fop.render.rtf.rtflib.tools.jpeg.JPEGException;
-
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
-
-import java.io.File;
-import java.net.URL;
import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.commons.io.IOUtils;
+
+import org.apache.fop.render.rtf.rtflib.tools.ImageConstants;
+import org.apache.fop.render.rtf.rtflib.tools.ImageUtil;
/**
* Creates an RTF image from an external graphic file.
@@ -342,13 +340,13 @@ public class RtfExternalGraphic extends RtfElement {
}
- if (url == null) {
- throw new ExternalGraphicException("The attribute 'url' of "
- + "<fo:external-graphic> is null.");
+ if (url == null && imagedata == null) {
+ throw new ExternalGraphicException(
+ "No image data is available (neither URL, nor in-memory)");
}
String linkToRoot = System.getProperty("jfor_link_to_root");
- if (linkToRoot != null) {
+ if (url != null && linkToRoot != null) {
writer.write("{\\field {\\* \\fldinst { INCLUDEPICTURE \"");
writer.write(linkToRoot);
File urlFile = new File(url.getFile());
@@ -380,7 +378,7 @@ public class RtfExternalGraphic extends RtfElement {
}
// Determine image file format
- String file = url.getFile ();
+ String file = (url != null ? url.getFile() : "<unknown>");
imageformat = FormatBase.determineFormat(imagedata);
if (imageformat != null) {
imageformat = imageformat.convert(imageformat, imagedata);
diff --git a/src/java/org/apache/fop/svg/PDFBridgeContext.java b/src/java/org/apache/fop/svg/PDFBridgeContext.java
index 3ffad3335..9f235b6a9 100644
--- a/src/java/org/apache/fop/svg/PDFBridgeContext.java
+++ b/src/java/org/apache/fop/svg/PDFBridgeContext.java
@@ -26,6 +26,10 @@ import org.apache.batik.bridge.Bridge;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.DocumentLoader;
import org.apache.batik.bridge.UserAgent;
+
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+
import org.apache.fop.fonts.FontInfo;
/**
@@ -36,6 +40,9 @@ public class PDFBridgeContext extends BridgeContext {
/** The font list. */
private final FontInfo fontInfo;
+ private final ImageManager imageManager;
+ private final ImageSessionContext imageSessionContext;
+
private AffineTransform linkTransform;
/**
@@ -50,9 +57,13 @@ public class PDFBridgeContext extends BridgeContext {
public PDFBridgeContext(UserAgent userAgent,
DocumentLoader loader,
FontInfo fontInfo,
+ ImageManager imageManager,
+ ImageSessionContext imageSessionContext,
AffineTransform linkTransform) {
super(userAgent, loader);
this.fontInfo = fontInfo;
+ this.imageManager = imageManager;
+ this.imageSessionContext = imageSessionContext;
this.linkTransform = linkTransform;
}
@@ -66,9 +77,13 @@ public class PDFBridgeContext extends BridgeContext {
*/
public PDFBridgeContext(UserAgent userAgent,
FontInfo fontInfo,
+ ImageManager imageManager,
+ ImageSessionContext imageSessionContext,
AffineTransform linkTransform) {
super(userAgent);
this.fontInfo = fontInfo;
+ this.imageManager = imageManager;
+ this.imageSessionContext = imageSessionContext;
this.linkTransform = linkTransform;
}
@@ -78,10 +93,29 @@ public class PDFBridgeContext extends BridgeContext {
* @param fontInfo the font list for the text painter, may be null
* in which case text is painted as shapes
*/
- public PDFBridgeContext(UserAgent userAgent, FontInfo fontInfo) {
- this(userAgent, fontInfo, null);
+ public PDFBridgeContext(UserAgent userAgent,
+ FontInfo fontInfo,
+ ImageManager imageManager,
+ ImageSessionContext imageSessionContext) {
+ this(userAgent, fontInfo, imageManager, imageSessionContext, null);
}
+ /**
+ * Returns the ImageManager to be used by the ImageElementBridge.
+ * @return the image manager
+ */
+ public ImageManager getImageManager() {
+ return this.imageManager;
+ }
+
+ /**
+ * Returns the ImageSessionContext to be used by the ImageElementBridge.
+ * @return the image session context
+ */
+ public ImageSessionContext getImageSessionContext() {
+ return this.imageSessionContext;
+ }
+
private void putPDFElementBridgeConditional(String className, String testFor) {
try {
Class.forName(testFor);
@@ -136,7 +170,10 @@ public class PDFBridgeContext extends BridgeContext {
//TODO There's no matching method in the super-class here
public BridgeContext createBridgeContext() {
return new PDFBridgeContext(getUserAgent(), getDocumentLoader(),
- fontInfo, linkTransform);
+ fontInfo,
+ getImageManager(),
+ getImageSessionContext(),
+ linkTransform);
}
-
+
}
diff --git a/src/java/org/apache/fop/svg/PDFGraphics2D.java b/src/java/org/apache/fop/svg/PDFGraphics2D.java
index 2436e1a10..c3c336000 100644
--- a/src/java/org/apache/fop/svg/PDFGraphics2D.java
+++ b/src/java/org/apache/fop/svg/PDFGraphics2D.java
@@ -62,13 +62,17 @@ import org.apache.batik.ext.awt.RadialGradientPaint;
import org.apache.batik.ext.awt.RenderingHintsKeyExt;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.gvt.PatternPaint;
+
+import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG;
+import org.apache.xmlgraphics.java2d.AbstractGraphics2D;
+import org.apache.xmlgraphics.java2d.GraphicContext;
+
import org.apache.fop.fonts.CIDFont;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontSetup;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.LazyFont;
-import org.apache.fop.image.JpegImage;
import org.apache.fop.pdf.BitmapImage;
import org.apache.fop.pdf.PDFAnnotList;
import org.apache.fop.pdf.PDFColor;
@@ -76,6 +80,7 @@ import org.apache.fop.pdf.PDFConformanceException;
import org.apache.fop.pdf.PDFDeviceColorSpace;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFGState;
+import org.apache.fop.pdf.PDFImage;
import org.apache.fop.pdf.PDFImageXObject;
import org.apache.fop.pdf.PDFLink;
import org.apache.fop.pdf.PDFName;
@@ -86,10 +91,8 @@ import org.apache.fop.pdf.PDFResources;
import org.apache.fop.pdf.PDFState;
import org.apache.fop.pdf.PDFText;
import org.apache.fop.pdf.PDFXObject;
-import org.apache.fop.render.pdf.FopPDFImage;
+import org.apache.fop.render.pdf.ImageRawJPEGAdapter;
import org.apache.fop.util.ColorExt;
-import org.apache.xmlgraphics.java2d.AbstractGraphics2D;
-import org.apache.xmlgraphics.java2d.GraphicContext;
/**
* PDF Graphics 2D.
@@ -397,7 +400,7 @@ public class PDFGraphics2D extends AbstractGraphics2D {
* @param width the width to draw the image
* @param height the height to draw the image
*/
- public void addJpegImage(JpegImage jpeg, float x, float y,
+ public void addJpegImage(ImageRawJPEG jpeg, float x, float y,
float width, float height) {
preparePainting();
// Need to include hash code as when invoked from FO you
@@ -405,9 +408,9 @@ public class PDFGraphics2D extends AbstractGraphics2D {
// count is not enough.
String key = "__AddJPEG_" + hashCode() + "_" + jpegCount[0];
jpegCount[0]++;
- FopPDFImage fopimage = new FopPDFImage(jpeg, key);
+ PDFImage pdfimage = new ImageRawJPEGAdapter(jpeg, key);
PDFName imageName = this.pdfDoc.addImage(resourceContext,
- fopimage).getName();
+ pdfimage).getName();
AffineTransform at = getTransform();
double[] matrix = new double[6];
at.getMatrix(matrix);
diff --git a/src/java/org/apache/fop/svg/PDFImageElementBridge.java b/src/java/org/apache/fop/svg/PDFImageElementBridge.java
index 1545fc475..a2542e86f 100644
--- a/src/java/org/apache/fop/svg/PDFImageElementBridge.java
+++ b/src/java/org/apache/fop/svg/PDFImageElementBridge.java
@@ -19,24 +19,28 @@
package org.apache.fop.svg;
-import org.apache.batik.bridge.SVGImageElementBridge;
-
-import java.awt.Shape;
import java.awt.Graphics2D;
+import java.awt.Shape;
import java.awt.geom.Rectangle2D;
-import java.io.BufferedInputStream;
-import java.io.InputStream;
import org.w3c.dom.Element;
+import org.w3c.dom.svg.SVGDocument;
import org.apache.batik.bridge.BridgeContext;
+import org.apache.batik.bridge.SVGImageElementBridge;
import org.apache.batik.gvt.AbstractGraphicsNode;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.util.ParsedURL;
-import org.apache.fop.image.JpegImage;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.image.analyser.ImageReaderFactory;
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG;
+import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
/**
* Bridge class for the &lt;image> element when jpeg images.
@@ -50,6 +54,10 @@ public class PDFImageElementBridge extends SVGImageElementBridge {
*/
public PDFImageElementBridge() { }
+ private final ImageFlavor[] supportedFlavors = new ImageFlavor[]
+ {ImageFlavor.RAW_JPEG,
+ ImageFlavor.GRAPHICS2D,
+ ImageFlavor.XML_DOM};
/**
* Create the raster image node.
* THis checks if it is a jpeg file and creates a jpeg node
@@ -60,51 +68,68 @@ public class PDFImageElementBridge extends SVGImageElementBridge {
* @return a new graphics node
*/
protected GraphicsNode createImageGraphicsNode
- (BridgeContext ctx, Element imageElement, ParsedURL purl) {
+ (BridgeContext ctx, Element imageElement, ParsedURL purl) {
+ PDFBridgeContext pdfCtx = (PDFBridgeContext)ctx;
+
+ ImageManager manager = pdfCtx.getImageManager();
+ ImageSessionContext sessionContext = pdfCtx.getImageSessionContext();
try {
- InputStream is = purl.openStream();
- if (!is.markSupported()) {
- is = new BufferedInputStream(is, 1024);
- }
+ ImageInfo info = manager.getImageInfo(purl.toString(), sessionContext);
+ Image image = manager.getImage(info, supportedFlavors, sessionContext);
- is.mark(3);
- byte [] data = new byte[3];
- is.read(data);
- is.reset();
- if ((data[0] == (byte)0xFF)
- && (data[1] == (byte)0xD8)
- && (data[2] == (byte)0xFF)) {
- FopImage.ImageInfo ii = ImageReaderFactory.make
- (purl.toString(), is, null);
- JpegImage jpeg = new JpegImage(ii);
- jpeg.load(FopImage.ORIGINAL_DATA);
- PDFJpegNode node = new PDFJpegNode(jpeg, ctx, imageElement, purl);
-
- Rectangle2D imgBounds = getImageBounds(ctx, imageElement);
- Rectangle2D bounds = node.getPrimitiveBounds();
- float [] vb = new float[4];
- vb[0] = 0; // x
- vb[1] = 0; // y
- vb[2] = (float) bounds.getWidth(); // width
- vb[3] = (float) bounds.getHeight(); // height
-
- // handles the 'preserveAspectRatio', 'overflow' and 'clip'
- // and sets the appropriate AffineTransform to the image node
- initializeViewport(ctx, imageElement, node, vb, imgBounds);
- return node;
+ AbstractGraphicsNode specializedNode = null;
+ if (image instanceof ImageXMLDOM) {
+ ImageXMLDOM xmlImage = (ImageXMLDOM)image;
+ if (xmlImage.getDocument() instanceof SVGDocument) {
+ return createSVGImageNode(ctx, imageElement,
+ (SVGDocument)xmlImage.getDocument());
+ } else {
+ //Convert image to Graphics2D
+ image = manager.convertImage(xmlImage,
+ new ImageFlavor[] {ImageFlavor.GRAPHICS2D});
+ }
}
- } catch (Exception ex) {
- //TODO Handle this exception
- }
+ if (image instanceof ImageRawJPEG) {
+ ImageRawJPEG jpegImage = (ImageRawJPEG)image;
+ specializedNode = new PDFJpegNode(jpegImage, ctx, imageElement, purl);
+
+ } else if (image instanceof ImageGraphics2D) {
+ ImageGraphics2D g2dImage = (ImageGraphics2D)image;
+ specializedNode = new Graphics2DNode(g2dImage);
+ } else {
+ ctx.getUserAgent().displayError(
+ new ImageException("Cannot convert an image to a usable format: " + purl));
+ }
+
+ Rectangle2D imgBounds = getImageBounds(ctx, imageElement);
+ Rectangle2D bounds = specializedNode.getPrimitiveBounds();
+ float [] vb = new float[4];
+ vb[0] = 0; // x
+ vb[1] = 0; // y
+ vb[2] = (float) bounds.getWidth(); // width
+ vb[3] = (float) bounds.getHeight(); // height
+ // handles the 'preserveAspectRatio', 'overflow' and 'clip'
+ // and sets the appropriate AffineTransform to the image node
+ initializeViewport(ctx, imageElement, specializedNode, vb, imgBounds);
+ return specializedNode;
+ } catch (Exception e) {
+ ctx.getUserAgent().displayError(e);
+ }
+
return superCreateGraphicsNode(ctx, imageElement, purl);
}
/**
+ * Calls the superclass' createImageGraphicNode() method to create the normal GraphicsNode.
+ * @param ctx the bridge context
+ * @param imageElement the image element
+ * @param purl the parsed URL
+ * @return the newly created graphics node
* @see org.apache.batik.bridge.SVGImageElementBridge#createGraphicsNode(BridgeContext, Element)
*/
protected GraphicsNode superCreateGraphicsNode
- (BridgeContext ctx, Element imageElement, ParsedURL purl) {
+ (BridgeContext ctx, Element imageElement, ParsedURL purl) {
return super.createImageGraphicsNode(ctx, imageElement, purl);
}
@@ -116,21 +141,21 @@ public class PDFImageElementBridge extends SVGImageElementBridge {
*/
public class PDFJpegNode extends AbstractGraphicsNode {
- private JpegImage jpeg;
+ private ImageRawJPEG jpeg;
private BridgeContext ctx;
private Element imageElement;
private ParsedURL purl;
private GraphicsNode origGraphicsNode = null;
/**
- * Create a new pdf jpeg node for drawing jpeg images
+ * Create a new PDF JPEG node for drawing JPEG images
* into pdf graphics.
- * @param j the jpeg image
+ * @param j the JPEG image
* @param ctx the bridge context
* @param imageElement the SVG image element
* @param purl the URL to the image
*/
- public PDFJpegNode(JpegImage j, BridgeContext ctx,
+ public PDFJpegNode(ImageRawJPEG j, BridgeContext ctx,
Element imageElement, ParsedURL purl) {
this.jpeg = j;
this.ctx = ctx;
@@ -138,32 +163,23 @@ public class PDFImageElementBridge extends SVGImageElementBridge {
this.purl = purl;
}
- /**
- * Get the outline of this image.
- * @return the outline shape which is the primitive bounds
- */
+ /** {@inheritDoc} */
public Shape getOutline() {
return getPrimitiveBounds();
}
- /**
- * Paint this jpeg image.
- * As this is used for inserting jpeg into pdf
- * it adds the jpeg image to the PDFGraphics2D.
- * @param g2d the graphics to draw the image on
- */
+ /** {@inheritDoc} */
public void primitivePaint(Graphics2D g2d) {
if (g2d instanceof PDFGraphics2D) {
PDFGraphics2D pdfg = (PDFGraphics2D) g2d;
float x = 0;
float y = 0;
try {
- float width = jpeg.getWidth();
- float height = jpeg.getHeight();
+ float width = jpeg.getSize().getWidthPx();
+ float height = jpeg.getSize().getHeightPx();
pdfg.addJpegImage(jpeg, x, y, width, height);
} catch (Exception e) {
- //TODO Handle this exception properly
- e.printStackTrace();
+ ctx.getUserAgent().displayError(e);
}
} else {
// Not going directly into PDF so use
@@ -179,40 +195,71 @@ public class PDFImageElementBridge extends SVGImageElementBridge {
}
}
- /**
- * Get the geometrix bounds of the image.
- * @return the primitive bounds
- */
+ /** {@inheritDoc} */
public Rectangle2D getGeometryBounds() {
return getPrimitiveBounds();
}
- /**
- * Get the primitive bounds of this bridge element.
- * @return the bounds of the jpeg image
- */
+ /** {@inheritDoc} */
public Rectangle2D getPrimitiveBounds() {
- try {
- return new Rectangle2D.Double(0, 0, jpeg.getWidth(),
- jpeg.getHeight());
- } catch (Exception e) {
- //TODO Handle this exception properly
- e.printStackTrace();
- }
- return null;
+ return new Rectangle2D.Double(0, 0,
+ jpeg.getSize().getWidthPx(),
+ jpeg.getSize().getHeightPx());
+ }
+
+ /** {@inheritDoc} */
+ public Rectangle2D getSensitiveBounds() {
+ //No interactive features, just return primitive bounds
+ return getPrimitiveBounds();
}
+ }
+
+ /**
+ * A node that holds a Graphics2D image.
+ */
+ public class Graphics2DNode extends AbstractGraphicsNode {
+
+ private ImageGraphics2D image;
+
/**
- * Returns the bounds of the sensitive area covered by this node,
- * This includes the stroked area but does not include the effects
- * of clipping, masking or filtering.
- * @return the bounds of the sensitive area
+ * Create a new Graphics2D node.
+ * @param g2d the Graphics2D image
*/
+ public Graphics2DNode(ImageGraphics2D g2d) {
+ this.image = g2d;
+ }
+
+ /** {@inheritDoc} */
+ public Shape getOutline() {
+ return getPrimitiveBounds();
+ }
+
+ /** {@inheritDoc} */
+ public void primitivePaint(Graphics2D g2d) {
+ int width = image.getSize().getWidthPx();
+ int height = image.getSize().getHeightPx();
+ Rectangle2D area = new Rectangle2D.Double(0, 0, width, height);
+ image.getGraphics2DImagePainter().paint(g2d, area);
+ }
+
+ /** {@inheritDoc} */
+ public Rectangle2D getGeometryBounds() {
+ return getPrimitiveBounds();
+ }
+
+ /** {@inheritDoc} */
+ public Rectangle2D getPrimitiveBounds() {
+ return new Rectangle2D.Double(0, 0,
+ image.getSize().getWidthPx(),
+ image.getSize().getHeightPx());
+ }
+
+ /** {@inheritDoc} */
public Rectangle2D getSensitiveBounds() {
//No interactive features, just return primitive bounds
return getPrimitiveBounds();
}
}
-
}
diff --git a/src/java/org/apache/fop/svg/PDFTranscoder.java b/src/java/org/apache/fop/svg/PDFTranscoder.java
index 417b82097..281df1b1d 100644
--- a/src/java/org/apache/fop/svg/PDFTranscoder.java
+++ b/src/java/org/apache/fop/svg/PDFTranscoder.java
@@ -23,6 +23,10 @@ import java.awt.Color;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.io.InputStream;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Document;
import org.w3c.dom.svg.SVGLength;
@@ -41,6 +45,12 @@ import org.apache.batik.transcoder.TranscodingHints;
import org.apache.batik.transcoder.image.ImageTranscoder;
import org.apache.batik.transcoder.keys.BooleanKey;
import org.apache.batik.transcoder.keys.FloatKey;
+import org.apache.batik.util.ParsedURL;
+
+import org.apache.xmlgraphics.image.loader.ImageContext;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
+import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext;
import org.apache.fop.Version;
import org.apache.fop.fonts.FontInfo;
@@ -99,6 +109,9 @@ public class PDFTranscoder extends AbstractFOPTranscoder
/** Graphics2D instance that is used to paint to */
protected PDFDocumentGraphics2D graphics = null;
+ private ImageManager imageManager;
+ private ImageSessionContext imageSessionContext;
+
/**
* Constructs a new <tt>PDFTranscoder</tt>.
*/
@@ -141,6 +154,11 @@ public class PDFTranscoder extends AbstractFOPTranscoder
graphics.getPDFDocument().getInfo().setProducer("Apache FOP Version "
+ Version.getVersion()
+ ": PDF Transcoder for Batik");
+ if (hints.containsKey(KEY_DEVICE_RESOLUTION)) {
+ graphics.setDeviceDPI(((Float)hints.get(KEY_DEVICE_RESOLUTION)).floatValue());
+ }
+
+ setupImageInfrastructure(uri);
try {
Configuration effCfg = this.cfg;
@@ -196,9 +214,6 @@ public class PDFTranscoder extends AbstractFOPTranscoder
//int h = (int)(height + 0.5);
try {
- if (hints.containsKey(KEY_DEVICE_RESOLUTION)) {
- graphics.setDeviceDPI(((Float)hints.get(KEY_DEVICE_RESOLUTION)).floatValue());
- }
OutputStream out = output.getOutputStream();
if (!(out instanceof BufferedOutputStream)) {
out = new BufferedOutputStream(out);
@@ -227,6 +242,39 @@ public class PDFTranscoder extends AbstractFOPTranscoder
}
}
+ private void setupImageInfrastructure(final String baseURI) {
+ final ImageContext imageContext = new ImageContext() {
+ public float getSourceResolution() {
+ return 25.4f / userAgent.getPixelUnitToMillimeter();
+ }
+ };
+ this.imageManager = new ImageManager(imageContext);
+ this.imageSessionContext = new AbstractImageSessionContext() {
+
+ public ImageContext getParentContext() {
+ return imageContext;
+ }
+
+ public float getTargetResolution() {
+ return graphics.getDeviceDPI();
+ }
+
+ public Source resolveURI(String uri) {
+ System.out.println("resolve " + uri);
+ try {
+ ParsedURL url = new ParsedURL(baseURI, uri);
+ InputStream in = url.openStream();
+ StreamSource source = new StreamSource(in, url.toString());
+ return source;
+ } catch (IOException ioe) {
+ userAgent.displayError(ioe);
+ return null;
+ }
+ }
+
+ };
+ }
+
/** {@inheritDoc} */
protected BridgeContext createBridgeContext() {
//For compatibility with Batik 1.6
@@ -239,7 +287,8 @@ public class PDFTranscoder extends AbstractFOPTranscoder
if (isTextStroked()) {
fontInfo = null;
}
- BridgeContext ctx = new PDFBridgeContext(userAgent, fontInfo);
+ BridgeContext ctx = new PDFBridgeContext(userAgent, fontInfo,
+ this.imageManager, this.imageSessionContext);
return ctx;
}
diff --git a/src/java/org/apache/fop/util/dijkstra/DefaultEdgeDirectory.java b/src/java/org/apache/fop/util/dijkstra/DefaultEdgeDirectory.java
new file mode 100644
index 000000000..381b356a2
--- /dev/null
+++ b/src/java/org/apache/fop/util/dijkstra/DefaultEdgeDirectory.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util.dijkstra;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Default implementation of an edge directory for the {@link DijkstraAlgorithm}.
+ */
+public class DefaultEdgeDirectory implements EdgeDirectory {
+
+ /** The directory of edges */
+ private Map edges = new java.util.HashMap();
+ //Map<Vertex,Map<Vertex,Edge>>
+
+ /**
+ * Adds a new edge between two vertices.
+ * @param edge the new edge
+ */
+ public void addEdge(Edge edge) {
+ Map directEdges = (Map)edges.get(edge.getStart());
+ if (directEdges == null) {
+ directEdges = new java.util.HashMap();
+ edges.put(edge.getStart(), directEdges);
+ }
+ directEdges.put(edge.getEnd(), edge);
+ }
+
+ /** {@inheritDoc} */
+ public int getPenalty(Vertex start, Vertex end) {
+ Map edgeMap = (Map)edges.get(start);
+ if (edgeMap != null) {
+ Edge route = (Edge)edgeMap.get(end);
+ if (route != null) {
+ int penalty = route.getPenalty();
+ if (penalty < 0) {
+ throw new IllegalStateException("Penalty must not be negative");
+ }
+ return penalty;
+ }
+ }
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ public Iterator getDestinations(Vertex origin) {
+ Map directRoutes = (Map)edges.get(origin);
+ if (directRoutes != null) {
+ Iterator iter = directRoutes.keySet().iterator();
+ return iter;
+ }
+ return Collections.EMPTY_LIST.iterator();
+ }
+
+ /**
+ * Returns an iterator over all edges with the given origin.
+ * @param origin the origin
+ * @return an iterator over Edge instances
+ */
+ public Iterator getEdges(Vertex origin) {
+ Map directRoutes = (Map)edges.get(origin);
+ if (directRoutes != null) {
+ Iterator iter = directRoutes.values().iterator();
+ return iter;
+ }
+ return Collections.EMPTY_LIST.iterator();
+ }
+
+ /**
+ * Returns the best edge (the edge with the lowest penalty) between two given vertices.
+ * @param start the start vertex
+ * @param end the end vertex
+ * @return the best vertex or null if none is found
+ */
+ public Edge getBestEdge(Vertex start, Vertex end) {
+ Edge best = null;
+ Iterator iter = getEdges(start);
+ while (iter.hasNext()) {
+ Edge edge = (Edge)iter.next();
+ if (edge.getEnd().equals(end)) {
+ if (best == null || edge.getPenalty() < best.getPenalty()) {
+ best = edge;
+ }
+ }
+ }
+ return best;
+ }
+
+
+}
diff --git a/src/java/org/apache/fop/util/dijkstra/DijkstraAlgorithm.java b/src/java/org/apache/fop/util/dijkstra/DijkstraAlgorithm.java
new file mode 100644
index 000000000..a5b2fe202
--- /dev/null
+++ b/src/java/org/apache/fop/util/dijkstra/DijkstraAlgorithm.java
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util.dijkstra;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * This is an implementation of Dijkstra's algorithm to find the shortest path for a directed
+ * graph with non-negative edge weights.
+ * @see <a href="http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm">WikiPedia on Dijkstra's
+ * Algorithm</a>
+ */
+public class DijkstraAlgorithm {
+
+ /** Infinity value for distances. */
+ public static final int INFINITE = Integer.MAX_VALUE;
+
+ /** Compares penalties between two possible destinations. */
+ private final Comparator penaltyComparator = new Comparator() {
+ public int compare(Object left, Object right) {
+ int leftPenalty = getLowestPenalty((Vertex)left);
+ int rightPenalty = getLowestPenalty((Vertex)right);
+ if (leftPenalty < rightPenalty) {
+ return -1;
+ } else if (leftPenalty == rightPenalty) {
+ return ((Comparable)left).compareTo(right);
+ } else {
+ return 1;
+ }
+ }
+ };
+
+ /** The directory of edges */
+ private EdgeDirectory edgeDirectory;
+
+ /** The priority queue for all vertices under inspection, ordered by penalties/distances. */
+ private TreeSet priorityQueue = new TreeSet(penaltyComparator);
+ //Set<Vertex>
+
+ /** The set of vertices for which the lowest penalty has been found. */
+ private Set finishedVertices = new java.util.HashSet();
+ //Set<Vertex>
+
+ /** The currently known lowest penalties for all vertices. */
+ private Map lowestPenalties = new java.util.HashMap();
+ //Map<Vertex,Integer>
+
+ /** Map of all predecessors in the spanning tree of best routes. */
+ private Map predecessors = new java.util.HashMap();
+ //Map<Vertex,Vertex>
+
+ /**
+ * Main Constructor.
+ * @param edgeDirectory the edge directory this instance should work on
+ */
+ public DijkstraAlgorithm(EdgeDirectory edgeDirectory) {
+ this.edgeDirectory = edgeDirectory;
+ }
+
+ /**
+ * Returns the penalty between two vertices.
+ * @param start the start vertex
+ * @param end the end vertex
+ * @return the penalty between two vertices, or 0 if no single edge between the two vertices
+ * exists.
+ */
+ protected int getPenalty(Vertex start, Vertex end) {
+ return this.edgeDirectory.getPenalty(start, end);
+ }
+
+ /**
+ * Returns an iterator over all valid destinations for a given vertex.
+ * @param origin the origin from which to search for destinations
+ * @return the iterator over all valid destinations for a given vertex
+ */
+ protected Iterator getDestinations(Vertex origin) {
+ return this.edgeDirectory.getDestinations(origin);
+ }
+
+ private void reset() {
+ finishedVertices.clear();
+ priorityQueue.clear();
+
+ lowestPenalties.clear();
+ predecessors.clear();
+ }
+
+ /**
+ * Run Dijkstra's shortest path algorithm. After this method is finished you can use
+ * {@link #getPredecessor(Vertex)} to reconstruct the best/shortest path starting from the
+ * destination backwards.
+ * @param start the starting vertex
+ * @param destination the destination vertex.
+ */
+ public void execute(Vertex start, Vertex destination) {
+ if (start == null || destination == null) {
+ throw new NullPointerException("start and destination may not be null");
+ }
+
+ reset();
+ setShortestDistance(start, 0);
+ priorityQueue.add(start);
+
+ // the current node
+ Vertex u;
+
+ // extract the vertex with the shortest distance
+ while (priorityQueue.size() > 0) {
+ u = (Vertex)priorityQueue.first();
+ priorityQueue.remove(u);
+
+ if (destination.equals(u)) {
+ //Destination reached
+ break;
+ }
+
+ finishedVertices.add(u);
+ relax(u);
+ }
+ }
+
+ /**
+ * Compute new lowest penalties for neighboring vertices. Update the lowest penalties and the
+ * predecessor map if a better solution is found.
+ * @param u the vertex to process
+ */
+ private void relax(Vertex u) {
+ Iterator iter = getDestinations(u);
+ while (iter.hasNext()) {
+ Vertex v = (Vertex)iter.next();
+ // skip node already settled
+ if (isFinished(v)) {
+ continue;
+ }
+
+ int shortDist = getLowestPenalty(u) + getPenalty(u, v);
+
+ if (shortDist < getLowestPenalty(v)) {
+ // assign new shortest distance and mark unsettled
+ setShortestDistance(v, shortDist);
+
+ // assign predecessor in shortest path
+ setPredecessor(v, u);
+ }
+ }
+ }
+
+ private void setPredecessor(Vertex a, Vertex b) {
+ predecessors.put(a, b);
+ }
+
+ /**
+ * Indicates whether a shortest route to a vertex has been found.
+ * @param v the vertex
+ * @return true if the shortest route to this vertex has been found.
+ */
+ private boolean isFinished(Vertex v) {
+ return finishedVertices.contains(v);
+ }
+
+ private void setShortestDistance(Vertex vertex, int distance) {
+ //Remove so it is inserted at the right position after the lowest penalty changes for this
+ //vertex.
+ priorityQueue.remove(vertex);
+
+ //Update the lowest penalty.
+ lowestPenalties.put(vertex, new Integer(distance));
+
+ //Insert the vertex again at the new position based on the lowest penalty
+ priorityQueue.add(vertex);
+ }
+
+ /**
+ * Returns the lowest penalty from the start point to a given vertex.
+ * @param vertex the vertex
+ * @return the lowest penalty or {@link DijkstraAlgorithm#INFINITE} if there is no route to
+ * the destination.
+ */
+ public int getLowestPenalty(Vertex vertex) {
+ Integer d = ((Integer)lowestPenalties.get(vertex));
+ return (d == null) ? INFINITE : d.intValue();
+ }
+
+ /**
+ * Returns the vertex's predecessor on the shortest path.
+ * @param vertex the vertex for which to find the predecessor
+ * @return the vertex's predecessor on the shortest path, or
+ * <code>null</code> if there is no route to the destination.
+ */
+ public Vertex getPredecessor(Vertex vertex) {
+ return (Vertex)predecessors.get(vertex);
+ }
+
+}
diff --git a/src/java/org/apache/fop/util/dijkstra/Edge.java b/src/java/org/apache/fop/util/dijkstra/Edge.java
new file mode 100644
index 000000000..f709b9e26
--- /dev/null
+++ b/src/java/org/apache/fop/util/dijkstra/Edge.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util.dijkstra;
+
+/**
+ * Represents an edge (or direct route between two points) for the {@link DijkstraAlgorithm}.
+ * Implement this class to hold the start and end vertex for an edge and implement the
+ * <code>getPenalty()</code> method.
+ */
+public interface Edge {
+
+ /**
+ * Returns the start vertex of the edge.
+ * @return the start vertex
+ */
+ Vertex getStart();
+
+ /**
+ * Returns the end vertex of the edge.
+ * @return the end vertex
+ */
+ Vertex getEnd();
+
+ /**
+ * Returns the penalty (or distance) for this edge.
+ * @return the penalty value (must be non-negative)
+ */
+ int getPenalty();
+
+}
diff --git a/src/java/org/apache/fop/util/dijkstra/EdgeDirectory.java b/src/java/org/apache/fop/util/dijkstra/EdgeDirectory.java
new file mode 100644
index 000000000..6a2dc848b
--- /dev/null
+++ b/src/java/org/apache/fop/util/dijkstra/EdgeDirectory.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util.dijkstra;
+
+import java.util.Iterator;
+
+/**
+ * Represents a directory of edges for use by the {@link DijkstraAlgorithm}.
+ */
+public interface EdgeDirectory {
+
+ /**
+ * Returns the penalty between two vertices.
+ * @param start the start vertex
+ * @param end the end vertex
+ * @return the penalty between two vertices, or 0 if no single edge between the two vertices
+ * exists.
+ */
+ int getPenalty(Vertex start, Vertex end);
+
+ /**
+ * Returns an iterator over all valid destinations for a given vertex.
+ * @param origin the origin from which to search for destinations
+ * @return the iterator over all valid destinations for a given vertex
+ */
+ Iterator getDestinations(Vertex origin);
+
+} \ No newline at end of file
diff --git a/src/java/org/apache/fop/util/dijkstra/Vertex.java b/src/java/org/apache/fop/util/dijkstra/Vertex.java
new file mode 100644
index 000000000..40c41b0b7
--- /dev/null
+++ b/src/java/org/apache/fop/util/dijkstra/Vertex.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util.dijkstra;
+
+/**
+ * Represents a vertex to be used by {@link DijkstraAlgorithm}. If you want to represent a city,
+ * you can do "public class City implements Vertex". The purpose of this interface is to make
+ * sure the Vertex implementation implements the Comparable interface so the sorting order is
+ * well-defined even when two vertices have the same penalty/distance from an origin point.
+ * Therefore, make sure you implement the <code>compareTo(Object)</code> and
+ * <code>equals(Object)</code> methods.
+ */
+public interface Vertex extends Comparable {
+
+}