Browse Source

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
tags/fop-0_95beta
Jeremias Maerki 16 years ago
parent
commit
44c5761c1a
100 changed files with 4371 additions and 1371 deletions
  1. 1
    0
      build.xml
  2. 1
    0
      examples/mathml/resources/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageLoaderFactory
  3. 1
    0
      examples/mathml/resources/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImagePreloader
  4. 66
    0
      examples/mathml/src/org/apache/fop/mathml/ImageLoaderFactoryMathML.java
  5. 71
    0
      examples/mathml/src/org/apache/fop/mathml/ImageLoaderMathML.java
  6. 11
    16
      examples/mathml/src/org/apache/fop/mathml/MathMLElement.java
  7. 6
    47
      examples/mathml/src/org/apache/fop/mathml/MathMLElementMapping.java
  8. 2
    2
      examples/mathml/src/org/apache/fop/mathml/MathMLObj.java
  9. 189
    0
      examples/mathml/src/org/apache/fop/mathml/PreloaderMathML.java
  10. 1
    0
      examples/plan/resources/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImagePreloader
  11. 9
    14
      examples/plan/src/org/apache/fop/plan/PlanElement.java
  12. 5
    29
      examples/plan/src/org/apache/fop/plan/PlanElementMapping.java
  13. 2
    2
      examples/plan/src/org/apache/fop/plan/PlanObj.java
  14. 114
    0
      examples/plan/src/org/apache/fop/plan/PreloaderPlan.java
  15. 2
    1
      fop.bat
  16. 13
    0
      lib/README.txt
  17. BIN
      lib/batik-all-1.6.jar
  18. BIN
      lib/batik-all-1.7.jar
  19. 13
    3
      lib/batik.NOTICE.txt
  20. BIN
      lib/xml-apis-ext.jar
  21. BIN
      lib/xmlgraphics-commons-1.3svn.jar
  22. 5
    0
      src/java/META-INF/services/org.apache.fop.render.pdf.PDFImageHandler
  23. 2
    0
      src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageConverter
  24. 2
    0
      src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageLoaderFactory
  25. 2
    0
      src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImagePreloader
  26. 17
    4
      src/java/org/apache/fop/apps/FOURIResolver.java
  27. 29
    2
      src/java/org/apache/fop/apps/FOUserAgent.java
  28. 20
    4
      src/java/org/apache/fop/apps/FopFactory.java
  29. 8
    14
      src/java/org/apache/fop/area/AreaTreeHandler.java
  30. 16
    17
      src/java/org/apache/fop/area/AreaTreeParser.java
  31. 10
    9
      src/java/org/apache/fop/area/Trait.java
  32. 40
    8
      src/java/org/apache/fop/cli/CommandLineOptions.java
  33. 60
    0
      src/java/org/apache/fop/cli/ImageInputHandler.java
  34. 27
    6
      src/java/org/apache/fop/cli/InputHandler.java
  35. 45
    0
      src/java/org/apache/fop/cli/image2fo.xsl
  36. 5
    10
      src/java/org/apache/fop/fo/FOTreeBuilder.java
  37. 27
    16
      src/java/org/apache/fop/fo/flow/ExternalGraphic.java
  38. 5
    9
      src/java/org/apache/fop/fo/pagination/Root.java
  39. 18
    17
      src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
  40. 41
    0
      src/java/org/apache/fop/image/loader/batik/BatikUtil.java
  41. 120
    0
      src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java
  42. 107
    0
      src/java/org/apache/fop/image/loader/batik/ImageConverterWMF2G2D.java
  43. 63
    0
      src/java/org/apache/fop/image/loader/batik/ImageLoaderFactorySVG.java
  44. 62
    0
      src/java/org/apache/fop/image/loader/batik/ImageLoaderFactoryWMF.java
  45. 78
    0
      src/java/org/apache/fop/image/loader/batik/ImageLoaderSVG.java
  46. 70
    0
      src/java/org/apache/fop/image/loader/batik/ImageLoaderWMF.java
  47. 69
    0
      src/java/org/apache/fop/image/loader/batik/ImageWMF.java
  48. 182
    0
      src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java
  49. 142
    0
      src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java
  50. 26
    0
      src/java/org/apache/fop/image/loader/batik/package.html
  51. 75
    30
      src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java
  52. 8
    9
      src/java/org/apache/fop/layoutmgr/TraitSetter.java
  53. 143
    47
      src/java/org/apache/fop/layoutmgr/inline/ImageLayout.java
  54. 181
    0
      src/java/org/apache/fop/pdf/AlphaRasterImage.java
  55. 14
    13
      src/java/org/apache/fop/pdf/BitmapImage.java
  56. 4
    4
      src/java/org/apache/fop/pdf/FlateFilter.java
  57. 0
    3
      src/java/org/apache/fop/pdf/PDFFactory.java
  58. 5
    0
      src/java/org/apache/fop/pdf/PDFFilterList.java
  59. 1
    3
      src/java/org/apache/fop/pdf/PDFICCStream.java
  60. 11
    3
      src/java/org/apache/fop/pdf/PDFImage.java
  61. 14
    7
      src/java/org/apache/fop/pdf/PDFImageXObject.java
  62. 19
    7
      src/java/org/apache/fop/pdf/PDFObject.java
  63. 3
    0
      src/java/org/apache/fop/pdf/PDFReference.java
  64. 20
    6
      src/java/org/apache/fop/pdf/PDFText.java
  65. 13
    13
      src/java/org/apache/fop/render/AbstractGenericSVGHandler.java
  66. 3
    3
      src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java
  67. 43
    45
      src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java
  68. 1
    1
      src/java/org/apache/fop/render/Graphics2DAdapter.java
  69. 3
    18
      src/java/org/apache/fop/render/Graphics2DImagePainter.java
  70. 2
    1
      src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java
  71. 143
    41
      src/java/org/apache/fop/render/afp/AFPRenderer.java
  72. 13
    19
      src/java/org/apache/fop/render/java2d/Java2DGraphics2DAdapter.java
  73. 61
    80
      src/java/org/apache/fop/render/java2d/Java2DRenderer.java
  74. 6
    3
      src/java/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java
  75. 131
    124
      src/java/org/apache/fop/render/pcl/PCLRenderer.java
  76. 17
    0
      src/java/org/apache/fop/render/pcl/PCLRendererContext.java
  77. 32
    0
      src/java/org/apache/fop/render/pcl/PCLRendererContextConstants.java
  78. 8
    0
      src/java/org/apache/fop/render/pcl/PCLSVGHandler.java
  79. 200
    0
      src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java
  80. 0
    374
      src/java/org/apache/fop/render/pdf/FopPDFImage.java
  81. 110
    0
      src/java/org/apache/fop/render/pdf/ImageRawCCITTFaxAdapter.java
  82. 96
    0
      src/java/org/apache/fop/render/pdf/ImageRawJPEGAdapter.java
  83. 249
    0
      src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java
  84. 2
    1
      src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java
  85. 33
    11
      src/java/org/apache/fop/render/pdf/PDFImageHandler.java
  86. 68
    0
      src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java
  87. 83
    0
      src/java/org/apache/fop/render/pdf/PDFImageHandlerRawCCITTFax.java
  88. 83
    0
      src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java
  89. 77
    7
      src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java
  90. 84
    0
      src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java
  91. 74
    0
      src/java/org/apache/fop/render/pdf/PDFImageHandlerXML.java
  92. 71
    89
      src/java/org/apache/fop/render/pdf/PDFRenderer.java
  93. 1
    1
      src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java
  94. 28
    23
      src/java/org/apache/fop/render/pdf/PDFSVGHandler.java
  95. 71
    0
      src/java/org/apache/fop/render/ps/ImageEncoderCCITTFax.java
  96. 51
    0
      src/java/org/apache/fop/render/ps/ImageEncoderJPEG.java
  97. 23
    11
      src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java
  98. 5
    95
      src/java/org/apache/fop/render/ps/PSImageUtils.java
  99. 183
    49
      src/java/org/apache/fop/render/ps/PSRenderer.java
  100. 0
    0
      src/java/org/apache/fop/render/ps/PSSupportedFlavors.java

