Skip to content

Latest commit

 

History

History
208 lines (162 loc) · 11.4 KB

File metadata and controls

208 lines (162 loc) · 11.4 KB

tabula-java Build Status

tabula-java is a library for extracting tables from PDF files — it is the table extraction engine that powers Tabula (repo). You can use tabula-java as a command-line tool to programmatically extract tables from PDFs.

© 2014-2020 Manuel Aristarán. Available under MIT License. See LICENSE.

Download

From the releases page you can grab either:

  • the tabula-*-jar-with-dependencies.jar — runs on any Java 8+ JVM, on Mac, Windows and Linux.
  • the tabula-native-* binary — a GraalVM-compiled native executable for a specific OS/architecture. No JVM required, faster startup.

Both produce identical output; pick whichever fits your environment.

This is a fork of tabulapdf/tabula-java that tracks upstream dependency updates (PDFBox, BouncyCastle, slf4j, commons-cli, commons-csv, gson, jbig2-imageio) and adds the GraalVM native-image build described below.

Commandline Usage Examples

tabula-java provides a command line application:

$ java -jar target/tabula-1.0.5-jar-with-dependencies.jar --help
usage: tabula [-a <AREA>] [-b <DIRECTORY>] [-c <COLUMNS>] [-f <FORMAT>]
       [-g] [-h] [-i] [-l] [-n] [-o <OUTFILE>] [-p <PAGES>] [-r] [-s
       <PASSWORD>] [-t] [-u] [-v]

Tabula helps you extract tables from PDFs

 -a,--area <AREA>           -a/--area = Portion of the page to analyze.
                            Example: --area 269.875,12.75,790.5,561.
                            Accepts top,left,bottom,right i.e. y1,x1,y2,x2
                            where all values are in points relative to the
                            top left corner. If all values are between
                            0-100 (inclusive) and preceded by '%', input
                            will be taken as % of actual height or width
                            of the page. Example: --area %0,0,100,50. To
                            specify multiple areas, -a option should be
                            repeated. Default is entire page
 -b,--batch <DIRECTORY>     Convert all .pdfs in the provided directory.
 -c,--columns <COLUMNS>     X coordinates of column boundaries. Example
                            --columns 10.1,20.2,30.3. If all values are
                            between 0-100 (inclusive) and preceded by '%',
                            input will be taken as % of actual width of
                            the page. Example: --columns %25,50,80.6
 -f,--format <FORMAT>       Output format: (CSV,TSV,JSON). Default: CSV
 -g,--guess                 Guess the portion of the page to analyze per
                            page.
 -h,--help                  Print this help text.
 -i,--silent                Suppress all stderr output.
 -l,--lattice               Force PDF to be extracted using lattice-mode
                            extraction (if there are ruling lines
                            separating each cell, as in a PDF of an Excel
                            spreadsheet)
 -n,--no-spreadsheet        [Deprecated in favor of -t/--stream] Force PDF
                            not to be extracted using spreadsheet-style
                            extraction (if there are no ruling lines
                            separating each cell)
 -o,--outfile <OUTFILE>     Write output to <file> instead of STDOUT.
                            Default: -
 -p,--pages <PAGES>         Comma separated list of ranges, or all.
                            Examples: --pages 1-3,5-7, --pages 3 or
                            --pages all. Default is --pages 1
 -r,--spreadsheet           [Deprecated in favor of -l/--lattice] Force
                            PDF to be extracted using spreadsheet-style
                            extraction (if there are ruling lines
                            separating each cell, as in a PDF of an Excel
                            spreadsheet)
 -s,--password <PASSWORD>   Password to decrypt document. Default is empty
 -t,--stream                Force PDF to be extracted using stream-mode
                            extraction (if there are no ruling lines
                            separating each cell)
 -u,--use-line-returns      Use embedded line returns in cells. (Only in
                            spreadsheet mode.)
 -v,--version               Print version and exit.

It also includes a debugging tool, run java -cp ./target/tabula-1.0.5-jar-with-dependencies.jar technology.tabula.debug.Debug -h for the available options.

You can also integrate tabula-java with any JVM language. For Java examples, see the tests folder.

