All formats

Apache XML Graphics Commons

LanguageJava
LicenseApache-2.0
Repositorygithub.com/apache/xmlgraphics-commons
DocumentationPostScript and EPS support
Depends oncommons-logging
Read / writeDSC comments only (no rendering) / yes (EPS, Level 2)

XML Graphics Commons is the graphics toolkit behind Apache FOP and Batik. EPSDocumentGraphics2D is a Graphics2D implementation: you draw with normal Java2D calls and it writes a single-page, fully conforming EPS file with %%BoundingBox. The DSC parser reads the header comments of existing EPS and PostScript files without running them.

It can’t render EPS and doesn’t add a preview image. Transparency in Java2D drawing is not reproduced, because PostScript has none.

Installation#

XML
<dependency>
  <groupId>org.apache.xmlgraphics</groupId>
  <artifactId>xmlgraphics-commons</artifactId>
  <version>2.11</version>
</dependency>

Gradle: implementation("org.apache.xmlgraphics:xmlgraphics-commons:2.11")

Basic usage: write an EPS file with Java2D#

Java
import java.awt.Color;
import java.awt.Font;
import java.awt.geom.Ellipse2D;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.xmlgraphics.java2d.GraphicContext;
import org.apache.xmlgraphics.java2d.ps.EPSDocumentGraphics2D;

public class WriteEps {
    public static void main(String[] args) throws IOException {
        try (OutputStream out = new BufferedOutputStream(new FileOutputStream("logo.eps"))) {
            EPSDocumentGraphics2D g2d = new EPSDocumentGraphics2D(true); // text as shapes
            g2d.setGraphicContext(new GraphicContext());
            g2d.setupDocument(out, 200, 100);  // bounding box size in points

            g2d.setColor(new Color(50, 100, 200));
            g2d.fill(new Ellipse2D.Double(10, 10, 80, 80));
            g2d.setColor(Color.BLACK);
            g2d.setFont(new Font("SansSerif", Font.BOLD, 28));
            g2d.drawString("LOGO", 100, 62);

            g2d.finish();
        }
    }
}

How to read the bounding box of an EPS file#

Java
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;

import org.apache.xmlgraphics.ps.DSCConstants;
import org.apache.xmlgraphics.ps.dsc.DSCParser;
import org.apache.xmlgraphics.ps.dsc.events.DSCComment;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentBoundingBox;

try (InputStream in = new BufferedInputStream(new FileInputStream("logo.eps"))) {
    DSCParser parser = new DSCParser(in);  // needs a stream that supports mark()
    DSCComment c = parser.nextDSCComment(DSCConstants.BBOX);
    if (c instanceof DSCCommentBoundingBox bbox && bbox.getBoundingBox() != null) {
        System.out.println(bbox.getBoundingBox());  // Rectangle2D in points
    }
}

DSCConstants.HIRES_BBOX finds %%HiResBoundingBox.

How to read an EPS file that has a TIFF or WMF preview#

Files with a binary header start with C5 D0 D3 C6 instead of %!PS. Read the offset and length of the PostScript section (little-endian) and parse only that part:

Java
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;

static InputStream postScriptPart(Path path) throws IOException {
    byte[] data = Files.readAllBytes(path);
    ByteBuffer b = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
    if (data.length >= 30 && b.getInt(0) == 0xC6D3D0C5) {
        int offset = b.getInt(4);
        int length = b.getInt(8);
        return new ByteArrayInputStream(data, offset, length);
    }
    return new ByteArrayInputStream(data);  // plain EPS
}

Pass the result to new DSCParser(...). ByteArrayInputStream supports mark().

Tips#