opencollab / jlatexmath

A Java API to render LaTeX
Other
514 stars 109 forks source link

Slightly deformed characters in SVG output #32

Closed vlad-ivanov-name closed 6 years ago

vlad-ivanov-name commented 7 years ago

For some reason fonts in SVG output I'm getting from JLaTeXMath are just a bit misshapen.

Example:

A = \frac{2394}{b \cdot 1650}

PNG:

jlatexmath-problem

SVG:

B771A71686B3F75C52A0298E8288BF80A6738EA9A433A51140F9514884F50304.zip

Code I use:

    private final static String SVG_NS = "http://www.w3.org/2000/svg";
    private final static String SVG_ROOT = "svg";
    private final static String SVG_EXT = ".svg";
    private final static float FONT_SIZE = 12;

    private String renderLatex(String source) {
        DOMImplementation DOMImpl = GenericDOMImplementation.getDOMImplementation();
        Document document = DOMImpl.createDocument(SVG_NS, SVG_ROOT, null);
        SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(document);
        SVGGraphics2D g = new SVGGraphics2D(ctx, true);

        TeXFormula formula = new TeXFormula(source);
        TeXFormula.TeXIconBuilder builder = formula.new TeXIconBuilder();

        builder.setStyle(TeXConstants.STYLE_DISPLAY);
        builder.setSize(FONT_SIZE);

        TeXIcon icon = builder.build();

        icon.setInsets(new Insets(0, 0, 0, 0));

        g.setSVGCanvasSize(new Dimension(icon.getIconWidth(), icon.getIconHeight()));
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, icon.getIconWidth(), icon.getIconHeight());

        icon.paintIcon(null, g, 0, 0);

        StringWriter out = new StringWriter();

        try {
            g.stream(out, true);

            out.flush();
            out.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return out.toString();
    }

Package versions:

        <dependency>
            <groupId>org.scilab.forge</groupId>
            <artifactId>jlatexmath</artifactId>
            <version>1.0.6</version>
        </dependency>

        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>batik-svggen</artifactId>
            <version>1.8</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>batik-dom</artifactId>
            <version>1.8</version>
            <scope>provided</scope>
        </dependency>
davidmoten commented 7 years ago

Can you edit the code so that I can see what the constants are? (FONT_SIZE, SVG_NS, SVG_ROOT)

vlad-ivanov-name commented 7 years ago

Sure, I have edited the code.

vlad-ivanov-name commented 7 years ago

One more addition (although likely irrelevant)

    static {
        DefaultTeXFont.registerAlphabet(new CyrillicRegistration());
    }
calixteman commented 7 years ago

Unfortunately, I already know this bug... i) to avoid to use the font files, the characters are replaced by their shape: as far as I remember SVGGraphics2D uses java::awt::font::TextLayout to draw glyphes as shapes and I think that the bug is here. ii) there is a workaround: write the text as it is (no replacement by glyph shapes) and put the fonts (which are in the jar and in the repo) somewhere accessible by your svg reader.

vlad-ivanov-name commented 7 years ago

Thanks. Do you know if it occurs for every font used with TextLayout? Maybe it's a matter of fixing the fonts in the repo? Could we convert the fonts to some other format?

calixteman commented 7 years ago

@resetnow I'm investigating and will try to find a workaround

vlad-ivanov-name commented 7 years ago

FTR I tried to open and re-export fonts with FontLab VI with no results. So must be something related to AWT.

murkle commented 6 years ago

