[Fixes #48][2.4.x] Reinstate png, jpg support. Removes imagen-legacy dependency.#81
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR replaces the existing JAI/Imagen-based TIFF mosaic assembly with a Java2D/ImageIO implementation and removes a legacy Imagen codec dependency, aiming to reduce reliance on the legacy codec stack and simplify image composition.
Changes:
- Reworked mosaic generation to use
BufferedImage+Graphics2Ddrawing rather thanImageNmosaic/translate operations. - Enabled ImageIO disk cache usage during mosaic generation.
- Removed
imagen-legacy-codec-corefrom Maven dependencies.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| src/main/java/org/mapfish/print/output/FileCachingJaiMosaicOutputFactory.java | Replaces Imagen mosaic pipeline with Java2D/ImageIO-based mosaic creation and disk caching. |
| pom.xml | Drops legacy Imagen codec dependency corresponding to the removed codec usage. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (images == null || images.isEmpty()) { | ||
| return; | ||
| } |
| int totalHeight = 0; | ||
| int maxWidth = 0; | ||
|
|
||
| for (ImageInfo imageinfo : images) { | ||
| totalHeight += imageinfo.height + MARGIN; | ||
| if (maxWidth < imageinfo.width) { | ||
| maxWidth = (int) imageinfo.width; | ||
| } | ||
| } |
| g2d.drawImage(pageImage, 0, currentY, null); | ||
| currentY += imageinfo.height + MARGIN; |
| // Explicitly enable ImageIO disk caching. This honors the original intent | ||
| // of the "FileCaching" class by preventing stream data from flooding the RAM. | ||
| ImageIO.setUseCache(true); |
There was a problem hiding this comment.
From the javadoc, this does not seem necessary, true is the default (also, it shoud be done once at startup, not for every image write):
Sets a flag indicating whether a disk-based cache file should be used when creating ImageInputStreams and ImageOutputStreams.
When reading from a standard InputStream, it may be necessary to save previously read information in a cache since the underlying stream does not allow data to be re-read. Similarly, when writing to a standard OutputStream, a cache may be used to allow a previously written value to be changed before flushing it to the final destination.
The cache may reside in main memory or on disk. Setting this flag to false disallows the use of disk for future streams, which may be advantageous when working with small images, as the overhead of creating and destroying files is removed.
On startup, the value is set to true.
|
|
||
| if (pageImage == null) { | ||
| g2d.dispose(); | ||
| throw new IllegalArgumentException("Cannot read image: " + imageinfo.imageFile.getAbsolutePath() + " - missing ImageIO plugin for this format."); |
|
|
||
| pbMosaic.addSource(translated); | ||
| i++; | ||
| LOGGER.debug("Adding page image " + i + " bounds: [0," + currentY + " " + pageImage.getWidth() + "," + (currentY + pageImage.getHeight()) + "]"); |
| // Explicitly enable ImageIO disk caching. This honors the original intent | ||
| // of the "FileCaching" class by preventing stream data from flooding the RAM. | ||
| ImageIO.setUseCache(true); |
There was a problem hiding this comment.
From the javadoc, this does not seem necessary, true is the default (also, it shoud be done once at startup, not for every image write):
Sets a flag indicating whether a disk-based cache file should be used when creating ImageInputStreams and ImageOutputStreams.
When reading from a standard InputStream, it may be necessary to save previously read information in a cache since the underlying stream does not allow data to be re-read. Similarly, when writing to a standard OutputStream, a cache may be used to allow a previously written value to be changed before flushing it to the final destination.
The cache may reside in main memory or on disk. Setting this flag to false disallows the use of disk for future streams, which may be advantageous when working with small images, as the overhead of creating and destroying files is removed.
On startup, the value is set to true.
| i++; | ||
| LOGGER.debug("Adding page image " + i + " bounds: [" + 0 + "," + height + " " + source.getWidth() + "," + (height + source.getHeight()) + "]"); | ||
| RenderedOp translated = translateImage(height, source); | ||
| BufferedImage pageImage = ImageIO.read(imageinfo.imageFile); |
There was a problem hiding this comment.
This is a serious regression, it materializes in memory all the input images instead of allowing a tiled approach.
The class was designed to use JAI/ImageN exactly to avoid materializing everything in memory.
I suggest to keep the ImageIO writing bits while retaining the ImageN code (and fix it as necessary).
For reading use ImageN ImageRead operation (mimicks what GT/GS do), it can perform deferred and tiled loading and uses ImageIO t actually read the tiles.
You'll need to add the dependency in the POM.
| <groupId>org.eclipse.imagen</groupId> | ||
| <artifactId>imagen-core</artifactId> | ||
| </dependency> | ||
| <dependency> |
There was a problem hiding this comment.
Yes, not really needed, ImageIO direct writing is fine.
| TileCache cache = ImageN.createTileCache((long) (height * width * 400)); | ||
| RenderingHints hints = new RenderingHints(ImageN.KEY_TILE_CACHE, cache); | ||
| RenderedOp mosaic = ImageN.create("mosaic", pbMosaic, hints); |
| } | ||
|
|
||
| RenderedOp mosaic = ImageN.create("mosaic", pbMosaic); | ||
| TileCache cache = ImageN.createTileCache((long) (height * width * 400)); |
| if(LOGGER.isDebugEnabled()) { | ||
| LOGGER.debug("Adding page image " + i + " bounds: [" + 0 + "," + height + " " + source.getWidth() + "," + (height + source.getHeight()) + "]"); | ||
| } |
| pb.add(null); | ||
| pb.add(null); | ||
| RenderedOp source = ImageN.create("TIFF", pb); | ||
| ParameterBlockImageN pb = new ParameterBlockImageN("ImageRead"); |
There was a problem hiding this comment.
I'm a bit confused here... this is the right code, but I don't see a new dependency on the ImageN imageread module. Maybe it is included transitively?
There was a problem hiding this comment.
@aaime
The dependency:tree says
- org.geotools:gt-render:jar:34.0:compile
- org.geotools:gt-coverage:jar:34.0:compile
- org.eclipse.imagen:imageread:jar:0.9.0:compile
- org.geotools:gt-coverage:jar:34.0:compile
Full dependency tree
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------< org.mapfish.print:print-lib >---------------------
[INFO] Building print-lib 2.4-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- dependency:3.7.0:tree (default-cli) @ print-lib ---
[INFO] org.mapfish.print:print-lib:jar:2.4-SNAPSHOT
[INFO] +- org.geotools:gt-epsg-hsql:jar:34.0:compile
[INFO] | +- org.geotools:gt-referencing:jar:34.0:compile
[INFO] | | +- org.ejml:ejml-ddense:jar:0.41:compile
[INFO] | | | \- org.ejml:ejml-core:jar:0.41:compile
[INFO] | | +- commons-pool:commons-pool:jar:1.5.4:compile
[INFO] | | +- org.geotools:gt-metadata:jar:34.0:compile
[INFO] | | | +- org.geotools:gt-api:jar:34.0:compile
[INFO] | | | | +- systems.uom:systems-common:jar:2.1:compile
[INFO] | | | | | +- si.uom:si-quantity:jar:2.1:compile
[INFO] | | | | | \- si.uom:si-units:jar:2.1:compile
[INFO] | | | | | \- jakarta.annotation:jakarta.annotation-api:jar:1.3.4:compile
[INFO] | | | | \- tech.units:indriya:jar:2.2:compile
[INFO] | | | | +- tech.uom.lib:uom-lib-common:jar:2.2:compile
[INFO] | | | | +- jakarta.inject:jakarta.inject-api:jar:2.0.1:compile
[INFO] | | | | \- org.apiguardian:apiguardian-api:jar:1.1.2:compile
[INFO] | | | +- org.apache.commons:commons-lang3:jar:3.18.0:compile
[INFO] | | | \- org.geotools.ogc:net.opengis.ows:jar:34.0:compile
[INFO] | | | +- org.geotools.ogc:org.w3.xlink:jar:34.0:compile
[INFO] | | | +- org.eclipse.emf:org.eclipse.emf.common:jar:2.15.0:compile
[INFO] | | | +- org.eclipse.emf:org.eclipse.emf.ecore:jar:2.15.0:compile
[INFO] | | | \- org.eclipse.emf:org.eclipse.emf.ecore.xmi:jar:2.15.0:compile
[INFO] | | +- it.geosolutions.jgridshift:jgridshift-core:jar:1.3:compile
[INFO] | | \- net.sf.geographiclib:GeographicLib-Java:jar:1.49:compile
[INFO] | \- org.hsqldb:hsqldb:jar:2.7.2:compile
[INFO] +- org.geotools:gt-render:jar:34.0:compile
[INFO] | +- javax.measure:unit-api:jar:2.2:compile
[INFO] | +- org.geotools:gt-main:jar:34.0:compile
[INFO] | | +- org.geotools:gt-http:jar:34.0:compile
[INFO] | | +- org.apache.commons:commons-text:jar:1.13.0:compile
[INFO] | | +- com.google.re2j:re2j:jar:1.8:compile
[INFO] | | \- org.eclipse.imagen:utilities:jar:0.9.0:compile
[INFO] | +- org.geotools:gt-coverage:jar:34.0:compile
[INFO] | | +- it.geosolutions.imageio-ext:imageio-ext-tiff:jar:2.0.0:compile
[INFO] | | | +- it.geosolutions.imageio-ext:imageio-ext-utilities:jar:2.0.0:compile
[INFO] | | | | \- org.eclipse.imagen:rendered-image-browser:jar:0.9.0:compile
[INFO] | | | +- it.geosolutions.imageio-ext:imageio-ext-geocore:jar:2.0.0:compile
[INFO] | | | | +- it.geosolutions.imageio-ext:imageio-ext-streams:jar:2.0.0:compile
[INFO] | | | | +- javax.xml.bind:jaxb-api:jar:2.4.0-b180830.0359:compile
[INFO] | | | | +- org.glassfish.jaxb:jaxb-runtime:jar:2.4.0-b180830.0438:runtime
[INFO] | | | | | +- org.glassfish.jaxb:txw2:jar:2.4.0-b180830.0438:runtime
[INFO] | | | | | +- com.sun.istack:istack-commons-runtime:jar:3.0.7:runtime
[INFO] | | | | | +- org.jvnet.staxex:stax-ex:jar:1.8:runtime
[INFO] | | | | | \- com.sun.xml.fastinfoset:FastInfoset:jar:1.2.15:runtime
[INFO] | | | | \- javax.activation:javax.activation-api:jar:1.2.0:compile
[INFO] | | | \- io.airlift:aircompressor:jar:0.27:compile
[INFO] | | +- org.eclipse.imagen:affine:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:algebra:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:bandmerge:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:bandselect:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:bandcombine:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:border:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:buffer:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:crop:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:iterators:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:lookup:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:mosaic:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:nullop:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:rescale:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:scale:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:scale2:jar:0.9.0:compile
[INFO] | | | \- org.huldra.math:bigint:jar:0.7.1:compile
[INFO] | | +- org.eclipse.imagen:stats:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:translate:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:warp:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:zonal:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:binarize:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:format:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:colorconvert:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:errordiffusion:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:orderdither:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:colorindexer:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:imagefunction:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:piecewise:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:classifier:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:rlookup:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:vectorbin:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:shadedrelief:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:imageread:jar:0.9.0:compile
[INFO] | | +- org.eclipse.imagen:convolve:jar:0.9.0:compile
[INFO] | | \- commons-io:commons-io:jar:2.19.0:compile
[INFO] | +- org.geotools:gt-cql:jar:34.0:compile
[INFO] | \- com.conversantmedia:disruptor:jar:1.2.15:compile
[INFO] +- com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:jar:2.19.0:compile
[INFO] | +- com.fasterxml.jackson.core:jackson-databind:jar:2.19.0:compile
[INFO] | | \- com.fasterxml.jackson.core:jackson-annotations:jar:2.19.0:compile
[INFO] | +- org.yaml:snakeyaml:jar:2.4:compile
[INFO] | \- com.fasterxml.jackson.core:jackson-core:jar:2.19.0:compile
[INFO] +- org.locationtech.jts:jts-core:jar:1.20.0:compile
[INFO] +- javax.servlet:servlet-api:jar:2.5:provided
[INFO] +- org.apache.logging.log4j:log4j-core:jar:2.24.3:compile
[INFO] +- org.apache.logging.log4j:log4j-api:jar:2.24.3:compile
[INFO] +- com.google.guava:guava:jar:33.4.8-jre:compile
[INFO] | +- com.google.guava:failureaccess:jar:1.0.3:compile
[INFO] | +- com.google.guava:listenablefuture:jar:9999.0-empty-to-avoid-conflict-with-guava:compile
[INFO] | +- org.jspecify:jspecify:jar:1.0.0:compile
[INFO] | +- com.google.errorprone:error_prone_annotations:jar:2.36.0:compile
[INFO] | \- com.google.j2objc:j2objc-annotations:jar:3.0.0:compile
[INFO] +- org.apache.pdfbox:pdfbox:jar:2.0.34:compile
[INFO] | +- org.apache.pdfbox:fontbox:jar:2.0.34:compile
[INFO] | \- commons-logging:commons-logging:jar:1.3.5:compile
[INFO] +- org.apache.pdfbox:pdfbox-tools:jar:2.0.34:compile
[INFO] | \- org.apache.pdfbox:pdfbox-debugger:jar:2.0.34:compile
[INFO] | \- org.bouncycastle:bcpkix-jdk18on:jar:1.80:compile
[INFO] | \- org.bouncycastle:bcutil-jdk18on:jar:1.80.2:compile
[INFO] | \- org.bouncycastle:bcprov-jdk18on:jar:1.80.2:compile
[INFO] +- javax.media:jai_imageio:jar:1.1:compile
[INFO] +- commons-httpclient:commons-httpclient:jar:3.1:compile
[INFO] | \- commons-codec:commons-codec:jar:1.2:compile
[INFO] +- org.mockito:mockito-core:jar:5.15.2:test
[INFO] | +- net.bytebuddy:byte-buddy:jar:1.15.11:test
[INFO] | +- net.bytebuddy:byte-buddy-agent:jar:1.15.11:test
[INFO] | \- org.objenesis:objenesis:jar:3.3:test
[INFO] +- org.apache.xmlgraphics:batik-transcoder:jar:1.18:compile
[INFO] | +- org.apache.xmlgraphics:batik-anim:jar:1.18:compile
[INFO] | | +- org.apache.xmlgraphics:batik-css:jar:1.18:compile
[INFO] | | +- org.apache.xmlgraphics:batik-ext:jar:1.18:compile
[INFO] | | +- org.apache.xmlgraphics:batik-parser:jar:1.18:compile
[INFO] | | \- org.apache.xmlgraphics:batik-svg-dom:jar:1.18:compile
[INFO] | +- org.apache.xmlgraphics:batik-awt-util:jar:1.18:compile
[INFO] | | \- org.apache.xmlgraphics:xmlgraphics-commons:jar:2.10:compile
[INFO] | +- org.apache.xmlgraphics:batik-bridge:jar:1.18:compile
[INFO] | | \- org.apache.xmlgraphics:batik-script:jar:1.18:compile
[INFO] | +- org.apache.xmlgraphics:batik-dom:jar:1.18:compile
[INFO] | +- org.apache.xmlgraphics:batik-gvt:jar:1.18:compile
[INFO] | +- org.apache.xmlgraphics:batik-shared-resources:jar:1.18:compile
[INFO] | +- org.apache.xmlgraphics:batik-svggen:jar:1.18:compile
[INFO] | +- org.apache.xmlgraphics:batik-util:jar:1.18:compile
[INFO] | | +- org.apache.xmlgraphics:batik-constants:jar:1.18:compile
[INFO] | | \- org.apache.xmlgraphics:batik-i18n:jar:1.18:compile
[INFO] | +- org.apache.xmlgraphics:batik-xml:jar:1.18:compile
[INFO] | \- xml-apis:xml-apis-ext:jar:1.3.04:compile
[INFO] +- xerces:xercesImpl:jar:2.7.1:compile
[INFO] +- com.github.librepdf:openpdf:jar:1.3.26:compile
[INFO] | \- com.google.code.findbugs:jsr305:jar:3.0.2:compile
[INFO] +- org.json:json:jar:20231013:compile
[INFO] +- org.eclipse.imagen:imagen-core:jar:0.9.0:compile
[INFO] +- org.springframework:spring-context:jar:5.3.39:compile
[INFO] | +- org.springframework:spring-aop:jar:5.3.39:compile
[INFO] | +- org.springframework:spring-beans:jar:5.3.39:compile
[INFO] | +- org.springframework:spring-core:jar:5.3.39:compile
[INFO] | | \- org.springframework:spring-jcl:jar:5.3.39:compile
[INFO] | \- org.springframework:spring-expression:jar:5.3.39:compile
[INFO] +- org.springframework:spring-web:jar:5.3.39:compile
[INFO] +- xalan:xalan:jar:2.7.0:compile
[INFO] | \- xml-apis:xml-apis:jar:1.0.b2:compile
[INFO] +- io.dropwizard.metrics:metrics-core:jar:4.2.30:compile
[INFO] | \- org.slf4j:slf4j-api:jar:2.0.16:compile
[INFO] +- io.dropwizard.metrics:metrics-servlet:jar:4.2.30:compile
[INFO] +- io.dropwizard.metrics:metrics-httpclient:jar:4.2.30:compile
[INFO] | +- org.apache.httpcomponents:httpcore:jar:4.4.16:compile
[INFO] | \- org.apache.httpcomponents:httpclient:jar:4.5.14:compile
[INFO] +- io.dropwizard.metrics:metrics-servlets:jar:4.2.30:compile
[INFO] | +- io.dropwizard.metrics:metrics-healthchecks:jar:4.2.30:compile
[INFO] | +- io.dropwizard.metrics:metrics-json:jar:4.2.30:compile
[INFO] | +- io.dropwizard.metrics:metrics-jvm:jar:4.2.30:compile
[INFO] | \- com.helger:profiler:jar:1.1.1:compile
[INFO] +- io.dropwizard.metrics:metrics-log4j2:jar:4.2.30:compile
[INFO] +- io.dropwizard.metrics:metrics-jmx:jar:4.2.30:compile
[INFO] \- junit:junit:jar:4.7:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.219 s
[INFO] Finished at: 2026-06-15T16:35:14+02:00
[INFO] ------------------------------------------------------------------------
Key changes:
imagen-legacy-codec-coredependency to resolve downstream project conflicts.FileSeekableStreamwith standardjavax.imageio.ImageIO, utilizingImageIO.setUseCache(true)to maintain disk-backed memory efficiency without needing JAI'sTileCache.FileCachingJaiMosaicOutputFactory) to use standardjava.awt.Graphics2DandBufferedImageinstead of JAI'sRenderedOpandParameterBlock.