Skip to content

CSSTranscodingHelper

carlosame edited this page Jul 28, 2024 · 7 revisions

CSSTranscodingHelper

Found in the io.sf.carte.echosvg.transcoder.util package, it is an utility for transcoding documents that use modern CSS, bypassing the EchoSVG style computations which (except for selectors) are mostly tied to the old CSS2.


Markup recommendations

To obtain the best results, your document should define style properties in a style sheet or the style attribute, instead of using style-like attributes like font-size.

For example it is preferable:

<text style="font-size: 20px;">  

to:

<text font-size="20">  

Supported CSS

Modern CSS is allowed, with most of the following specifications being supported:

  • Selectors Level 4.

  • Values and Units Level 4 (calc(), viewport-based units).

  • Values and Units Level 5 (advanced attr()).

  • Color Level 4 (color(display-p3 -0.61 1.09 -0.22)) and color-mix from Level 5.

  • Custom properties Level 1 (var()).

  • Properties and Values API Level 1 (@property rule).

  • Media Queries Level 4 (@media screen and (400px <= width <= 700px)).

  • Conditional Rules Level 4 (@supports (color: lch(45% 30 60))).

As an example of what the helper can do, please see this test document. All of the CSS shown there is supported.


Use it as a direct replacement for a Transcoder

Wrap your transcoder with the helper, and proceed with it:

   Transcoder transcoder = new PNGTranscoder();

   CSSTranscodingHelper helper = new CSSTranscodingHelper(transcoder);
   helper.transcode(input, output);

and that's all.


Configuring for Media Queries

Media Queries use the SVG viewport dimensions by default, but you can set the dimensions used by queries by setting the SVGAbstractTranscoder.KEY_WIDTH and SVGAbstractTranscoder.KEY_HEIGHT transcoding hints. And the target medium (screen, print, etc.) can be set via the SVGAbstractTranscoder.KEY_MEDIA hint.

For example:

   Transcoder transcoder = new PNGTranscoder();

   CSSTranscodingHelper helper = new CSSTranscodingHelper(transcoder);

   helper.getTranscoder().addTranscodingHint(SVGAbstractTranscoder.KEY_MEDIA, "screen");
   helper.getTranscoder().addTranscodingHint(SVGAbstractTranscoder.KEY_WIDTH, 450);
   helper.getTranscoder().addTranscodingHint(SVGAbstractTranscoder.KEY_HEIGHT, 500);

   String uri = "https://www.example.com/my_image.svg";
   java.io.Reader reader = ... [SVG document reader]
   java.io.OutputStream os = ... [where to write the image]

   TranscoderOutput output = new TranscoderOutput(os);

   helper.transcode(reader, uri, output, null);

or alternatively:

   TranscoderInput input = new TranscoderInput(reader);
   input.setURI(uri);
   TranscoderOutput output = new TranscoderOutput(os);

   helper.transcode(input, output);

Dark mode

You can enable the dark mode with

helper.setDarkMode(true);

Rendering SVG inside HTML

You can also render <svg> elements that are located inside an HTML document. By default, the first <svg> element (in document order) will be used, but you can point to a specific one using a CSS selector. For example:

helper.transcode(reader, uri, output, "#mySvg");

alternatively:

   TranscoderInput input = new TranscoderInput(reader);
   input.setURI(uri);
   TranscoderOutput output = new TranscoderOutput(os);
   helper.getTranscoder().addTranscodingHint(SVGAbstractTranscoder.KEY_SVG_SELECTOR, "#mySvg");

   helper.transcode(input, output);

And instead of the default XML parser (perfectly valid for XHTML) you can use an HTML one. You could use the validator.nu HTML parser (one of the parsers used by the Firefox browser). For that, you have to add the dependency first:

Gradle

implementation group: 'nu.validator', name: 'htmlparser', version: '1.4.16'

Maven

<dependency>
    <groupId>nu.validator</groupId>
    <artifactId>htmlparser</artifactId>
    <version>1.4.16</version>
</dependency>

and then

Plugging the validator.nu HTML parser

HtmlParser parser = new HtmlParser(XmlViolationPolicy.ALTER_INFOSET);
parser.setCommentPolicy(XmlViolationPolicy.ALLOW);
parser.setXmlnsPolicy(XmlViolationPolicy.ALLOW);

helper.setXMLReader(parser);
helper.setHTMLEmbedding(true);

Note that calling setHTMLEmbedding(boolean) is not required if the document uri ends with .html.


Foreign elements

The processing of foreign elements located inside a <foreignObject> is performed via SVG 1.2 features. Therefore, if a document contains foreign elements, the <svg> element should either not have a version attribute, or that attribute's value must be 1.2 or 2.