For reference, here's the output using opentype.js to render to SVG (via canvas2svg.js) which looks fine

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1130" height="970"><defs/><g transform="scale(1,1)"><rect fill="rgb(255,255,255)" stroke="none" x="0" y="0" width="1130" height="970" fill-opacity="1"/><g transform="scale(131,131)"><g transform="translate(0.6183206106870229,1.9732853740458014)"><path fill="none" stroke="none"/><path fill="rgb(0,0,0)" stroke="none" paint-order="stroke fill markers" d=" M 0.377 -0.6940000000000001 L 0.638 0 L 0.546 0 L 0.47000000000000003 -0.20400000000000001 L 0.179 -0.20400000000000001 L 0.10200000000000001 0 L 0.028 0 L 0.289 -0.6940000000000001 L 0.377 -0.6940000000000001 M 0.448 -0.26 L 0.357 -0.517 Q 0.328 -0.6 0.325 -0.622 L 0.324 -0.622 Q 0.318 -0.589 0.265 -0.441 L 0.2 -0.26 L 0.448 -0.26 Z"/><path fill="none" stroke="none"/></g><g transform="translate(1.562769221798134,1.9732853740458014)"><path fill="none" stroke="none"/><path fill="rgb(0,0,0)" stroke="none" paint-order="stroke fill markers" d=" M 0.687 -0.33 L 0.09 -0.33 Q 0.056 -0.33 0.056 -0.35000000000000003 Q 0.056 -0.37 0.089 -0.37 L 0.6880000000000001 -0.37 Q 0.721 -0.37 0.721 -0.35000000000000003 Q 0.721 -0.33 0.687 -0.33 M 0.6880000000000001 -0.13 L 0.089 -0.13 Q 0.056 -0.13 0.056 -0.15 Q 0.056 -0.17 0.09 -0.17 L 0.687 -0.17 Q 0.721 -0.17 0.721 -0.15 Q 0.721 -0.13 0.6880000000000001 -0.13 Z"/><path fill="none" stroke="none"/></g><g transform="translate(3.3577752191159247,1.2967773740458015)"><path fill="none" stroke="none"/><path fill="rgb(0,0,0)" stroke="none" paint-order="stroke fill markers" d=" M 0.17400000000000002 -0.188 L 0.251 -0.259 Q 0.281 -0.29 0.2955 -0.3055 Q 0.31 -0.321 0.33 -0.34900000000000003 Q 0.35000000000000003 -0.377 0.3585 -0.404 Q 0.367 -0.431 0.367 -0.461 Q 0.367 -0.523 0.328 -0.5685 Q 0.289 -0.614 0.222 -0.614 Q 0.161 -0.614 0.1315 -0.5730000000000001 Q 0.10200000000000001 -0.532 0.083 -0.459 Q 0.066 -0.484 0.061 -0.488 Q 0.06 -0.489 0.0545 -0.4965 Q 0.049 -0.504 0.042 -0.514 Q 0.088 -0.678 0.23600000000000002 -0.678 Q 0.332 -0.678 0.3905 -0.6155 Q 0.449 -0.553 0.449 -0.463 Q 0.449 -0.424 0.4315 -0.3865 Q 0.41400000000000003 -0.34900000000000003 0.398 -0.3305 Q 0.382 -0.312 0.35000000000000003 -0.28 Q 0.34 -0.271 0.3055 -0.241 Q 0.271 -0.211 0.261 -0.202 Q 0.254 -0.196 0.1975 -0.14100000000000001 Q 0.14100000000000001 -0.08600000000000001 0.122 -0.07 L 0.231 -0.07 Q 0.23700000000000002 -0.07 0.249 -0.07050000000000001 Q 0.261 -0.07100000000000001 0.267 -0.07100000000000001 L 0.449 -0.07100000000000001 L 0.449 0 L 0.05 0 L 0.05 -0.064 L 0.17400000000000002 -0.188 Z"/><path fill="none" stroke="none"/></g><g transform="translate(3.8577772191159245,1.2967773740458015)"><path fill="none" stroke="none"/><path fill="rgb(0,0,0)" stroke="none" paint-order="stroke fill markers" d=" M 0.092 -0.514 L 0.056 -0.5680000000000001 Q 0.08700000000000001 -0.62 0.1385 -0.649 Q 0.19 -0.678 0.248 -0.678 Q 0.323 -0.678 0.3765 -0.634 Q 0.43 -0.59 0.43 -0.526 Q 0.43 -0.47600000000000003 0.402 -0.4295 Q 0.374 -0.383 0.319 -0.354 Q 0.375 -0.337 0.41600000000000004 -0.2905 Q 0.457 -0.244 0.457 -0.18 Q 0.457 -0.099 0.3965 -0.0385 Q 0.336 0.022 0.247 0.022 Q 0.123 0.022 0.042 -0.082 L 0.053 -0.14200000000000002 Q 0.085 -0.093 0.138 -0.066 Q 0.191 -0.039 0.245 -0.039 Q 0.301 -0.039 0.3345 -0.08 Q 0.368 -0.121 0.368 -0.181 Q 0.368 -0.203 0.3625 -0.225 Q 0.357 -0.247 0.34400000000000003 -0.2705 Q 0.331 -0.294 0.3035 -0.309 Q 0.276 -0.324 0.23800000000000002 -0.324 L 0.167 -0.324 L 0.167 -0.385 Q 0.242 -0.391 0.246 -0.392 Q 0.291 -0.402 0.3195 -0.4405 Q 0.34800000000000003 -0.47900000000000004 0.34800000000000003 -0.526 Q 0.34800000000000003 -0.5710000000000001 0.3185 -0.5955 Q 0.289 -0.62 0.247 -0.62 Q 0.199 -0.62 0.156 -0.592 Q 0.113 -0.5640000000000001 0.092 -0.514 Z"/><path fill="none" stroke="none"/></g><g transform="translate(4.357779219115924,1.2967773740458015)"><path fill="none" stroke="none"/><path fill="rgb(0,0,0)" stroke="none" paint-order="stroke fill markers" d=" M 0.07200000000000001 -0.024 L 0.10300000000000001 -0.077 Q 0.149 -0.039 0.20600000000000002 -0.039 Q 0.27 -0.039 0.3175 -0.1005 Q 0.365 -0.162 0.373 -0.277 Q 0.341 -0.23700000000000002 0.296 -0.2155 Q 0.251 -0.194 0.20400000000000001 -0.194 Q 0.134 -0.194 0.088 -0.2645 Q 0.042 -0.335 0.042 -0.434 Q 0.042 -0.541 0.107 -0.611 Q 0.17 -0.678 0.253 -0.678 Q 0.289 -0.678 0.3215 -0.663 Q 0.354 -0.648 0.386 -0.6125 Q 0.418 -0.577 0.4375 -0.5055000000000001 Q 0.457 -0.434 0.457 -0.335 Q 0.457 -0.177 0.382 -0.0775 Q 0.307 0.022 0.20500000000000002 0.022 Q 0.135 0.022 0.07200000000000001 -0.024 M 0.37 -0.435 Q 0.369 -0.46 0.364 -0.486 Q 0.359 -0.512 0.34800000000000003 -0.545 Q 0.337 -0.578 0.312 -0.599 Q 0.28700000000000003 -0.62 0.253 -0.62 Q 0.192 -0.62 0.153 -0.5630000000000001 Q 0.124 -0.517 0.124 -0.434 Q 0.124 -0.356 0.147 -0.315 Q 0.181 -0.255 0.243 -0.255 Q 0.3 -0.255 0.3355 -0.301 Q 0.371 -0.34700000000000003 0.371 -0.41100000000000003 Q 0.371 -0.428 0.37 -0.435 Z"/><path fill="none" stroke="none"/></g><g transform="translate(4.857781219115925,1.2967773740458015)"><path fill="none" stroke="none"/><path fill="rgb(0,0,0)" stroke="none" paint-order="stroke fill markers" d=" M 0.372 -0.171 L 0.372 0 L 0.293 0 L 0.293 -0.171 L 0.028 -0.171 L 0.028 -0.232 L 0.281 -0.656 L 0.372 -0.656 L 0.372 -0.232 L 0.47100000000000003 -0.232 L 0.47100000000000003 -0.171 L 0.372 -0.171 M 0.106 -0.232 L 0.299 -0.232 L 0.299 -0.612 Q 0.299 -0.551 0.106 -0.232 Z"/><path fill="none" stroke="none"/></g><rect fill="rgb(0,0,0)" stroke="none" x="2.738328830227036" y="1.7032858740458015" width="3.2389007777777774" height="0.039999"/><g transform="translate(2.738328830227036,2.6592363740458014)"><path fill="none" stroke="none"/><path fill="rgb(0,0,0)" stroke="none" paint-order="stroke fill markers" d=" M 0.157 -0.6940000000000001 L 0.157 -0.396 Q 0.229 -0.455 0.318 -0.455 Q 0.387 -0.455 0.4335 -0.3865 Q 0.48 -0.318 0.48 -0.223 Q 0.48 -0.124 0.425 -0.0565 Q 0.37 0.011 0.294 0.011 Q 0.222 0.011 0.16 -0.046 L 0.16 0 L 0.082 0 L 0.082 -0.6940000000000001 L 0.157 -0.6940000000000001 M 0.16 -0.335 L 0.16 -0.114 Q 0.195 -0.05 0.257 -0.05 Q 0.312 -0.05 0.357 -0.0925 Q 0.402 -0.135 0.402 -0.223 Q 0.402 -0.31 0.361 -0.352 Q 0.32 -0.394 0.267 -0.394 Q 0.199 -0.394 0.16 -0.335 Z"/><path fill="none" stroke="none"/></g><g transform="translate(3.477219719115925,2.6592363740458014)"><path fill="none" stroke="none"/><path fill="rgb(0,0,0)" stroke="none" paint-order="stroke fill markers" d=" M 0.192 -0.25 Q 0.192 -0.217 0.162 -0.202 Q 0.151 -0.197 0.139 -0.197 Q 0.106 -0.197 0.091 -0.227 Q 0.08600000000000001 -0.23800000000000002 0.08600000000000001 -0.25 Q 0.08600000000000001 -0.28300000000000003 0.116 -0.298 Q 0.127 -0.303 0.139 -0.303 Q 0.17200000000000001 -0.303 0.187 -0.273 Q 0.192 -0.262 0.192 -0.25 Z"/><path fill="none" stroke="none"/></g><g transform="translate(3.9772216080048137,2.6592363740458014)"><path fill="none" stroke="none"/><path fill="rgb(0,0,0)" stroke="none" paint-order="stroke fill markers" d=" M 0.299 -0.678 L 0.299 -0.058 L 0.424 -0.058 L 0.424 0 L 0.095 0 L 0.095 -0.058 L 0.22 -0.058 L 0.22 -0.578 Q 0.169 -0.556 0.089 -0.554 L 0.089 -0.612 Q 0.22 -0.617 0.279 -0.678 L 0.299 -0.678 Z"/><path fill="none" stroke="none"/></g><g transform="translate(4.477223608004814,2.6592363740458014)"><path fill="none" stroke="none"/><path fill="rgb(0,0,0)" stroke="none" paint-order="stroke fill markers" d=" M 0.41500000000000004 -0.658 L 0.41500000000000004 -0.599 Q 0.362 -0.62 0.31 -0.62 Q 0.23800000000000002 -0.62 0.1865 -0.5575 Q 0.135 -0.495 0.126 -0.379 Q 0.194 -0.462 0.295 -0.462 Q 0.365 -0.462 0.41100000000000003 -0.3915 Q 0.457 -0.321 0.457 -0.222 Q 0.457 -0.164 0.4425 -0.1245 Q 0.428 -0.085 0.393 -0.046 Q 0.334 0.022 0.251 0.022 Q 0.223 0.022 0.1965 0.014 Q 0.17 0.006 0.14100000000000001 -0.0175 Q 0.112 -0.041 0.091 -0.078 Q 0.07 -0.115 0.056 -0.178 Q 0.042 -0.241 0.042 -0.322 Q 0.042 -0.47900000000000004 0.121 -0.5785 Q 0.2 -0.678 0.309 -0.678 Q 0.364 -0.678 0.41500000000000004 -0.658 M 0.127 -0.219 Q 0.129 -0.196 0.1335 -0.17500000000000002 Q 0.138 -0.154 0.15 -0.11850000000000001 Q 0.162 -0.083 0.188 -0.061 Q 0.214 -0.039 0.251 -0.039 Q 0.313 -0.039 0.35100000000000003 -0.101 Q 0.375 -0.14200000000000002 0.375 -0.222 Q 0.375 -0.298 0.352 -0.339 Q 0.318 -0.401 0.256 -0.401 Q 0.197 -0.401 0.1625 -0.354 Q 0.128 -0.307 0.128 -0.247 Q 0.127 -0.23500000000000001 0.127 -0.219 Z"/><path fill="none" stroke="none"/></g><g transform="translate(4.977225608004814,2.6592363740458014)"><path fill="none" stroke="none"/><path fill="rgb(0,0,0)" stroke="none" paint-order="stroke fill markers" d=" M 0.153 -0.592 L 0.153 -0.386 Q 0.199 -0.427 0.26 -0.427 Q 0.338 -0.427 0.3935 -0.3615 Q 0.449 -0.296 0.449 -0.203 Q 0.449 -0.109 0.3845 -0.043500000000000004 Q 0.32 0.022 0.23 0.022 Q 0.171 0.022 0.121 -0.005 Q 0.07100000000000001 -0.032 0.039 -0.076 L 0.07200000000000001 -0.132 Q 0.094 -0.091 0.137 -0.065 Q 0.18 -0.039 0.229 -0.039 Q 0.23700000000000002 -0.039 0.2465 -0.04 Q 0.256 -0.041 0.2785 -0.05 Q 0.301 -0.059000000000000004 0.317 -0.0745 Q 0.333 -0.09 0.34650000000000003 -0.124 Q 0.36 -0.158 0.36 -0.20500000000000002 Q 0.36 -0.28800000000000003 0.33 -0.327 Q 0.3 -0.366 0.259 -0.366 Q 0.219 -0.366 0.19 -0.3435 Q 0.161 -0.321 0.147 -0.28700000000000003 L 0.081 -0.28700000000000003 L 0.081 -0.656 L 0.41600000000000004 -0.656 L 0.41600000000000004 -0.592 L 0.153 -0.592 Z"/><path fill="none" stroke="none"/></g><g transform="translate(5.477227608004815,2.6592363740458014)"><path fill="none" stroke="none"/><path fill="rgb(0,0,0)" stroke="none" paint-order="stroke fill markers" d=" M 0.457 -0.326 Q 0.457 -0.17500000000000002 0.417 -0.088 Q 0.393 -0.036000000000000004 0.34850000000000003 -0.007 Q 0.304 0.022 0.249 0.022 Q 0.217 0.022 0.1875 0.012 Q 0.158 0.002 0.1265 -0.027 Q 0.095 -0.056 0.076 -0.101 Q 0.042 -0.184 0.042 -0.326 Q 0.042 -0.47800000000000004 0.08 -0.562 Q 0.108 -0.624 0.154 -0.651 Q 0.2 -0.678 0.25 -0.678 Q 0.294 -0.678 0.3385 -0.6545 Q 0.383 -0.631 0.41100000000000003 -0.579 Q 0.457 -0.49 0.457 -0.326 M 0.25 -0.039 Q 0.33 -0.039 0.361 -0.146 Q 0.379 -0.209 0.379 -0.338 Q 0.379 -0.467 0.36 -0.523 Q 0.354 -0.538 0.34950000000000003 -0.5465 Q 0.34500000000000003 -0.555 0.332 -0.5750000000000001 Q 0.319 -0.595 0.2975 -0.606 Q 0.276 -0.617 0.249 -0.617 Q 0.169 -0.617 0.137 -0.516 Q 0.12 -0.461 0.12 -0.338 Q 0.12 -0.21 0.137 -0.149 Q 0.168 -0.039 0.25 -0.039 Z"/><path fill="none" stroke="none"/></g></g></g></svg>

vlad-ivanov-name commented 6 years ago

Okay so after some digging the issue is caused by font resizing. There's a call to deriveFont(1) in DefaultTeXFontParser.createFont. So the font is derived with scale of 1 and later in CharBox graphics object is transformed to match the scale. I think somewhere inside AWT or even in some native library some code either uses 32-bit floats or misuses floating point, so when font is scaled to 1 some calculations lose precision. I know it's a lot of "some" but there's an easy workaround.

Here's a font derived with scale 1 and painted with scale 100:

bad

Here's a font derived with scale 100 and painted with scale 1:

good

murkle commented 6 years ago

Thanks, fix works very well for me (for a very old bug 😄 )