This is the second half of my feature requests, see: https://github.com/Hopding/pdf-lib/issues/229.
It would be great if pdf-lib could generate PDF/A-3 documents, which in my case are required by the ZUGFeRD specification.
Hello @zimt28! This is an interesting idea. What exactly do you envision this feature looking like?
As far as I can tell, the PDF/A standard is just a subset of the PDF standard. Since pdf-lib adheres to the PDF 1.7 spec, I would think that all you need to do to generate a PDF/A document with pdf-lib is simply not use the PDF features that are disallowed in PDF/A. Or put another way, generating a PDF/A document with pdf-lib shouldn't require any new features. It just means not using particular tools offered by pdf-lib.
Hi! First of all thank you so much @Hopding for this awesome library!
I'm not the original poster of this issue, but I'm also interested in generating PDF/A documents. So, I tried to generate a valid PDF/A-3B document with the help of veraPDF (a PDF/A conformance checker).
Apparently, it's not enough to leave away certain PDF features. Some things need to be added.
Here are my findings:
Metadata key with a metadata stream as value<pdf:Subject>${options.subject}</pdf:Subject> to fix this.</rdf:RDF> in the XMP metadata added above:
<rdf:Description rdf:about="" xmlns:pdfaid="http://www.aiim.org/pdfa/ns/id/">
<pdfaid:part>3</pdfaid:part>
<pdfaid:conformance>B</pdfaid:conformance>
</rdf:Description>
const encoder = new TextEncoder();
const data = ... // Use document information and current time to make the identifier unique
const hash = await crypto.subtle.digest('SHA-512', data);
const hashArray = Array.from(new Uint8Array(hash));
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
const permanent = PDFHexString.of(hashHex);
const changing = permanent;
doc.context.trailerInfo.ID = doc.context.obj([permanent, changing]);
DeviceRGB shall only be used (...) if the file has a PDF/A OutputIntent that contains an RGB destination profilesRGB2014.icc from http://www.color.org/srgbprofiles.xalter#v2) as follows: const outputIntent = doc.context.obj({
Type: 'OutputIntent',
S: 'GTS_PDFA1',
OutputConditionIdentifier: PDFString.of('sRGB'),
DestOutputProfile: profileStreamRef,
});
const outputIntentRef = doc.context.register(outputIntent);
doc.catalog.set(PDFName.of('OutputIntents'), doc.context.obj([outputIntentRef]));
}
```
CIDFont dictionary shall contain a CIDToGIDMap entry that shall be a stream mapping from CIDs to glyph indices or the name IdentityCIDToGIDMap could be added in CustomFontEmbedder.ts somehow?(Disclaimer: I'm not sure if my code snippets are clean & correct. At least, they removed (almost all) the veraPDF validation errors for my specific use case. There might be further issues for other PDF features. @Hopding feel free to edit the code snippets if you see need.)
Edit: Oh, and Happy New Year!
this would be great as there are not other pure js libs doing this.
Just came accross this issue because I am working on adding factur-x conformance, which needs PDF-A3 conformance.
@13thirteen Your information was very helpful. Regarding your last point:
I added the following to the file "CustomFontEmbedder.ts" and achieved full PDFA-3 compliance:
In the function embedCIDFontDict I changed
const cidFontDict = context.obj({
Type: 'Font',
Subtype: this.isCFF() ? 'CIDFontType0' : 'CIDFontType2',
BaseFont: this.baseFontName,
...
to:
const cidFontDict = context.obj({
Type: 'Font',
Subtype: this.isCFF() ? 'CIDFontType0' : 'CIDFontType2',
CIDToGIDMap: 'Identity',
BaseFont: this.baseFontName,
...
Similarly, I would like to be able to choose the specification version (1.4, ..., 1.7) of the PDF document produced by pdf-lib. This would make it possible to start from an 1.7 document and remove from it features that are too recent in order to keep only the compatible part.
Most helpful comment
Hi! First of all thank you so much @Hopding for this awesome library!
I'm not the original poster of this issue, but I'm also interested in generating PDF/A documents. So, I tried to generate a valid PDF/A-3B document with the help of veraPDF (a PDF/A conformance checker).
Apparently, it's not enough to leave away certain PDF features. Some things need to be added.
Here are my findings:
Metadatakey with a metadata stream as value<pdf:Subject>${options.subject}</pdf:Subject>to fix this.</rdf:RDF>in the XMP metadata added above:<rdf:Description rdf:about="" xmlns:pdfaid="http://www.aiim.org/pdfa/ns/id/"> <pdfaid:part>3</pdfaid:part> <pdfaid:conformance>B</pdfaid:conformance> </rdf:Description>const encoder = new TextEncoder(); const data = ... // Use document information and current time to make the identifier unique const hash = await crypto.subtle.digest('SHA-512', data); const hashArray = Array.from(new Uint8Array(hash)); const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join(''); const permanent = PDFHexString.of(hashHex); const changing = permanent; doc.context.trailerInfo.ID = doc.context.obj([permanent, changing]);DeviceRGBshall only be used (...) if the file has a PDF/AOutputIntentthat contains an RGB destination profilesRGB2014.iccfrom http://www.color.org/srgbprofiles.xalter#v2) as follows:```
public static setColorProfile(doc: PDFDocument) {
const profile = ...; // Content of file sRGB2014.icc
const profileStream = doc.context.stream(profile, {
Length: profile.length,
});
const profileStreamRef = doc.context.register(profileStream);
F: 4,(setting thePrintflag) to the annotation dictionary.CIDFontdictionary shall contain aCIDToGIDMapentry that shall be a stream mapping from CIDs to glyph indices or the nameIdentityCIDToGIDMapcould be added in CustomFontEmbedder.ts somehow?(Disclaimer: I'm not sure if my code snippets are clean & correct. At least, they removed (almost all) the veraPDF validation errors for my specific use case. There might be further issues for other PDF features. @Hopding feel free to edit the code snippets if you see need.)
Edit: Oh, and Happy New Year!