+ 1
- 0
build.xml View File

@@ -1018,6 +1018,7 @@ NOTE:
overview="${src.dir}/java/org/apache/fop/overview.html"
use="true"
failonerror="true"
source="${javac.source}"
public="${javadoc.public}"
package="${javadoc.package}"
private="${javadoc.private}">

+ 1
- 0
examples/mathml/resources/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageLoaderFactory View File

@@ -0,0 +1 @@
org.apache.fop.mathml.ImageLoaderFactoryMathML

+ 1
- 0
examples/mathml/resources/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImagePreloader View File

@@ -0,0 +1 @@
org.apache.fop.mathml.PreloaderMathML

+ 66
- 0
examples/mathml/src/org/apache/fop/mathml/ImageLoaderFactoryMathML.java View File

@@ -0,0 +1,66 @@
/*
* 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.mathml;

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 MathML.
*/
public class ImageLoaderFactoryMathML extends AbstractImageLoaderFactory {

/** MathML MIME type */
public static final String MIME_MATHML = "text/mathml";
private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
ImageFlavor.GRAPHICS2D};
private static final String[] MIMES = new String[] {
MIME_MATHML};
/** {@inheritDoc} */
public String[] getSupportedMIMETypes() {
return MIMES;
}
/** {@inheritDoc} */
public ImageFlavor[] getSupportedFlavors(String mime) {
return FLAVORS;
}
/** {@inheritDoc} */
public ImageLoader newImageLoader(ImageFlavor targetFlavor) {
return new ImageLoaderMathML(targetFlavor);
}
/** {@inheritDoc} */
public int getUsagePenalty(String mime, ImageFlavor flavor) {
return 0;
}

