Qoppa’s Java PDF library jPDFProcess can be packaged as a REST API and then deployed to any J2EE server to provide RESTful services. See below.
If you are looking for an-easy to install solution, Qoppa Software also offers a Restful API Module as part of Qoppa’s PDF Automation Server that be installed and started by simply running the installer for your OS (Windows, Mac, Linux or Unix) and includes more functions than the sample war below.
The following sample WAR file provides a number of PDF functions from jPDFProcess as a REST API:
1. Introduction
The jPDFRest sample implements a prototype of a RESTful API for accessing Qoppa’s jPDFProcess functionality.
This sample implements:
- transferring PDF files to/from the REST service
- returning PDF and image representations of PDF pages and
- retrieving basic document metadata information.
This prototype has very limited features, but we provide source code to the implementation so that it is very simple to add any function supported by jPDFProcess: create PDF, print PDF, convert PDF to images, merge PDF form data, add watermark, flatten comments or fields, assemble or split PDF, linearize PDF, extract content, encrypt / secure. Contact us if you need help.
2. jPDFRest Server
The jPDFRest server has been implemented and packaged (jPDFRest.war) to deploy as a servlet. This allows for easy deployment to servlet containers (Tomcat, WildFly, etc.).
The following configuration is needed before deploying the .WAR file:
- Determine (select or create) a file storage directory for use by the REST service. The REST API implementation needs somewhere to store uploaded PDF files.
- Edit the restConfig.xml file (supplied) with the license for jPDFProcess and the path of the REST storage directory created in step (a).
- Configure your servlet container with a Java system property named PDFREST_CONFIG which has as its value the path to the restConfig.xml file.
(Ex. For Tomcat this requires editing the setenv.sh (or .bat) file in Tomcat’s configuration directory, /bin, to set this property in the CATALINA_OPTS environment variable.)
After deployment the REST API can be accessed via a URL structured like this: http:// {host:port} /jPDFRest/api/… where
- {host:port} are the hostname and port where Tomcat is setup (ex. “server.company.com:8080”)
- “/jPDFRest” is the servlet context name. This defaults to the name of the deployed .WAR file – so the above example assumes that jPDFRest.WAR was deployed. The context name can be changed by renaming the .WAR file before deployment (or eliminated through configuration options for the servlet container).
After deployment the following tests can be performed to ensure that configuration and installation are correct:
- Connect to the API version URL from a browser – you should receive XML data with version information for the REST service. This will establish that the REST API service is deployed and running. Ex. http://server.com/jPDFRest/api/version
- Copy a pdf file (ex. “test.pdf”) to the REST storage directory and retrieve the first page using a URL like this: http://server.com/jPDFRest/api/pdfs/test/pages/0?format=JPEGNote: On a Linux service the file permissions for your PDF file will need to be set in order for the REST service to access that file – otherwise you will get an exception message.If this works without error (i.e. returns JPEG image) then the REST service has been configured correctly.
3. Clients
3.1. Service Client
The “Service Client” is a library that Qoppa developed to facilitate accessing the jPDFProcess REST service in a manner programmatically similar to using jPDFProcess directly.
The service client implements 4 objects:
- Service
- SvcPDFDocument
- SvcPDFPage
- SvcDocumentInfo
SvcPDFDocument, SvcPDFPage and SvcDocumentInfo are designed to perform limited operations with the same semantics as the PDFDocument, PDFPage and DocumentInfo classes in jPDFProcess.
The full API for the service client is supplied as Javadocs.
Here is a sample (that uses most significant parts of the API) to open a PDF file and save each page to a JPEG image :
import com.qoppa.pdf.rest.client; // Create service and open PDF file Service svc = new Service("localhost:8080"); SvcPDFDocument doc = new SvcPDFDocument(svc, "C:/temp/test01.pdf", null); // Get document info SvcDocumentInfo docInfo = doc.getDocumentInfo(); // Save pages for( int i=0; i<docInfo.getPageCount(); i++) { FileOutputStream fStream = null; fStream = new FileOutputStream("c:/temp/test01_page" + i + ".jpg"); SvcPDFPage page = doc.getPage(i); page.savePageAsJPEG(fStream, 300, 0.8f); fStream.close(); } // Close document (delete from server) doc.close(); |
3.2. Jersey 1.x Client API
The Jersey JAX-RS reference implementation project (http://jersey.java.net) provided a REST client API framework in its 1.x release. (Note: Jersey 2.x contains an implementation of the JAX-RS 2.0 Client API – which is different from the Jersey 1.x REST Client API.)
Using this API, a simple REST client program can be written to use the jPDFRest server.
Here is code for equivalent to the above service client sample, but written using the Jersey 1.x Client API. Note that this code uses, but doesn’t contain definitions for, a copyStream() function that copies one stream to another.
Sample Java Code
import java.io.File; import java.io.IOException; import java.io.OutputStream; import javax.ws.rs.core.MediaType; import com.qoppa.pdf.IPassword; import com.qoppa.pdf.PDFException; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.WebResource; // Open file File pdfFile = new File("c:/temp/test.pdf"); // Setup URI web resource builder Client cli = Client.<i>create</i>(); WebResource webRes = cli.resource("http://localhost:8080/jPDFRest/api/pdfs"); // Setup for POST request WebResource.Builder req = webRes.type(MediaType.<i>valueOf</i>("application/pdf")); if(password != null) req = req.header("X-pdfpass", _pass.getPasswords()[0]); // 1st password // Send PDF file via POST ClientResponse response = req.post(ClientResponse.class, pdfFile); // Parse and save {pdfId} from returned Location URI String Location = response.getHeaders().get("Location").get(0); String pdfId = Location.substring(Location.lastIndexOf('/') + 1, Location.length()); // Setup GET request for document info req = webRes.path(pdfId).path("documentInfo"); // GET document info XML & parse to SvcDocumentInfo object SvcDocumentInfo docInfo = req.get(SvcDocumentInfo.class); // Save pages for (int i=0; i<docInfo.getPageCount(); i++) { // Setup request for document page req = webRes.path(pdfId).path("pages").path(String.valueOf(i)); // GET document page as JPEG InputStream inStream = req.queryParam("format", "JPEG"). queryParam("res", "300"). queryParam("quality", "0.8"). get(InputStream.class); // Setup stream to save file FileOutputStream outStream = null; fStream = new FileOutputStream("c:/temp/test01_page" + i + ".jpg"); // Copy returned image stream to file copyStream(inStream, outStream); fStream.close(); } // Setup request to delete document from server req = webRes.path(pdfId); // DELETE document from server ClientResponse response = req.delete(ClientResponse.class); |
SvcDocumentInfo.java
import java.util.Date; import javax.xml.bind.annotation.XmlAccessType; importjavax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "DocumentInfo") @XmlAccessorType(XmlAccessType.PROPERTY) public class SvcDocumentInfo { // Storage members private String _title; private int _pageCount; private String _author; private String _subject; private String _keywords; private String _creator; private String _producer; private Date _creationDate; private Date _modDate; // Constructor: default public SvcDocumentInfo() { } // Property: Title @XmlElement(name = "title") public String getTitle() { return _title; } public void setTitle(String value) { _title = value; } // Property: Author @XmlElement(name = "author") public String getAuthor() { return _author; } public void setAuthor(String value) { _author = value; } // Property: Subject @XmlElement(name = "subject") public String getSubject() { return _subject; } public void setSubject(String value) { _subject = value; } // Property: Keywords @XmlElement(name = "keywords") public String getKeywords() { return _keywords; } public void setKeywords(String value) { _keywords = value; } // Property: Creator @XmlElement(name = "creator") public String getCreator() { return _creator; } public void setCreator(String value) { _creator = value; } // Property: Producer @XmlElement(name = "producer") public String getProducer() { return _producer; } public void setProducer(String value) { _producer = value; } // Property: CreationDate @XmlElement(name = "creationDate") public Date getCreationDate() { return _creationDate; } public void setCreationDate(Date value) { _creationDate = value; } // Property: ModDate @XmlElement(name = "modDate") public Date getModDate() { return _modDate; } public void setModDate(Date value) { _modDate = value; } // Property: PageCount @XmlElement(name = "pageCount") public int getPageCount() { return _pageCount; } public void setPageCount(int value) { _pageCount = value; } } |
3.3. Other Java Frameworks
There are other Java frameworks which could be used to write software for calling a REST API:
- Apache HttpClient
- RestEasy Client
- Jersey 2.x Client – reference implementation of JAX-RS 2.0 Client API
3.4. REST API Reference
Command |
URI |
Query Params |
Header Params |
Request Body |
Response Body |
Description |
GET | /api/version |
text/xml |
Version info as XML | |||
GET | /api/pdfs |
<docList> – JSON or XML |
Get list of document URIs | |||
POST | /api/pdfs |
application/pdf |
Upload PDF and return {pdfId} in Location header | |||
DELETE | /api/pdfs/{pdfId} | Delete PDF document | ||||
GET | /api/pdfs/{pdfId} |
application/pdf |
Get PDF document | |||
GET | /api/pdfs/{pdfId} | format=TIFF | TIF res={# dpi} comp={type} (below) stripRows={# rps} byteOrder= “BIG_ENDIAN” | “LITTLE_ENDIAN” gray=true | false quality={# qVal} dither= “None” | “FLOYD_STEINBERG” |
X-pdfpass = {password} |
image/tiff |
Get PDF as multi-page TIFF | |
GET | /api/pdfs/{pdfId}/documentInfo |
X-pdfpass = {password} |
<documentInfo> – JSON or XML |
Get document info | ||
GET | /api/pdfs/{pdfId}/pages/{pageId} |
X-pdfpass = {password} |
application/pdf |
Get single-page PDF | ||
GET | /api/pdfs/{pdfId}/pages/{pageId} | format=GIF res={dpi} |
X-pdfpass = {password} |
image/gif |
Get PDF page as GIF image | |
GET | /api/pdfs/{pdfId}/pages/{pageId} | format=JPEG | JPG res={dpi} quality={qVal} |
X-pdfpass = {password} |
image/jpeg |
Get PDF page as JPEG image | |
GET | /api/pdfs/{pdfId}/pages/{pageId} | format=PNG res={dpi} |
X-pdfpass = {password} |
image/png |
Get PDF page as PNG image | |
GET | /api/pdfs/{pdfId}/pages/{pageId} | format=TIFF | TIF res={# dpi} comp={type} (below) stripRows={# rps} byteOrder= “BIG_ENDIAN” | “LITTLE_ENDIAN” gray=true | false quality={# qVal} dither= “None” | “FLOYD_STEINBERG” |
X-pdfpass = {password} |
image/tiff |
Get PDF page as TIFF image |
Supported TIFF Compression values for {comp}
- None (i.e. empty string)
- Deflate
- CCITT_RLE
- CCITT_T4
- CCITT_T6
- FAX_GROUP3
- FAX_GROUP4
- JPEG
- LZW
- Packbits
- ZLib
Contact us if you need any help.