Releases: css4j/echosvg
2.0
All users are encouraged to upgrade, as the 1.x branch will now only receive security updates. Version 2.0 is new, but it passes far more tests than 1.2.4.
Highlights
Advanced CSS
Adds native support for several CSS improvements, which until now required the use of the Transcoding Helper but now are available out-of-the-box.
- Custom properties (
var()
function).
fill: var(--my-color, blue);
- The
@property
rule (registered custom properties).
@property --my-length {
syntax: "<length>";
inherits: true;
initial-value: 4px;
}
@supports (color: oklch(67% 0.18 270)) {
g {
--my-color: oklch(45% 0.3 264);
--my-stroke-width: calc(1px + var(--my-length));
}
}
- Level 4 Media Queries, including the
prefers-color-scheme
media feature. As a result, theKEY_PREFERS_COLOR_SCHEME
transcoding hint was added.
@media screen and (300px < width <= 1000px) and (prefers-color-scheme: light) {
text.myclass {
font-size: calc(var(--my-FontSize) + 2pt);
}
}
See also KEY_MEDIA
.
-
The
turn
,Q
,vw
,vh
,vmin
,vmax
,lh
,rlh
,rem
andrex
units. -
calc()
expressions, both in CSS properties/attributes and non-CSS attributes. You can writey = "calc(30% + 2vmin)"
for example, like you'd do with modern web browsers. -
The advanced
attr()
value that was recently implemented by Chromium-based web browsers.
ellipse {
fill: attr(data-color type(<color>), #22a);
}
- The
initial
,unset
andrevert
CSS-wide keywords (this being SVG,revert
is currently handled asunset
).
Standards-compliant Resolution
In addition, it implements a true resolution concept: the resolution is no longer used in CSS unit conversions, matching the standards-compliant behaviour of web browsers. That resolution is also available to CSS Media Queries.
To make it available to the transcoder, the KEY_RESOLUTION_DPI
transcoding hint was added. The old KEY_PIXEL_UNIT_TO_MILLIMETER
transcoding hint can still be used, but is no longer used in CSS unit conversions (only in the encoding phase).
The transcoder module was split in 4 sub-modules: api, svg, svg2svg and tosvg
Sometimes an SVG library is embedded into an executable, and a common concern for both EchoSVG and Batik users in those cases is to make the size of the embedded modules as small as possible.
Notably, in the case of the Transcoder a number of unneeded classes may be included. For an example of such concern see
eclipse-platform/eclipse.platform.swt#1438 (comment)
The current transcoder
module was designed as a monolithic do-it-all package, with users always carrying code that they do not intend to run. For example, the code to convert WMF to SVG was always there even if you just wanted to convert SVG to PNG.
So it was split in several submodules, in a way that backwards compatibility is kept (the old transcoder
module still exists and provides all the classes), so users willing to minimize their dependencies can choose a smaller specific sub-module.
Version 2.0 splits the transcoder in 4 modules:
transcoder-api
(API)transcoder-svg
(SVG to image)transcoder-svg2svg
(SVG to SVG)transcoder-tosvg
(conversions to SVG, currently only WMF to SVG)
In the typical case of rendering SVG as a PNG, the full 2.0 transcoder with dependencies fills a jar of 6.34 MB, while the specific SVG-to-image transcoder becomes a bit smaller (6.04 MB).
The gains are higher for the WMF to SVG case (3.38 MB) or the SVG-to-SVG (2.64 MB).
More flexible DOM (and transcoding from SVG)
Until now, before transcoding a file one has to specify whether it is SVG or HTML via the KEY_DOCUMENT_ELEMENT
and KEY_DOCUMENT_ELEMENT_NAMESPACE_URI
hints. Now the DOM factories use a different procedure, and in consequence those transcoding hints are ignored. For example if you are using the SVG-to-PNG transcoder, it will always look for SVG in any provided document.
However, if the file being processed is HTML instead of XHTML you still have to specify an HTML parser as explained in the wiki.
Transcoding with color profiles
If you transcode an SVG image which uses colors outside of the sRGB color palette (e.g. color(display-p3 1 1 0)
), EchoSVG determines the smallest color gamut that fits your image and subsequently uses it. The color profile is automatically embedded in the resulting image, if needed.
Most of the color conversions are done via the AWT toolkit and, when converting a color to a smaller gamut (where that color isn't represented), it doesn't attempt any gamut mapping. Moreover there are several elements in the SVG specification where the sRGB color space is assumed (e.g. the filter primitives), and if one combines one of those with an out-of-gamut color, the results are less than perfect.
The CSSTranscodingHelper
restricts the used colors to the Display P3 and A98 RGB gamuts, doing an accurate gamut mapping. If your SVG image includes colors outside of those gamuts, you may obtain better results using that tool.
Disclaimer
I only have access to devices with sRGB displays, so haven't visually checked the color-profiled PNG/JPG images. In that sense, the color profile support should be considered as untested. But the profiles are indeed in the images, and the pixel values seem correct.
Upgrading
If your build uses Gradle, do not forget to allow the download of the new dependencies from the Maven repository, with an includeGroupByRegex
or similar:
repositories {
maven {
url = "https://css4j.github.io/maven/"
mavenContent {
releasesOnly()
}
content {
includeGroupByRegex 'io\\.sf\\..*'
// Alternative to the regex:
//includeGroup 'io.sf.carte'
//includeGroup 'io.sf.jclf'
//includeGroup 'io.sf.graphics'
//includeGroup 'io.sf.w3'
}
}
}
If you find any issue upgrading, please check MIGRATING_FROM_BATIK
. Open an issue or discussion if necessary.
2.0 preview 1
This first preview of 2.0 is mainly intended to check how the transcoder module split is received, as it is a potentially controversial change. It could always be reverted or done differently.
Summary of the new features in 2.0:
Support for advanced CSS
Adds native supports for several CSS improvements, which until now required the use of the Transcoder Helper but now are available out-of-the-box.
-
Custom properties (
var()
function). -
The
@property
rule (registered custom properties). -
Media Queries level 4, including the
prefers-color-scheme
media feature. As a result, theKEY_PREFERS_COLOR_SCHEME
transcoding hint was added. -
The
vw
,vh
,vmin
,vmax
,lh
,rlh
,rem
andrex
units. -
calc()
expressions, both in CSS properties/attributes and non-CSS attributes. -
The
initial
,unset
andrevert
CSS-wide keywords (this being SVG,revert
is currently handled asunset
). -
The advanced
attr()
value that Google Chrome 133 is shipping.
In addition to this, it implements a true resolution concept: the resolution is no longer used in CSS unit conversions, matching the standards-compliant behaviour of web browsers. That resolution is also available to CSS Media Queries.
To make it available to the transcoder, the KEY_RESOLUTION_DPI
transcoding hint was added. The old KEY_PIXEL_UNIT_TO_MILLIMETER
transcoding hint can still be used, but is no longer used in CSS unit conversions (only in the encoding phase).
Split the transcoder module in 4 sub-modules: api, svg, svg2svg and tosvg
Sometimes an SVG library is embedded into an executable, and a common concern for both EchoSVG and Batik users in those cases is to make the size of the embedded modules as small as possible.
Notably, in the case of the Transcoder a number of unneeded classes may be included. For an example of such concern see
eclipse-platform/eclipse.platform.swt#1438 (comment)
The current transcoder
module was designed as a monolithic do-it-all package, with users always carrying code that they do not intend to run. For example, the code to convert WMF to SVG was always there even if you just wanted to convert SVG to PNG.
So it was split in several submodules, in a way that backwards compatibility is kept (the old transcoder
module still exists and provides all the classes), so users willing to minimize their dependencies can choose a smaller specific sub-module.
Version 2.0-pre1 splits the transcoder in 4 modules:
transcoder-api
(API)transcoder-svg
(SVG to image)transcoder-svg2svg
(SVG to SVG)transcoder-tosvg
(conversions to SVG, currently only WMF to SVG)
In the typical case of rendering SVG as a PNG, the 2.0-pre1 transcoder with dependencies fills a jar of 6.33 MB, while the specific SVG-to-image transcoder becomes a bit smaller (6.03 MB).
The gains are higher for the WMF to SVG case (3.37 MB) or the SVG-to-SVG (2.59 MB).
More flexible DOM (and transcoding from SVG)
Until now, before transcoding a file one has to specify whether it is SVG or HTML via the KEY_DOCUMENT_ELEMENT
and KEY_DOCUMENT_ELEMENT_NAMESPACE_URI
hints. Now the DOM factories use a different procedure, and in consequence those transcoding hints are ignored. For example if you are using the SVG-to-PNG transcoder, it will always look for SVG in any provided document.
However, if the file being processed is HTML instead of XHTML you still have to specify an HTML parser as explained in the wiki.
Transcoding with color profiles (warning: experimental)
If you transcode an SVG image which uses colors outside of the sRGB color palette (e.g. color(display-p3 1 1 0)
), EchoSVG determines the smallest color gamut that fits your image and subsequently uses it.
Unfortunately the color conversions are done via the AWT toolkit and aren't very precise. Moreover there are several places in the codebase where the sRGB color space is assumed, and the results are less than perfect.
If the SVG that you want to transcode uses color spaces outside of the sRGB gamut, you may want to consider using the CSSTranscodingHelper
instead, as it uses the css4j color conversions which are more accurate (similar results to ColorJS).
1.2.4
A first preview release of 2.0 is imminent, so it is time for a new stable version.
The fixes are much less important than in previous stable versions, but still good to have. The upgrade to css4j 5.1 means that the transcoder helper now has an advanced attr()
support which is expected to be compatible with the forthcoming version 133 of Google Chrome.
Detail of changes
- awt: avoid division by zero in
feTurbulence
processing [BATIK-1102]. - dom: allow creating documents with
null
qualified name inGenericDOMImplementation
. - parser: small performance improvement in
NumberParser.equalsAny
. - util:
NormalizingReader
was silently dropping one character on each call toread(cbuf[])
. - util: make
ParsedURL
andParsedURLData
serializable. - util: use a fixed locale in case conversion when retrieving the decoder factory.
- Gradle: do not depend on compile-only artifacts in the fat jars.
- Make tests compatible with Java 23.
- Tests: test arabic characters.
- Upgrade to css4j 5.1.
- Upgrade to css4j-awt 5.0.
- Upgrade to jclf-text 5.0.2.
- Upgrade to commons-io 2.18.0.
- Upgrade to JUnit 5.11.4.
- Upgrade to GrGit 5.3.0.
- Upgrade to checkstyle 10.21.1.
- Upgrade to dependency-check-gradle 12.0.1.
- Upgrade to gradle-license-report 2.9.
- Upgrade Gradle wrapper to 8.12.1.
- README: use the assignment operator in the Gradle example.
- Bump year to 2025 in NOTICE.
1.2.3
New batch of backports from the master
branch, with SVG 2.0 compliance fixes and color improvements.
Also fixes a rendering crash when relative URLs read from a jar:
file are shorter than 4 characters (for example <use href="#a1">
).
Detail of changes
- bridge: update
<use>
and<image>
nodes on changes to namespacelesshref
attribute. - bridge: detect circularities and non-SVG elements referred by
<use>
. - css: increase the accuracy of color conversions.
- util: do not crash on
jar:
relative URLs of less than 4 characters, avoid string creation. - Tests: create images with the correct resolution in
AbstractImageTranscoderTest
. - Upgrade to css4j 4.4 (which adds support for the
srgb-linear
color space). - Upgrade Gradle wrapper to 8.10.2.
1.2.2
As there is still a long way towards the 2.0 version, several SVG compliance fixes were backported from the master
branch and are made available here, including an important performance improvement.
Detail of changes
- anim,bridge: improve lenient parsing, especially that of paths, polygons and polyline points. Paths and point sets are now only parsed once, even if referenced by multiple
<use>
elements, which fixes an important performance bottleneck. - anim: allow unrecognized SVG elements in
createElementNS()
of SVG 1.1 implementation, aligning it with the 1.2 one. - bridge: give
EMPTY_SHAPE
a smaller footprint. - svggen: be a bit more efficient in allocating the rgb() serialization color buffer.
- i18n: if the resource cannot be loaded, print a warning and return the key.
- Tests: check embedded profiles in ImageComparator.
- Upgrade Gradle wrapper to 8.10.
- Upgrade to JUnit 5.11.0.
- Update RELEASE_HOWTO.md with current practice.
1.2.1
SVG2 compliance fixes
This release brings the latest fixes right before merging the Typed OM patch (the basis for the forthcoming 2.0). Basically contains SVG2 compliance fixes.
This is intended to be the last 1.x release, although maintenance 1.2.x releases may be published if security vulnerabilities are found in the near future.
Detail of changes
- SVG2 compliance for the
viewBox
attribute, includingcalc()
support. - anim: make
SVGOMAnimatedRect.getUnderlyingValue()
less prone to races. - anim,bridge: continue rendering if x/y/width/height attributes of line,image,svg,use are wrong [SVG2].
- bridge: fix the handling of colors with percentage values in alpha channel.
- bridge: fix a resource leak in
BaseScriptingEnvironment
. - codec: improve handling of gray images in
PNGEncodeParam.getDefaultEncodeParam()
. - codec: clean up the usage of
PNGEncodeParam
,PNGDecodeParam
andPNGImageWriterParams
. - transcoder: compute image sizes in CSS context where appropriate [SVG2].
- Gradle: make xml-apis a compile-only dependency.
- Upgrade to css4j 4.3.1.
- Upgrade to wrapper-validation action v4.
1.2
Warning: dependency on xmlgraphics-commons was removed
If you use a Gradle build, be sure to add the following to the repositories
configuration for css4j's Maven repository:
includeGroup 'io.sf.graphics'
The configuration for the repository should look like this:
maven {
url "https://css4j.github.io/maven/"
mavenContent {
releasesOnly()
}
content {
includeGroup 'io.sf.graphics'
includeGroup 'io.sf.carte'
includeGroup 'io.sf.jclf'
}
}
Detail of changes
- anim: share the user agent css loading code between 1.1 and 1.2 implementations.
- anim,parser: support
calc()
values in animated rectangles. - Remove xmlgraphics-commons.
- Tests: add more Mermaid tests.
- Small javadoc tweaks.
- Upgrade to css4j 4.3.
1.1.1
Fix Java 8 compatibility of 1.1
A few Java 8 incompatibilities slipped into the codec
module in 1.1, and were detected by the secondary CI that checks the artifacts uploaded to the Maven repository. These are fixed in 1.1.1.
Note, however, that on Java 8 the new features introduced in the ImageIO writer will not work, due to lack of support by Java 8.
If you use the default PNGTranscoder
you should be fine, but if you are a SVGGraphics2D
user you may want to upgrade to Java 11 or later.
1.1
Highlights
Security fixes
Two security vulnerabilities in the util
module were fixed:
Adapt to new module name of xmlgraphics-commons
The next version of the xmlgraphics-commons dependency will use the org.apache.xmlgraphics.commons
module name, different to the one that was being used in EchoSVG until now (based on the Maven filename-based module name).
If you experience any difficulty due to the change, please use a plugin like Moditect for Maven or extra-java-module-info for Gradle. Or you could wait until the next version of xmlgraphics-commons is released and then set an explicit dependency.
More SVG2 compatibility
- More resilience against missing or wrong
href
,width
,height
,rx
,ry
,x
andy
attributes. - Full support for the namespaceless
href
attribute even in animations.
PNG codecs now support ICC color profiles
The native PNG codec and the ImageIO ImageWriter
now support color profiles automatically.
Color profiles in SVG Generator, in colors and embedded PNG images
See https://github.com/css4j/echosvg/wiki/SVG-Generator
Configurable compression level for embedded PNG images in the SVG Generator
See SVGGeneratorContext.setCompressionLevel()
.
New rendering hints in the PNG transcoder
Rendering hints KEY_KEYWORD_TEXT
, KEY_INTERNATIONAL_TEXT
and KEY_COMPRESSED_TEXT
allow embedding textual information (like copyright, author, description, etc) in rendered PNG images. And KEY_COMPRESSION_LEVEL
sets the compression level used in the PNG encoding (the default native encoder uses 9
by default, which is excessive for some use cases).
All of these hints work with both the native and the ImageIO adapters.
Per-module Fat-jars
If you manage your classpath manually and only require a specific module, get a fat-jar specific for your use case.
See https://github.com/css4j/echosvg/wiki/Uber-Jar
Detail of changes
- util: fix arbitrary file access during archive extraction. [security, CWE-22]
- util: set connect and read timeouts in
ParsedURLData
[BATIK-1366]. [security, CWE-770] - Modules: switch to
org.apache.xmlgraphics.commons
as xmlgraphics-commons module name. - Remove a few redundant interface usages, other cleanups.
- anim: support animatable namespaceless href attribute from SVG2.
- anim: allow missing
width
andheight
attributes in<rect>
[SVG2]. - anim, bridge: the
version
attribute isn't part of SVG anymore, just check for 1.2. - bridge: be tolerant to missing or malformed
href
attribute inimage
elements [SVG2]. - bridge: tolerate wrong
width
,height
,rx
andry
attributes in<rect>
[SVG2]. - bridge: tolerate wrong or missing
rx
andry
attributes in<ellipse>
,r
in<circle>
[SVG2]. - bridge: more resilience against missing or incorrect shape attributes [SVG2].
- bridge: nullcheck the animation engine in
SVGAnimationEngine
. - codec: support ICC color profiles in native PNG codec.
- codec: fix NPE writing the
zTXt
chunk. - codec: support ICC color profiles in
ImageIOPNGImageWriter
. - codec: configure the PNG compression level, support all the text chunks.
- codec: add a null check in
ImageIOJPEGImageWriter
, other small improvements. - css: remove dependency on xmlgraphics-commons.
- dom: check the namespaceless
href
attribute first. - extension: simplify
ColorSwitchBridge.createPaint()
. - extension: resource was in a directory with wrong name.
- script: give access to
org.mozilla.javascript.EcmaError
in the Rhino shutter [BATIK-912]. - svggen: support colors in non-sRGB color spaces, via color() function.
- svggen: support images based on ICC color profiles in
drawImage()
. - svggen: make the compression level of the embedded PNG images configurable.
- svggen: add Mac Glyph names for 210 & 257.
- transcoder: add the
KEY_COMPRESSION_LEVEL
,KEY_KEYWORD_TEXT
,KEY_INTERNATIONAL_TEXT
andKEY_COMPRESSED_TEXT
hints. - transcoder: do not close the output stream in
PNGImageEncoder
. - Unmerge codec packages from transcoder module, except for three classes.
- dom: fix XPath regression introduced by commit 8164dd7 (BATIK-1329: Remove xalan). Bug reported by Pavel Braginskiy in July 17 to the batik-users mailing list.
- JMH: move
DoubleStringPerformanceMark
to asvggen.jmh
package for improved modular compatibility. - Source formatting (pre-requisite to enable code style tools).
- Enable checks with the Checkstyle static analysis tool.
- Tests: test images from canvg's test suite #92.
- Tests: switch to a SVG 1.1 DTD in a number of test sample files.
- Tests: refactor to be more IDE-friendly.
- Tests: fix CodeQL alert 28.
- Tests: a number of other improvements.
- Distribution: add a Main-Class attribute to a few manifests.
- Gradle: use
implementation
instead ofapi
in several places. - Gradle: add the ability to create all-deps jar files for individual modules.
- Upgrade to Mozilla Rhino 1.7.15.
- Upgrade to xml-dtd 4.3.
- Upgrade to JUnit 5.10.3.
- Upgrade to extra-java-module-info 1.8.
- Upgrade to grGit 5.2.2.
- Upgrade Gradle wrapper to 8.9.
- CI: do not exclude any test.
- Run CI on Java 11 and 21.
1.0.1
This is a bugfix release and all users are encouraged to upgrade.
Detail of changes
- svg-dom: fix a bug copying transforms [BATIK-1361].
- transcoder: improve the
@supports
logic inCSSTranscodingHelper
. - Gradle: remove redundant module dependencies.
- Gradle: use dependency-license-report to check dependency licensing.
- Upgrade to css4j 4.2.2.
- Upgrade to JMH 1.37.
- Upgrade to JUnit 5.10.1.
- Upgrade to GrGit 5.2.1.
- Upgrade to extra-java-module-info version 1.6.
- Upgrade to
org.owasp.dependencycheck
8.4.2.