/** {@inheritDoc} */
public boolean isAvailable() {
//TODO Refine!
return true;
}

}

+ 71
- 0
examples/mathml/src/org/apache/fop/mathml/ImageLoaderMathML.java View File

@@ -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.mathml;

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;
import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;

/**
* ImageLoader for MathML (using JEuclid).
*/
public class ImageLoaderMathML extends AbstractImageLoader {

private ImageFlavor targetFlavor;

/**
* Main constructor.
* @param targetFlavor the target flavor
*/
public ImageLoaderMathML(ImageFlavor targetFlavor) {
if (!(ImageFlavor.GRAPHICS2D.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 (!ImageLoaderFactoryMathML.MIME_MATHML.equals(info.getMimeType())) {
throw new IllegalArgumentException("ImageInfo must be from an MathML image");
}
Image img = info.getOriginalImage();
if (!(img instanceof ImageGraphics2D)) {
throw new IllegalArgumentException(
"ImageInfo was expected to contain the MathML document as Graphics2D image");
}
ImageGraphics2D g2dImage = (ImageGraphics2D)img;
return g2dImage;
}

}

+ 11
- 16
examples/mathml/src/org/apache/fop/mathml/MathMLElement.java View File

@@ -23,9 +23,9 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.geom.Point2D;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;
import net.sourceforge.jeuclid.DOMMathBuilder;
import net.sourceforge.jeuclid.MathBase;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -34,11 +34,12 @@ import org.w3c.dom.Node;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;

import org.apache.batik.svggen.SVGGraphics2D;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.svggen.SVGGraphics2D;

import net.sourceforge.jeuclid.MathBase;
import net.sourceforge.jeuclid.DOMMathBuilder;
import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;

/**
* Defines the top-level element for MathML.
@@ -57,9 +58,7 @@ public class MathMLElement extends MathMLObj {
super(parent);
}

/**
* @see org.apache.fop.fo.FONode#processNode
*/
/** {@inheritDoc} */
public void processNode(String elementName,
Locator locator,
Attributes attlist,
@@ -141,15 +140,13 @@ public class MathMLElement extends MathMLObj {

}

/** @see org.apache.fop.fo.XMLObj#getDOMDocument() */
/** {@inheritDoc} */
public Document getDOMDocument() {
convertToSVG();
return doc;
}

/**
* @see org.apache.fop.fo.FONode#getNamespaceURI()
*/
/** {@inheritDoc} */
public String getNamespaceURI() {
if (svgDoc == null) {
return MathMLElementMapping.NAMESPACE;
@@ -157,9 +154,7 @@ public class MathMLElement extends MathMLObj {
return "http://www.w3.org/2000/svg";
}

/**
* @see org.apache.fop.fo.XMLObj#getDimension(Point2D)
*/
/** {@inheritDoc} */
public Point2D getDimension(Point2D view) {
convertToSVG();
return new Point2D.Float(width, height);

+ 6
- 47
examples/mathml/src/org/apache/fop/mathml/MathMLElementMapping.java View File

@@ -19,17 +19,12 @@
package org.apache.fop.mathml;

import org.apache.fop.fo.FONode;
import org.apache.fop.fo.ElementMapping;
import org.apache.fop.image.analyser.XMLReader;
import org.apache.fop.image.FopImage;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;

import java.util.HashMap;

import net.sourceforge.jeuclid.MathBase;
import net.sourceforge.jeuclid.DOMMathBuilder;
import org.w3c.dom.DOMImplementation;

import org.apache.fop.fo.ElementMapping;
import org.apache.fop.fo.FONode;

/**
* This class provides the element mapping for FOP.
@@ -44,19 +39,17 @@ public class MathMLElementMapping extends ElementMapping {
this.namespaceURI = NAMESPACE;
}

/** @see org.apache.fop.fo.ElementMapping#getDOMImplementation() */
/** {@inheritDoc} */
public DOMImplementation getDOMImplementation() {
return getDefaultDOMImplementation();
}

/** @see org.apache.fop.fo.ElementMapping#initialize() */
/** {@inheritDoc} */
protected void initialize() {
if (foObjs == null) {
foObjs = new HashMap();
foObjs.put("math", new ME());
foObjs.put(DEFAULT, new MathMLMaker());

XMLReader.setConverter(this.namespaceURI, new MathMLConverter());
}
}

@@ -72,38 +65,4 @@ public class MathMLElementMapping extends ElementMapping {
}
}

static class MathMLConverter implements XMLReader.Converter {
public FopImage.ImageInfo convert(Document doc) {
try {
FopImage.ImageInfo info = new FopImage.ImageInfo();
String fontname = "Helvetica";
int fontstyle = 0;
int inlinefontstyle = 0;
int inlinefontsize = 12;
int displayfontsize = 12;

MathBase base = new MathBase(
(new DOMMathBuilder(doc)).getMathRootElement(),
fontname, fontstyle, inlinefontsize,
displayfontsize);

base.setDebug(false);

info.data = MathMLElement.createSVG(base);

info.width = base.getWidth();
info.height = base.getHeight();

info.mimeType = "image/svg+xml";
info.str = "http://www.w3.org/2000/svg";

return info;
} catch (Throwable t) {
/**@todo log that properly */
}
return null;

}
}

}

+ 2
- 2
examples/mathml/src/org/apache/fop/mathml/MathMLObj.java View File

@@ -35,12 +35,12 @@ public class MathMLObj extends XMLObj {
super(parent);
}

/** @see org.apache.fop.fo.FONode#getNamespaceURI() */
/** {@inheritDoc} */
public String getNamespaceURI() {
return MathMLElementMapping.NAMESPACE;
}

/** @see org.apache.fop.fo.FONode#getNormalNamespacePrefix() */
/** {@inheritDoc} */
public String getNormalNamespacePrefix() {
return "mathml";
}

+ 189
- 0
examples/mathml/src/org/apache/fop/mathml/PreloaderMathML.java View File

@@ -0,0 +1,189 @@
/*
* 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.mathml;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.InputStream;

import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

import net.sourceforge.jeuclid.MathBase;
import net.sourceforge.jeuclid.SAXMathBuilder;

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.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.ImageGraphics2D;
import org.apache.xmlgraphics.image.loader.util.ImageUtil;
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;

import org.apache.fop.util.UnclosableInputStream;

/**
* Image preloader for MathML images.
*/
public class PreloaderMathML extends AbstractImagePreloader {

/** Logger instance */
private static Log log = LogFactory.getLog(PreloaderMathML.class);

private boolean jeuclidAvailable = 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 (jeuclidAvailable) {
try {
Loader loader = new Loader();
info = loader.getImage(uri, src, context);
} catch (NoClassDefFoundError e) {
jeuclidAvailable = false;
log.warn("JEuclid 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 JEuclid related classes when constructing the MathMLPreloader
* class.
*/
class Loader {
private ImageInfo getImage(String uri, Source src, ImageContext context) {

InputStream in = new UnclosableInputStream(ImageUtil.needInputStream(src));
try {
int length = in.available();
in.mark(length + 1);
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
Source source = new StreamSource(in);
SAXMathBuilder mathBuilder = new SAXMathBuilder();
SAXResult res = new SAXResult(mathBuilder);
transformer.transform(source, res);
String fontname = "Helvetica";
int fontstyle = 0;
int displayfontsize = 12;
int inlinefontsize = 12;

if (mathBuilder.getMathRootElement() == null) {
//not a MathML document
try {
in.reset();
} catch (IOException ioe) {
log.error("Error while resetting ImageInputStream", ioe);
}
return null;
}
final MathBase base = new MathBase(
mathBuilder.getMathRootElement(),
fontname, fontstyle, inlinefontsize,
displayfontsize);
ImageInfo info = new ImageInfo(uri, "text/mathml");
final ImageSize size = new ImageSize();
size.setSizeInMillipoints(
Math.round(base.getWidth() * 1000),
Math.round(base.getHeight() * 1000));
//Set the resolution to that of the FOUserAgent
size.setResolution(context.getSourceResolution());
size.calcPixelsFromSize();
info.setSize(size);

Graphics2DImagePainter painter = new Graphics2DImagePainter() {

public Dimension getImageSize() {
return size.getDimensionMpt();
}

public void paint(Graphics2D g2d, Rectangle2D area) {
base.paint(g2d);
}
};
//The whole image had to be loaded for this, so keep it
Image image = new ImageGraphics2D(info, painter);
info.getCustomObjects().put(ImageInfo.ORIGINAL_IMAGE, image);
return info;
} catch (NoClassDefFoundError ncdfe) {
try {
in.reset();
} catch (IOException ioe) {
// we're more interested in the original exception
}
jeuclidAvailable = false;
log.warn("JEuclid not in class path", ncdfe);
return null;
} catch (IOException e) {
// If the MathML 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 MathML 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;
} catch (TransformerException e) {
try {
in.reset();
} catch (IOException ioe) {
// we're more interested in the original exception
}
log.debug("Error while trying to parsing a MathML file: "
+ e.getMessage());
return null;
}
}
}

}

+ 1
- 0
examples/plan/resources/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImagePreloader View File

@@ -0,0 +1 @@
org.apache.fop.plan.PreloaderPlan

+ 9
- 14
examples/plan/src/org/apache/fop/plan/PlanElement.java View File

@@ -21,14 +21,15 @@ package org.apache.fop.plan;

import java.awt.geom.Point2D;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;

import org.w3c.dom.Document;

import org.xml.sax.Attributes;
import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;

/**
* This class defines the plan element.
*/
@@ -46,9 +47,7 @@ public class PlanElement extends PlanObj {
super(parent);
}

/**
* @see org.apache.fop.fo.FONode#processNode
*/
/** {@inheritDoc} */
public void processNode(String elementName, Locator locator,
Attributes attlist, PropertyList propertyList)
throws FOPException {
@@ -79,15 +78,13 @@ public class PlanElement extends PlanObj {

}

/**
* @see org.apache.fop.fo.XMLObj#getDOMDocument()
*/
/** {@inheritDoc} */
public Document getDOMDocument() {
convertToSVG();
return doc;
}

/** @see org.apache.fop.fo.FONode#getNamespaceURI() */
/** {@inheritDoc} */
public String getNamespaceURI() {
if (svgDoc == null) {
return PlanElementMapping.NAMESPACE;
@@ -95,9 +92,7 @@ public class PlanElement extends PlanObj {
return "http://www.w3.org/2000/svg";
}

/**
* @see org.apache.fop.fo.XMLObj#getDimension(Point2D)
*/
/** {@inheritDoc} */
public Point2D getDimension(Point2D view) {
convertToSVG();
return new Point2D.Float(width, height);

+ 5
- 29
examples/plan/src/org/apache/fop/plan/PlanElementMapping.java View File

@@ -19,12 +19,10 @@
package org.apache.fop.plan;

import org.apache.fop.fo.FONode;
import org.apache.fop.fo.ElementMapping;
import org.apache.fop.image.analyser.XMLReader;
import org.apache.fop.image.FopImage;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;

import org.apache.fop.fo.ElementMapping;
import org.apache.fop.fo.FONode;

/**
* This class provides the element mapping for FOP.
@@ -39,19 +37,17 @@ public class PlanElementMapping extends ElementMapping {
this.namespaceURI = NAMESPACE;
}

/** @see org.apache.fop.fo.ElementMapping#getDOMImplementation() */
/** {@inheritDoc} */
public DOMImplementation getDOMImplementation() {
return getDefaultDOMImplementation();
}

/** @see org.apache.fop.fo.ElementMapping#initialize() */
/** {@inheritDoc} */
protected void initialize() {
if (foObjs == null) {
foObjs = new java.util.HashMap();
foObjs.put("plan", new PE());
foObjs.put(DEFAULT, new PlanMaker());

XMLReader.setConverter(this.namespaceURI, new PlanConverter());
}
}

@@ -67,24 +63,4 @@ public class PlanElementMapping extends ElementMapping {
}
}

static class PlanConverter implements XMLReader.Converter {
public FopImage.ImageInfo convert(Document doc) {
try {
PlanRenderer pr = new PlanRenderer();
pr.setFontInfo("Helvetica", 12);
FopImage.ImageInfo info = new FopImage.ImageInfo();
info.data = pr.createSVGDocument(doc);
info.width = (int)pr.getWidth();
info.height = (int)pr.getHeight();
info.mimeType = "image/svg+xml";
info.str = "http://www.w3.org/2000/svg";
return info;
} catch (Throwable t) {
/**@todo Log this properly! */
}
return null;
}
}

}

+ 2
- 2
examples/plan/src/org/apache/fop/plan/PlanObj.java View File

@@ -38,12 +38,12 @@ public class PlanObj extends XMLObj {
super(parent);
}

/** @see org.apache.fop.fo.FONode#getNamespaceURI() */
/** {@inheritDoc} */
public String getNamespaceURI() {
return PlanElementMapping.NAMESPACE;
}

/** @see org.apache.fop.fo.FONode#getNormalNamespacePrefix() */
/** {@inheritDoc} */
public String getNormalNamespacePrefix() {
return "plan";
}

+ 114
- 0
examples/plan/src/org/apache/fop/plan/PreloaderPlan.java View File

@@ -0,0 +1,114 @@
/*
* 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.plan;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Document;

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.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.fop.util.UnclosableInputStream;

/**
* Image preloader for Plan images.
*/
public class PreloaderPlan extends AbstractImagePreloader {

/** Logger instance */
private static Log log = LogFactory.getLog(PreloaderPlan.class);

/** {@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 = getImage(uri, src, context);
if (info != null) {
ImageUtil.closeQuietly(src); //Image is fully read
}
return info;
}

private ImageInfo getImage(String uri, Source src, ImageContext context) {

InputStream in = new UnclosableInputStream(ImageUtil.needInputStream(src));
try {
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
Source source = new StreamSource(in);
DOMResult res = new DOMResult();
transformer.transform(source, res);
//Have to render the plan to know its size
PlanRenderer pr = new PlanRenderer();
Document svgDoc = pr.createSVGDocument((Document)res.getNode());
float width = pr.getWidth();
float height = pr.getHeight();
//Return converted SVG image
ImageInfo info = new ImageInfo(uri, "image/svg+xml");
final 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
Image image = new ImageXMLDOM(info, svgDoc,
svgDoc.getDocumentElement().getNamespaceURI());
info.getCustomObjects().put(ImageInfo.ORIGINAL_IMAGE, image);
return info;
} catch (TransformerException e) {
try {
in.reset();
} catch (IOException ioe) {
// we're more interested in the original exception
}
log.debug("Error while trying to parsing a Plan file: "
+ e.getMessage());
return null;
}
}

}

+ 2
- 1
fop.bat View File

@@ -56,10 +56,11 @@ set LOCALCLASSPATH=%LOCAL_FOP_HOME%build\fop.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LOCAL_FOP_HOME%build\fop-sandbox.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LOCAL_FOP_HOME%build\fop-hyph.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\xml-apis-1.3.02.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\xml-apis-ext.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\xercesImpl-2.7.1.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\xalan-2.7.0.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\serializer-2.7.0.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\batik-all-1.6.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\batik-all-1.7svn.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\xmlgraphics-commons-1.3svn.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\avalon-framework-4.2.0.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\commons-io-1.3.1.jar

+ 13
- 0
lib/README.txt View File

@@ -51,6 +51,19 @@ Normal Dependencies
Apache License v2.0

- Apache XML Commons Externals

xml-apis-ext-*.jar
http://xml.apache.org/commons/components/external/
(additional DOM APIs from W3C, like SVG, SMIL and Simple API for CSS)
Apache License v2.0 (applies to the distribution)
W3C Software Notice and License (applies to the various DOM Java bindings)
W3C Document License (applies to the DOM documentation)
http://www.w3.org/Consortium/Legal/copyright-software
http://www.w3.org/Consortium/Legal/copyright-documents
http://www.w3.org/Consortium/Legal/



Special Dependencies

BIN
lib/batik-all-1.6.jar View File


BIN
lib/batik-all-1.7.jar View File


+ 13
- 3
lib/batik.NOTICE.txt View File

@@ -1,8 +1,18 @@
This product includes software developed by
Apache Batik
Copyright 1999-2007 The Apache Software Foundation

This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).

This software contains code from the World Wide Web Consortium (W3C) for the
Document Object Model API (DOM API) and SVG Document Type Definition (DTD).

This software contains code from the International Organisation for Standardization
for the definition of character entities used in the software's documentation.
This software contains code from the International Organisation for
Standardization for the definition of character entities used in the software's
documentation.

This product includes images from the Tango Desktop Project
(http://tango.freedesktop.org/).

This product includes images from the Pasodoble Icon Theme
(http://www.jesusda.com/projects/pasodoble).

BIN
lib/xml-apis-ext.jar View File


BIN
lib/xmlgraphics-commons-1.3svn.jar View File


+ 5
- 0
src/java/META-INF/services/org.apache.fop.render.pdf.PDFImageHandler View File

@@ -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

+ 2
- 0
src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageConverter View File

@@ -0,0 +1,2 @@
org.apache.fop.image.loader.batik.ImageConverterSVG2G2D
org.apache.fop.image.loader.batik.ImageConverterWMF2G2D

+ 2
- 0
src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageLoaderFactory View File

@@ -0,0 +1,2 @@
org.apache.fop.image.loader.batik.ImageLoaderFactorySVG
org.apache.fop.image.loader.batik.ImageLoaderFactoryWMF

+ 2
- 0
src/java/META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImagePreloader View File

@@ -0,0 +1,2 @@
org.apache.fop.image.loader.batik.PreloaderWMF
org.apache.fop.image.loader.batik.PreloaderSVG

+ 17
- 4
src/java/org/apache/fop/apps/FOURIResolver.java View File

@@ -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);

+ 29
- 2
src/java/org/apache/fop/apps/FOUserAgent.java View File

@@ -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)


+ 20
- 4
src/java/org/apache/fop/apps/FopFactory.java View File

@@ -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();
@@ -292,6 +299,14 @@ public class FopFactory {
return this.imageFactory;
}

/**
* 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);
}
}

}

+ 8
- 14
src/java/org/apache/fop/area/AreaTreeHandler.java View File

@@ -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();

+ 16
- 17
src/java/org/apache/fop/area/AreaTreeParser.java View File

@@ -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) {

+ 10
- 9
src/java/org/apache/fop/area/Trait.java View File

@@ -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;
}

/**

+ 40
- 8
src/java/org/apache/fop/cli/CommandLineOptions.java View File

@@ -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"

+ 60
- 0
src/java/org/apache/fop/cli/ImageInputHandler.java View File

@@ -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;
}

}

+ 27
- 6
src/java/org/apache/fop/cli/InputHandler.java View File

@@ -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

@@ -131,6 +132,26 @@ public class InputHandler implements ErrorListener, Renderable {
transformTo(res);
}
/**
* 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
@@ -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);

+ 45
- 0
src/java/org/apache/fop/cli/image2fo.xsl View File

@@ -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>

+ 5
- 10
src/java/org/apache/fop/fo/FOTreeBuilder.java View File

@@ -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 + ")");
}

+ 27
- 16
src/java/org/apache/fop/fo/flow/ExternalGraphic.java View File

@@ -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
}

+ 5
- 9
src/java/org/apache/fop/fo/pagination/Root.java View File

@@ -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)+)");
}
}


+ 18
- 17
src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java View File

@@ -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. */

+ 41
- 0
src/java/org/apache/fop/image/loader/batik/BatikUtil.java View File

@@ -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;
}
}

+ 120
- 0
src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java View File

@@ -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;
}

}

+ 107
- 0
src/java/org/apache/fop/image/loader/batik/ImageConverterWMF2G2D.java View File

@@ -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.");
}
}
}
}

+ 63
- 0
src/java/org/apache/fop/image/loader/batik/ImageLoaderFactorySVG.java View File

@@ -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();
}

}

