ofdrw
| Language | Java 8+ |
|---|---|
| License | MIT |
| Repository | github.com/ofdrw/ofdrw (mirror: gitee.com/ofdrw/ofdrw) |
| Documentation | README and module docs in the repository (Chinese), e.g. export and conversion to OFD |
| Depends on | dom4j, Bouncy Castle, Apache PDFBox (converter), others per module |
| Read / write | yes / yes, including signatures, seals and encryption |
ofdrw implements GB/T 33190 in Java and is the most complete open-source OFD library. It covers the whole document model, a layout engine that flows paragraphs, tables and images onto pages, text extraction, merging and splitting, attachments, annotations and watermarks, digital signatures and electronic seals with Chinese national cryptography (SM2, SM3), GM/T 0099 encryption, OFD-A archive checks, and conversion between OFD and PDF, images, SVG, HTML and text.
The project keeps its public API backward compatible. Documentation and comments are in Chinese, and the test classes in each module are the best examples. The authors recommend the separate ofdrw-viewer (JavaScript) for displaying OFD, and the converter only for format migration.
Installation#
Maven, all modules:
<dependency>
<groupId>org.ofdrw</groupId>
<artifactId>ofdrw-full</artifactId>
<version>2.5.1</version>
</dependency>
Gradle:
implementation("org.ofdrw:ofdrw-full:2.5.1")
To keep dependencies small, use only the modules you need, e.g. ofdrw-reader for reading or ofdrw-converter for conversion.
Basic usage: create an OFD document#
OFDDoc lays out content on A4 pages and writes the file when closed:
import org.ofdrw.layout.OFDDoc;
import org.ofdrw.layout.element.Paragraph;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
public class HelloOfd {
public static void main(String[] args) throws IOException {
Path path = Paths.get("hello.ofd");
try (OFDDoc doc = new OFDDoc(path)) {
doc.add(new Paragraph("你好,OFD! Hello, OFD!", 5d)); // font size in mm
}
System.out.println("written " + path.toAbsolutePath());
}
}
How to extract text from an OFD file#
ContentExtractor returns the text of each text object; page numbers start at 1:
import org.ofdrw.reader.ContentExtractor;
import org.ofdrw.reader.OFDReader;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.List;
public class ExtractText {
public static void main(String[] args) throws IOException {
try (OFDReader reader = new OFDReader(Paths.get("invoice.ofd"))) {
System.out.println(reader.getNumberOfPages() + " pages");
ContentExtractor extractor = new ContentExtractor(reader);
for (int page = 1; page <= reader.getNumberOfPages(); page++) {
List<String> lines = extractor.getPageContent(page);
System.out.println("--- page " + page + " ---");
lines.forEach(System.out::println);
}
}
}
}
extractor.extractAll() returns the text of all pages. To read only part of a page, pass a RegionTextExtractorFilter(new java.awt.Rectangle(x, y, w, h)) (millimeters) to the ContentExtractor constructor.
How to convert OFD to PDF#
PDFExporter writes the PDF when it’s closed, so always use try-with-resources. export() without arguments exports all pages; page indexes passed to it start at 0:
import org.ofdrw.converter.export.OFDExporter;
import org.ofdrw.converter.export.PDFExporter;
import java.nio.file.Path;
import java.nio.file.Paths;
public class OfdToPdf {
public static void main(String[] args) throws Exception {
Path ofd = Paths.get("invoice.ofd");
Path pdf = Paths.get("invoice.pdf");
try (OFDExporter exporter = new PDFExporter(ofd, pdf)) {
exporter.export(); // or export(0, 2) for pages 1 and 3
}
}
}
Encrypted OFD files throw an exception. Missing fonts are replaced by similar fonts and logged as warnings. TextExporter, SVGExporter and HTMLExporter work the same way.
How to convert OFD pages to PNG#
import org.ofdrw.converter.export.CanvasImageExporter;
import java.nio.file.Path;
import java.nio.file.Paths;
public class OfdToPng {
public static void main(String[] args) throws Exception {
// 15 pixels per millimeter is about 380 dpi
try (CanvasImageExporter exporter =
new CanvasImageExporter(Paths.get("invoice.ofd"), Paths.get("out"), "PNG", 15d)) {
exporter.export();
for (Path img : exporter.getImgFilePaths()) {
System.out.println(img); // out/page-0.png, out/page-1.png, ...
}
}
}
}
How to convert PDF to OFD#
PDFConverter keeps PDF text as OFD text objects:
import org.ofdrw.converter.ofdconverter.PDFConverter;
import java.nio.file.Paths;
public class PdfToOfd {
public static void main(String[] args) throws Exception {
try (PDFConverter converter = new PDFConverter(Paths.get("out.ofd"))) {
converter.convert(Paths.get("in.pdf")); // or convert(path, 0, 1) for some pages
}
}
}
How to get page size and check for signatures#
try (OFDReader reader = new OFDReader("invoice.ofd")) {
org.ofdrw.core.basicType.ST_Box box = reader.getPageSize(1); // 1-based
System.out.println(box.getWidth() + " x " + box.getHeight() + " mm");
System.out.println("signed: " + reader.hasSignature());
}
Tips#
- On Linux servers, install Chinese fonts (for example SimSun-compatible fonts) before converting or rendering: most OFD invoices reference fonts by name.
OFDReaderunpacks the ZIP into a temporary folder; close it to delete the folder.- For large files,
OFDReader.setZipFileMaxSizeraises the default size limit of unpacked files. - Signing and verifying seals is in
ofdrw-sign(OFDSigner); see its quick-start document in the repository.