Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Batik not rendering the correct font color?

Tags:

fonts

png

svg

batik

I'm using the Apache Batik Java library to convert .svg vector image file to a .png file. The problem is that the font colors of the generated .png image are all going black. Here is the code that I'm using to do the conversion:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;

public class SVGHelperDesktop extends SVGHelper {
    @Override
    public byte[] convertSvgToPng(String svgXml, float png_width)
            throws SVGConversionException {
        byte[] resultPngBytes = null;

        try {
            ByteArrayInputStream inputSvgBytes = new 
                    ByteArrayInputStream(svgXml.getBytes());
            TranscoderInput input_svg_image = new 
                    TranscoderInput(inputSvgBytes);

            ByteArrayOutputStream outputPngBytes = new ByteArrayOutputStream();
            TranscoderOutput output_png_image = new TranscoderOutput(outputPngBytes);

            PNGTranscoder svgToPngConverter = new PNGTranscoder(); 
            svgToPngConverter.addTranscodingHint(PNGTranscoder.KEY_WIDTH, png_width);
            svgToPngConverter.transcode(input_svg_image, output_png_image);

            resultPngBytes = outputPngBytes.toByteArray();

            outputPngBytes.flush();
            outputPngBytes.close(); 
        } catch (Exception e) {
            throw new SVGConversionException("Error converting SVG to PNG", e);
        }

        return resultPngBytes;
    }
}

Using the AndroidSVG library on the same .svg file generates the correct .png image with the correct colors.

Another note; Using the default font of inkscape (the program I use to create vector graphics) solves this problem. Using any other font face causes Batik to change its colors to black.

Here's a link to my SVG file.

like image 870
MyNameIsUser Avatar asked Oct 14 '25 08:10

MyNameIsUser


2 Answers

Inkscape adds a custom CSS property, -inkscape-font-specification, to the style attribute associated with custom font text. Here's an excerpt:

style="...;-inkscape-font-specification:'Aharoni, Bold';..."

A known Batik bug prevents rendering CSS properties that start with a hyphen (-).

A simple fix is to edit the file and then remove the "-inkscape-font-specification" attributes.

Alternatively, you could use Batik's API to create a new CSS style parser that removes the offending CSS style class. For example:

  /**
   * <a href="https://issues.apache.org/jira/browse/BATIK-1112">Bug fix</a>
   */
  public static final class InkscapeCssParser extends Parser {
    public void parseStyleDeclaration( final String source )
      throws CSSException, IOException {
      super.parseStyleDeclaration(
        source.replaceAll( "-inkscape-font-specification:[^;\"]*;", "" )
      );
    }
  }

  static {
    XMLResourceDescriptor.setCSSParserClassName(
      InkscapeCssParser.class.getName()
    );
  }
like image 132
Paul LeBeau Avatar answered Oct 17 '25 04:10

Paul LeBeau


The accepted answer very helpfully points to the Batik bug 1112 indicating the "-inkscape-font-specification" is not properly parsed. The bug report has a workaround that works by re-implementing part of the CSS parser from Batik. To expand on this and make it available right here, here's my simplified and naive version of the workaround.

First a CSS parser class is needed overriding the one from Batik:

import org.apache.batik.css.parser.ExtendedParser;
import org.apache.batik.css.parser.Parser;
import org.w3c.css.sac.CSSException;
import java.io.IOException;

public class InkscapeCssParser extends Parser {
    public void parseStyleDeclaration(String source)
            throws CSSException, IOException {
        source = source.replaceAll(";-inkscape", ";inkscape");
        super.parseStyleDeclaration(source);
    }
}

Note that the source argument is the CSS style of a specific SVG element, not the full SVG source. parseStyleDeclaration is called for every element that has a style attribute.

Whereas the workaround provided in the Batik bug re-implements a good chunk of parseStyleDeclaration, I simply do a naive string replace to get rid of the offending "-" after the ";" since that's the core of the issue.

To use this, set the CSS parser class name before loading the document:

JSVGCanvas mSvgCanvas;
XMLResourceDescriptor.setCSSParserClassName(InkscapeCssParser.class.getName());
mSvgCanvas.setURI(svgUrl.toString());
like image 44
ralfoide Avatar answered Oct 17 '25 03:10

ralfoide



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!