+ 62
- 0
src/java/org/apache/fop/image/loader/batik/ImageLoaderFactoryWMF.java View File

@@ -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();
}

}

+ 78
- 0
src/java/org/apache/fop/image/loader/batik/ImageLoaderSVG.java View File

@@ -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;
}

}

+ 70
- 0
src/java/org/apache/fop/image/loader/batik/ImageLoaderWMF.java View File

@@ -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;
}

}

+ 69
- 0
src/java/org/apache/fop/image/loader/batik/ImageWMF.java View File

@@ -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;
}
}

+ 182
- 0
src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java View File

@@ -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;
}
}
}

}

+ 142
- 0
src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java View File

@@ -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;
}
}
}

}

+ 26
- 0
src/java/org/apache/fop/image/loader/batik/package.html View File

@@ -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>

+ 75
- 30
src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java View File

@@ -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);


+ 8
- 9
src/java/org/apache/fop/layoutmgr/TraitSetter.java View File

@@ -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 {

+ 143
- 47
src/java/org/apache/fop/layoutmgr/inline/ImageLayout.java View File

@@ -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;
}

+ 181
- 0
src/java/org/apache/fop/pdf/AlphaRasterImage.java View File

@@ -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;
}

}



+ 14
- 13
src/java/org/apache/fop/pdf/BitmapImage.java View File

