Apache XML Graphics Commons
| Language | Java |
|---|---|
| License | Apache-2.0 |
| Repository | github.com/apache/xmlgraphics-commons |
| Documentation | PostScript support |
| Depends on | commons-logging |
| Read / write | DSC structure only (no interpreter) / yes (Level 2 PostScript, EPS) |
XML Graphics Commons is the shared code of Apache FOP and Apache Batik. Its PostScript package has:
PSDocumentGraphics2D: aGraphics2Dthat writes a DSC-conforming Level 2 PostScript file. Draw with normal Java2D calls (shapes, text, images), callnextPage()between pages.EPSDocumentGraphics2D: the same for a single-page EPS file (see EPS).PSGenerator: low-level writer that escapes strings and writes DSC comments, for generating PostScript code yourself.DSCParser: reads the%%comments of an existing file (page count, bounding box, pages, resources) without running it. Use it to count pages, split files or extract a page.
It can’t render PostScript. Transparency isn’t supported in PostScript, so semi-transparent Java2D drawing is not reproduced.
Installation#
Maven:
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: draw a two-page PostScript file with Java2D#
Java
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
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.PSDocumentGraphics2D;
public class WritePs {
public static void main(String[] args) throws IOException {
try (OutputStream out = new BufferedOutputStream(new FileOutputStream("out.ps"))) {
// true: draw text as shapes (exact look); false: use PostScript fonts
PSDocumentGraphics2D g2d = new PSDocumentGraphics2D(true);
g2d.setGraphicContext(new GraphicContext());
g2d.setupDocument(out, 595, 842); // A4 in points
g2d.setColor(new Color(50, 100, 200));
g2d.fillRect(72, 72, 300, 150); // origin is top-left, as in Java2D
g2d.setColor(Color.BLACK);
g2d.setFont(new Font("SansSerif", Font.BOLD, 24));
g2d.drawString("Hello, PostScript", 72, 280);
g2d.nextPage();
g2d.setStroke(new BasicStroke(4f));
g2d.setColor(Color.RED);
g2d.drawOval(197, 321, 200, 200);
g2d.finish(); // writes the trailer
}
}
}
How to read the page count and bounding box of a PostScript file#
DSCParser walks the DSC comments. Wrap the input in a BufferedInputStream: the parser needs mark() support.
Java
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.xmlgraphics.ps.dsc.DSCParser;
import org.apache.xmlgraphics.ps.dsc.events.DSCComment;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentBoundingBox;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentPage;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentPages;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentTitle;
import org.apache.xmlgraphics.ps.dsc.events.DSCEvent;
public class PsInfo {
public static void main(String[] args) throws Exception {
try (InputStream in = new BufferedInputStream(new FileInputStream(args[0]))) {
DSCParser parser = new DSCParser(in);
int pagesSeen = 0;
while (parser.hasNext()) {
DSCEvent event = parser.nextEvent();
if (!event.isDSCComment()) continue;
DSCComment c = event.asDSCComment();
if (c instanceof DSCCommentTitle t) {
System.out.println("title: " + t.getTitle());
} else if (c instanceof DSCCommentPages p) {
System.out.println("%%Pages: " + p.getPageCount());
} else if (c instanceof DSCCommentBoundingBox b && b.getBoundingBox() != null) {
System.out.println("bounding box: " + b.getBoundingBox());
} else if (c instanceof DSCCommentPage page) {
pagesSeen++;
System.out.println("page " + page.getPageName() + " (#" + page.getPagePosition() + ")");
}
}
System.out.println("pages found: " + pagesSeen);
}
}
}
%%Pages: (atend) puts the real value in the trailer, so count %%Page: comments to be safe.
How to find a single DSC comment#
nextDSCComment skips to the next comment with a given name and returns null at the end of the file:
Java
import org.apache.xmlgraphics.ps.DSCConstants;
DSCParser parser = new DSCParser(new BufferedInputStream(new FileInputStream("in.ps")));
DSCComment bbox = parser.nextDSCComment(DSCConstants.BBOX);
if (bbox instanceof DSCCommentBoundingBox b) {
System.out.println(b.getBoundingBox()); // java.awt.geom.Rectangle2D in points
}
Tips#
- With
textAsShapes = false, text is written with the standard PostScript fonts (Helvetica, Times, Courier). Usetruefor other fonts or non-Latin text. g2d.setBackgroundColor(Color.WHITE)fills each page before drawing.- The PageExtractor class in
org.apache.xmlgraphics.ps.dsc.toolscopies a page range out of a DSC-conforming file.