JVM start-up time is a lot of the cost of the tabula command, so if you're trying to extract many tables from PDFs, you have a few options for speeding it up:

  • the -b option, which allows you to convert all pdfs in a given directory
  • the drip utility
  • the Ruby, Python, R, and Node.js bindings
  • writing your own program in any JVM language (Java, JRuby, Scala) that imports tabula-java.
  • waiting for us to implement an API/server-style system (it's on the roadmap)

API Usage Examples

A simple Java code example which extracts all rows and cells from all tables of all pages of a PDF document:

InputStream in = this.getClass().getResourceAsStream("my.pdf");
try (PDDocument document = PDDocument.load(in)) {
    SpreadsheetExtractionAlgorithm sea = new SpreadsheetExtractionAlgorithm();
    PageIterator pi = new ObjectExtractor(document).extract();
    while (pi.hasNext()) {
        // iterate over the pages of the document
        Page page = pi.next();
        List<Table> table = sea.extract(page);
        // iterate over the tables of the page
        for(Table tables: table) {
            List<List<RectangularTextContainer>> rows = tables.getRows();
            // iterate over the rows of the table
            for (List<RectangularTextContainer> cells : rows) {
                // print all column-cells of the row plus linefeed
                for (RectangularTextContainer content : cells) {
                    // Note: Cell.getText() uses \r to concat text chunks
                    String text = content.getText().replace("\r", " ");
                    System.out.print(text + "|");
                }
                System.out.println();
            }
        }
    }
}

For more detail information check the Javadoc. The Javadoc API documentation can be generated (see also 'Building from Source' section) via

mvn javadoc:javadoc

which generates the HTML files to directory target/site/apidocs/

Building from Source

JVM jar

Clone this repo and run:

mvn clean package assembly:single

This produces target/tabula-<version>.jar and target/tabula-<version>-jar-with-dependencies.jar (the runnable one, technology.tabula.CommandLineApp as main class). The compiler targets Java 8 bytecode, and this single jar runs unmodified on Java 8 through at least Java 21 — there's no need to build separate jars per JVM version.

GraalVM native image

Requires a GraalVM JDK (21+) as JAVA_HOME — install one via SDKMAN: sdk install java 21.0.2-graalce.

mvn -DskipTests package assembly:single

native-image \
  -jar target/tabula-<version>-jar-with-dependencies.jar \
  -H:ConfigurationFileDirectories=native-config \
  -H:IncludeResources='org/apache/pdfbox/resources/.*' \
  -H:IncludeResources='org/apache/fontbox/.*' \
  -H:+AddAllCharsets \
  --no-fallback \
  -o target/tabula-native

Notes:

  • native-image must be built with -jar against the fat jar. Building against the raw project classpath (e.g. via native-maven-plugin's default mode) breaks AWT's native library loading at runtime (Fatal error ... Could not allocate library name) — this was tried and reverted.
  • -H:+AddAllCharsets is required because PDFBox falls back to charsets (e.g. Windows-1252) that GraalVM excludes by default.
  • native-config/ holds reflect/resource/JNI config bootstrapped with the native-image-agent tracing agent against a representative PDF corpus. If you hit missing-resource/reflection errors on PDFs with shapes not yet covered, re-run the agent with -agentlib:native-image-agent=config-merge-dir=native-config against those PDFs.
  • native-image only cross-builds for the platform it runs on — build on each target OS/arch separately (Linux, macOS, Windows) to get all platform binaries.

Releasing

To cut a release: bump <version> in pom.xml, build the artifacts above, then:

git tag v<version>
git push origin v<version>
gh release create v<version> \
  target/tabula-<version>.jar \
  target/tabula-<version>-jar-with-dependencies.jar \
  target/tabula-native \
  --title "v<version>" --notes "..."

Rename target/tabula-native per-platform (e.g. tabula-native-linux-x86_64) if you're attaching binaries built on more than one OS.

Contributing

Interested in helping out? We'd love to have your help!

You can help by:

  • Reporting a bug.
  • Adding or editing documentation.
  • Contributing code via a Pull Request.
  • Spreading the word about tabula-java to people who might be able to benefit from using it.

Backers

You can also support our continued work on tabula-java with a one-time or monthly donation on OpenCollective. Organizations who use tabula-java can also sponsor the project for acknowledgement on our official site and this README.

Special thanks to the following users and organizations for generously supporting Tabula with donations and grants:

The John S. and James L. Knight Foundation The Shuttleworth Foundation