@@ -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

+ 4
- 4
src/java/org/apache/fop/pdf/FlateFilter.java View File

@@ -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;

+ 0
- 3
src/java/org/apache/fop/pdf/PDFFactory.java View File

@@ -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);

+ 5
- 0
src/java/org/apache/fop/pdf/PDFFilterList.java View File

@@ -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());

+ 1
- 3
src/java/org/apache/fop/pdf/PDFICCStream.java View File

@@ -66,9 +66,7 @@ public class PDFICCStream extends PDFStream {
return length;
}
/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
protected void outputRawStreamData(OutputStream out) throws IOException {
cp.write(out);
}

+ 11
- 3
src/java/org/apache/fop/pdf/PDFImage.java View File

@@ -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.
@@ -129,6 +129,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.
*

+ 14
- 7
src/java/org/apache/fop/pdf/PDFImageXObject.java View File

@@ -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} */

+ 19
- 7
src/java/org/apache/fop/pdf/PDFObject.java View File

@@ -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()));

+ 3
- 0
src/java/org/apache/fop/pdf/PDFReference.java View File

@@ -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;
}


+ 20
- 6
src/java/org/apache/fop/pdf/PDFText.java View File

@@ -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,19 +145,33 @@ 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

+ 13
- 13
src/java/org/apache/fop/render/AbstractGenericSVGHandler.java View File

