Skip to content

Commit

Permalink
Merge pull request #250 from syjer/pdf-a-support
Browse files Browse the repository at this point in the history
Cherry-pick from PR #143: pdf/a support
  • Loading branch information
danfickle authored Jul 14, 2018
2 parents e4849ea + 563d450 commit 02c2a66
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
import com.openhtmltopdf.render.PageBox;
import com.openhtmltopdf.render.RenderingContext;
import com.openhtmltopdf.render.ViewportBox;
import com.openhtmltopdf.render.AbstractOutputDevice.ClipInfo;
import com.openhtmltopdf.render.displaylist.DisplayListCollector;
import com.openhtmltopdf.render.displaylist.DisplayListContainer;
import com.openhtmltopdf.render.displaylist.DisplayListPainter;
Expand All @@ -49,14 +48,20 @@
import com.openhtmltopdf.util.Configuration;
import com.openhtmltopdf.util.ThreadCtx;
import com.openhtmltopdf.util.XRLog;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
import org.apache.pdfbox.pdmodel.common.PDMetadata;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDMarkInfo;
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot;
import org.apache.pdfbox.pdmodel.encryption.PDEncryption;
import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent;
import org.apache.xmpbox.XMPMetadata;
import org.apache.xmpbox.schema.AdobePDFSchema;
import org.apache.xmpbox.schema.PDFAIdentificationSchema;
import org.apache.xmpbox.schema.XMPBasicSchema;
import org.apache.xmpbox.type.BadFieldValueException;
import org.apache.xmpbox.xml.XmpSerializer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
Expand Down Expand Up @@ -97,7 +102,11 @@ public class PdfBoxRenderer implements Closeable {

// Usually 1.7
private float _pdfVersion;


private String _pdfAConformance;

private byte[] _colorProfile;

private boolean _testMode;

private PDFCreationListener _listener;
Expand All @@ -122,8 +131,13 @@ public class PdfBoxRenderer implements Closeable {

_producer = state._producer;


_svgImpl = state._svgImpl;
_mathmlImpl = state._mathmlImpl;

_pdfAConformance = state._pdfAConformance;
_colorProfile = state._colorProfile;

_dotsPerPoint = DEFAULT_DOTS_PER_POINT;
_testMode = state._testMode;
_useFastMode = state._useFastRenderer;
Expand Down Expand Up @@ -621,7 +635,11 @@ private void writePDF(List<PageBox> pages, RenderingContext c, Rectangle2D first
c.setPageCount(pageCount);
firePreWrite(pageCount); // opportunity to adjust meta data
setDidValues(doc); // set PDF header fields from meta data


if (_pdfAConformance != null) {
addPdfASchema(doc, _pdfAConformance);
}

for (int i = 0; i < pageCount; i++) {
PageBox currentPage = pages.get(i);

Expand All @@ -643,10 +661,63 @@ private void writePDF(List<PageBox> pages, RenderingContext c, Rectangle2D first
_outputDevice.finish(c, _root);
}

private void addPdfASchema(PDDocument document, String conformance) {
PDDocumentInformation information = document.getDocumentInformation();
XMPMetadata metadata = XMPMetadata.createXMPMetadata();

try {
PDFAIdentificationSchema pdfaid = metadata.createAndAddPFAIdentificationSchema();
pdfaid.setConformance(conformance);
pdfaid.setPart(1);

AdobePDFSchema pdfSchema = metadata.createAndAddAdobePDFSchema();
pdfSchema.setProducer(information.getProducer());

XMPBasicSchema xmpBasicSchema = metadata.createAndAddXMPBasicSchema();
xmpBasicSchema.setCreateDate(information.getCreationDate());

PDMetadata metadataStream = new PDMetadata(document);
PDMarkInfo markInfo = new PDMarkInfo();
markInfo.setMarked(true);

// add to catalog
PDDocumentCatalog catalog = document.getDocumentCatalog();
catalog.setMetadata(metadataStream);
// for pdf/a-1 compliance, add the StructTreeRoot that https://www.pdf-online.com/osa/validate.aspx was
// complaining. Based on https://stackoverflow.com/a/46806392
catalog.setStructureTreeRoot(new PDStructureTreeRoot());
//

catalog.setMarkInfo(markInfo);

XmpSerializer serializer = new XmpSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.serialize(metadata, baos, true);
metadataStream.importXMPMetadata( baos.toByteArray() );


if (_colorProfile != null) {
ByteArrayInputStream colorProfile = new ByteArrayInputStream(_colorProfile);
PDOutputIntent oi = new PDOutputIntent(document, colorProfile);
oi.setInfo("sRGB IEC61966-2.1");
oi.setOutputCondition("sRGB IEC61966-2.1");
oi.setOutputConditionIdentifier("sRGB IEC61966-2.1");
oi.setRegistryName("http://www.color.org");
catalog.addOutputIntent(oi);
}
} catch (BadFieldValueException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (TransformerException e) {
throw new RuntimeException(e);
}
}

// Sets the document information dictionary values from html metadata
private void setDidValues(PDDocument doc) {
PDDocumentInformation info = new PDDocumentInformation();

info.setCreationDate(Calendar.getInstance());

if (_producer == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,30 @@ public PdfRendererBuilder usePdfVersion(float version) {
state._pdfVersion = version;
return this;
}

/**
* Set the PDF/A conformance, typically we use PDF/A-1
*
* @param pdfAConformance
* @return
*/
public PdfRendererBuilder usePdfAConformance(PdfAConformance pdfAConformance) {
this.state._pdfAConformance = pdfAConformance.value;
return this;
}

/**
* Sets the color profile, needed for PDF/A conformance.
*
* You can use the sRGB.icc from https://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/resources/org/apache/pdfbox/resources/pdfa/
*
* @param colorProfile
* @return
*/
public PdfRendererBuilder useColorProfile(byte[] colorProfile) {
this.state._colorProfile = colorProfile;
return this;
}

/**
* By default, this project creates an entirely in-memory <code>PDDocument</code>.
Expand Down Expand Up @@ -214,5 +238,21 @@ private AddedFont(FSSupplier<InputStream> supplier, File fontFile, Integer weigh
this.style = style;
}
}

/**
* Various level of PDF/A conformance:
*
* PDF/A-1, PDF/A-2 and PDF/A-3
*/
public enum PdfAConformance {

PDF_A_1("A"), PDF_A_2("B"), PDF_A_3("U");

PdfAConformance(String value) {
this.value = value;
}

private final String value;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ public class PdfRendererBuilderState extends BaseRendererBuilder.BaseRendererBui
public float _pdfVersion = 1.7f;
public String _producer;
public PDDocument pddocument;
public String _pdfAConformance;
public byte[] _colorProfile;
}

0 comments on commit 02c2a66

Please sign in to comment.