Hi list!

Attempting to render an SVG file read from Batik onto an exported PDF
document has encountered a few problems, including:

   - Font rasterization
   - Font weights
   - Grid marks
   - Colour

*Versions*

   - Apache PDFBox 2.0.22
   - Apache Batik 1.14
   - Rototor's PDF Graphics 2D 0.31
   - OpenJDK 15
   - Linux kernel 5.9.14, XFCE on Arch

*Fonts*

   - Roboto, Roboto Thin -
   https://fonts.google.com/specimen/Roboto?preview.text_type=custom
   - Daggersquare - https://www.dafont.com/daggersquare.font

*Comparison*

In the following image, PDFBox export is on the left and Inkscape export on
the right, but sourced from the same SVG and font files:

https://i.ibb.co/pdxrf06/pdfbox-inkscape.png

Notice that:

   - the word WANTED is discoloured (not a big issue);
   - fine lines grid the entire image (especially visible against the
   WANTED text);
   - all text is rasterized;
   - the font weight (Roboto thin) is not honoured; and
   - the file sizes differ by a fair margin (also not a huge issue).

inkscape-poster.pdf is 23,481 bytes
pdfbox-poster.pdf is 493,896 bytes

*Question*

How do you force the font subsets to be embedded (to reduce PDF file size
and avoid rasterizing glyphs)?

*SSCCE*

The SSCCE transcodes /tmp/poster.svg to /tmp/pdfbox-poaster.pdf:

// SOF
import de.rototor.pdfbox.graphics2d.PdfBoxGraphics2D;
import org.apache.batik.anim.dom.SAXSVGDocumentFactory;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.DocumentLoader;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;

import java.io.File;
import java.util.Map;

import static java.awt.RenderingHints.*;
import static java.awt.geom.AffineTransform.getScaleInstance;
import static java.nio.file.Files.newOutputStream;
import static java.nio.file.StandardOpenOption.*;
import static
org.apache.batik.util.XMLResourceDescriptor.getXMLParserClassName;

public class Main {
  public static void main( final String[] args ) throws Exception {
    // Gain direct access to Batik graphics context.
    final var userAgent = new UserAgentAdapter();
    final var loader = new DocumentLoader( userAgent );
    final var context = new BridgeContext( userAgent, loader );
    context.setDynamic( false );

    // Read the SVG file to render as PDF.
    final var factory = new SAXSVGDocumentFactory( getXMLParserClassName()
);
    final var svg = factory.createSVGDocument( "/tmp/poster.svg" );
    final var node = new GVTBuilder().build( context, svg );

    // Ensure that small bounds are enlarged.
    final var bounds = node.getPrimitiveBounds();
    final var w = (float) bounds.getWidth();
    final var h = (float) bounds.getHeight();
    final var scale = (w < 1 || h < 1) ? 100 : 1;

    // Create the PDF document model.
    final var pageSize = new PDRectangle( w * scale, h * scale );
    final var page = new PDPage( pageSize );
    final var document = new PDDocument();
    document.addPage( page );

    // Ask Batik to render upon the PDF's graphics context.
    final var graphics = new PdfBoxGraphics2D( document, w, h );
    node.setRenderingHints( RENDERING_HINTS );
    node.paint( graphics );
    graphics.dispose();

    // Instruct PDFBox to apply the drawn nodes.
    try( var writer = new PDPageContentStream( document, page ) ) {
      final var xform = graphics.getXFormObject();
      xform.setMatrix( getScaleInstance( scale, scale ) );
      writer.drawForm( xform );
    }

    // Export the PDFBox document to a file.
    final var pdfFile = new File( "/tmp/pdfbox-poster.pdf" );
    final var fos = newOutputStream(
      pdfFile.toPath(), WRITE, CREATE, TRUNCATE_EXISTING );
    document.save( fos );
    document.close();
    fos.close();

    System.out.println( "Created: " + pdfFile );
  }

  private static final Map<Object, Object> RENDERING_HINTS = Map.of(
    KEY_ANTIALIASING, VALUE_ANTIALIAS_ON,
    KEY_ALPHA_INTERPOLATION, VALUE_ALPHA_INTERPOLATION_QUALITY,
    KEY_COLOR_RENDERING, VALUE_COLOR_RENDER_QUALITY,
    KEY_DITHERING, VALUE_DITHER_DISABLE,
    KEY_FRACTIONALMETRICS, VALUE_FRACTIONALMETRICS_ON,
    KEY_INTERPOLATION, VALUE_INTERPOLATION_BICUBIC,
    KEY_RENDERING, VALUE_RENDER_QUALITY,
    KEY_STROKE_CONTROL, VALUE_STROKE_PURE,
    KEY_TEXT_ANTIALIASING, VALUE_TEXT_ANTIALIAS_ON
  );
}
// EOF

I can provide the graphics off-list, if needed.

Thank you!

Reply via email to