@@ -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;

+ 3
- 3
src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java View File

@@ -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));

+ 43
- 45
src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java View File

@@ -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();
}
}


+ 1
- 1
src/java/org/apache/fop/render/Graphics2DAdapter.java View File

@@ -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;

+ 3
- 18
src/java/org/apache/fop/render/Graphics2DImagePainter.java View File

@@ -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();
}

+ 2
- 1
src/java/org/apache/fop/render/afp/AFPGraphics2DAdapter.java View File

@@ -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;

/**

+ 143
- 41
src/java/org/apache/fop/render/afp/AFPRenderer.java View File

@@ -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(),

+ 13
- 19
src/java/org/apache/fop/render/java2d/Java2DGraphics2DAdapter.java View File

@@ -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();
}
}

+ 61
- 80
src/java/org/apache/fop/render/java2d/Java2DRenderer.java View File

@@ -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;
}

+ 6
- 3
src/java/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java View File

@@ -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());

+ 131
- 124
src/java/org/apache/fop/render/pcl/PCLRenderer.java View File

@@ -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;
@@ -134,6 +135,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.
*/
@@ -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;
}

+ 17
- 0
src/java/org/apache/fop/render/pcl/PCLRendererContext.java View File

@@ -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)));
}

}

+ 32
- 0
src/java/org/apache/fop/render/pcl/PCLRendererContextConstants.java View File

@@ -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";

}

+ 8
- 0
src/java/org/apache/fop/render/pcl/PCLSVGHandler.java View File

@@ -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);
}
}


+ 200
- 0
src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java View File

@@ -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;
}

}


+ 0
- 374
src/java/org/apache/fop/render/pdf/FopPDFImage.java View File

@@ -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;
}
}

}


+ 110
- 0
src/java/org/apache/fop/render/pdf/ImageRawCCITTFaxAdapter.java View File

@@ -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;
}

}


+ 96
- 0
src/java/org/apache/fop/render/pdf/ImageRawJPEGAdapter.java View File

@@ -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;
}

}


+ 249
- 0
src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java View File

@@ -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;
}

}


+ 2
- 1
src/java/org/apache/fop/render/pdf/PDFGraphics2DAdapter.java View File

@@ -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;

+ 33
- 11
src/java/org/apache/fop/render/pdf/PDFImageHandler.java View File

@@ -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;
}

+ 68
- 0
src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java View File

@@ -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;
}

}

+ 83
- 0
src/java/org/apache/fop/render/pdf/PDFImageHandlerRawCCITTFax.java View File

@@ -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;
}

}

+ 83
- 0
src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java View File

@@ -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;
}

}

+ 77
- 7
src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java View File

@@ -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,24 +96,73 @@ 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.

+ 84
- 0
src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java View File

@@ -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;
}

}

+ 74
- 0
src/java/org/apache/fop/render/pdf/PDFImageHandlerXML.java View File

@@ -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;
}

}

+ 71
- 89
src/java/org/apache/fop/render/pdf/PDFRenderer.java View File

@@ -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(

+ 1
- 1
src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/

/* $Id: $ */
/* $Id$ */

package org.apache.fop.render.pdf;


+ 28
- 23
src/java/org/apache/fop/render/pdf/PDFSVGHandler.java View File

@@ -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;

+ 71
- 0
src/java/org/apache/fop/render/ps/ImageEncoderCCITTFax.java View File

@@ -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";
}
}

+ 51
- 0
src/java/org/apache/fop/render/ps/ImageEncoderJPEG.java View File

@@ -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";
}
}

+ 23
- 11
src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java View File

@@ -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

+ 5
- 95
src/java/org/apache/fop/render/ps/PSImageUtils.java View File

@@ -19,113 +19,21 @@
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 {

/** logging instance */
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
@@ -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,

+ 183
- 49
src/java/org/apache/fop/render/ps/PSRenderer.java View File

@@ -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 {

+ 0
- 0
src/java/org/apache/fop/render/ps/PSSupportedFlavors.java View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save