Archive a PDF document to PDF/A
The Pdftools SDK lets you archive a PDF document so that it meets a defined PDF/A standard and conformance level, making the minimum changes necessary to the PDF structure and objects so it complies. It provides detailed information about any changes that were made during the conversion process.
The Pdftools SDK supports conversion to the following PDF/A standards:
- PDF/A-1 (ISO 19005-1)
- PDF/A-2 (ISO 19005-2)
- PDF/A-3 (ISO 19005-3)
Within the PDF/A standards, the following conformance levels are supported:
- B (Basic)
- U (Unicode, only PDF/A-2 and PDF/A-3)
- A (Accessibility)
For more information about supported PDF/A standards, see PDF/A overview.
Steps to archive a document:
- Reading the input document
- Creating a Conformance object
- Creating a Validator object
- Running the Analyze method
- Creating a Converter object
- Running the Convert method
- Checking the conversion results
- Full example
You need to initialize the library.
Reading the input document
First you need to read the PDF document you want to archive. To do this, load the input document from the file system into a read-only PDF Document
.
This Document
can then later be passed to the Validator
and Converter
.
- .NET
- Java
// Open image document
using var inStr = File.OpenRead(inPath);
using var inDoc = Document.Open(inStr);
// Open input document
FileStream inStr = new FileStream(inPath, FileStream.Mode.READ_ONLY);
com.pdftools.pdf.Document inDoc = com.pdftools.pdf.Document.open(inStr);
Creating a Conformance object
The document conversion process begins with the creation of a Conformance
object.
The Conformance
object defines the PDF/A standard and level to which the output document must conform.
This example uses the PDF/A-2 standard (2
), with conformance level B (Conformance.PdfALevel.B
).
- .NET
- Java
// Create a Conformance object that specifies the PDF/A level against which the document is to be validated prior to conversion.
// Here, PDF/A-2b is specified.
Conformance conformance = new Conformance(2, Conformance.PdfALevel.B);
// Create a Conformance object that specifies the PDF/A level against which the document is to be validated prior to conversion.
// Here, PDF/A-2b is specified.
Conformance conformance = new Conformance(new Conformance.PdfAVersion(2, Conformance.PdfAVersion.Level.B));
Creating a Validator object
The Validator
object analyzes the conformance of the input PDF document with the PDF/A standard and level defined in the Conformance
object.
This step is similar to the first step of the PDF/A validation process. However, during the PDF/A conversion process, additional information is also generated about the potential conformance level of the document.
- .NET
- Java
// Create the Validator object, and use the Conformance object to create
// an AnalysisOptions object that controls the behavior of the Validator.
var validator = new Validator();
var analysisOptions = new AnalysisOptions() { Conformance = conformance };
// Create the Validator object, and use the Conformance object to create
// an AnalysisOptions object that controls the behavior of the Validator.
Validator validator = new Validator();
AnalysisOptions analysisOptions = new AnalysisOptions();
analysisOptions.setConformance(conformance);
Running the Analyze method
In addition to evaluating the document's conformance with the defined PDF/A standard and level, the Analyze
method also provides a recommendation on whether the input document should be converted to PDF/A.
The Analyze
method recommends conversion in the following cases:
- If
IsConforming
isfalse
, i.e., if the document does not conform to the requiredConformance
. - If the document is conforming, but there are other issues where conversion is highly recommended. For example, if corner-cases of the PDF/A specification that are known to cause problems for PDF viewers are detected.
When conversion is recommended, the recommended output PDF/A standard and level is provided in the RecommendedConformance
value of the AnalysisResult
object.
This RecommendedConformance
is the highest possible PDF/A level to which the document can conform.
Setting a higher level for the conversion typically results in a conformance exception.
Even if the RecommendedConformance
is higher than the Conformance
passed to the AnalysisOptions
, you do not need to increase the level of the Conformance
passed to the ConversionOptions
, because this level is automatically updated to the highest achievable level.
Therefore, you can always set the Conformance
provided in the AnalysisOptions
to the lowest acceptable level.
- .NET
- Java
// Run the analysis, and check the results.
// Only proceed if document is not conforming.
var analysisResult = validator.Analyze(inDoc, analysisOptions);
if (analysisResult.IsConversionRecommended) {
return; // No conversion is required.
}
// Run the analysis, and check the results.
// Only proceed if document is not conforming.
AnalysisResult analysisResult = validator.analyze(inDoc, analysisOptions);
if (analysisResult.getIsConversionRecommended())
{
return; // No conversion is required.
}
Creating a Converter object
The Converter
object converts the input PDF document into an output document that conforms to the defined PDF/A standard and level.
When the Converter
makes changes to the document during the conversion process, it emits ConversionEvent
events that provide detailed information about the type of change and where the change has been made in the output PDF/A document.
Even if the output document meets all required standards, the conversion may have resulted in differences that are acceptable in some processes, but not in others.
Because of this, a handler function should listen to the ConversionEvent
events and execute business logic based on the information contained in them.
Each ConversionEvent
has a Severity
that indicates the following types of changes were made to the output document:
- Information: Changes were made, but the change had no visible impact on the document.
- Warning: Changes were made that may have visible impacts. Check the output file to decide if the result is acceptable.
- Error: Changes were not successful. The document could not be converted to the desired conformance level.
You should check for the highest EventSeverity
that occurred during the conversion, as it makes it easier to troubleshoot errors later.
- .NET
- Java
// Create a converter object
var converter = new Converter();
// Add handler for conversion events
var eventsSeverity = EventSeverity.Information;
converter.ConversionEvent += (s, e) =>
{
// Get the event's suggested severity
var severity = e.Severity;
// Optionally, the suggested severity can be changed according to
// the requirements of your conversion process and, for example,
// the event's category (e.Category).
if (severity > eventsSeverity)
eventsSeverity = severity;
// Report conversion event
Console.WriteLine("- {0} {1}: {2} ({3}{4})",
severity.ToString()[0], e.Category, e.Message, e.Context, e.PageNo > 0 ? " page " + e.PageNo : ""
);
};
// Create a converter object
Converter converter = new Converter();
// Add handler for conversion events
class EventListener implements ConversionEventListener
{
private EventSeverity eventsSeverity = EventSeverity.INFORMATION;
public EventSeverity getEventsSeverity() {
return eventsSeverity;
}
@Override
public void conversionEvent(ConversionEvent event) {
// Get the event's suggested severity
EventSeverity severity = event.getSeverity();
// Optionally, the suggested severity can be changed according to
// the requirements of your conversion process and, for example,
// the event's category (e.Category).
if (severity.ordinal() > eventsSeverity.ordinal())
eventsSeverity = severity;
// Report conversion event
System.out.format("- %c %s: %s (%s%s)%n", severity.toString().charAt(0), event.getCategory(), event.getMessage(), event.getContext(), event.getPageNo() > 0 ? " on page " + event.getPageNo() : "");
}
}
EventListener el = new EventListener();
converter.addConversionEventListener(el);
Running the Convert method
After generating the AnalysisResult
and creating the Converter
objects, the final step is to call the Convert
method.
By default, the Converter
object attempts to convert the input PDF document to the PDF/A standard and level defined in the RecommendedConformance
value in the AnalysisResult
.
It is possible to override this behavior and force conversion to a different PDF/A standard and level.
You can force conversion by passing an optional ConversionOptions
parameter to the Convert
method.
When ConversionOptions
are passed to the Convert
method but the required conformance level cannot be achieved, conversion aborts with a ConformanceException
.
- .NET
- Java
// Create a stream for the output PDF/A file.
using var outStr = File.Create(outPath);
// Convert the input document to the recommended conformance level using the converter object.
using var outDoc = converter.Convert(analysisResult, inDoc, outStr);
// Create a stream for the output PDF/A file.
FileStream outStr = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW);
// Convert the input document to the recommended conformance level using the converter object.
Document outDoc = converter.convert(analysisResult, inDoc, outStr);
Checking the conversion results
If you plan to perform further processing, you may want to check the result of the conversion first.
The overall success can be read from the highest EventSeverity
that has been collected by the event handler during the conversion:
- .NET
- Java
// Check if critical conversion events occurred
switch (eventsSeverity)
{
case EventSeverity.Information:
Console.WriteLine(\$"Successfully converted document to {outDoc.Conformance}.");
break;
case EventSeverity.Warning:
Console.WriteLine(\$"Warnings occurred during the conversion of document to {outDoc.Conformance}.");
Console.WriteLine(\$"Check the output file to decide if the result is acceptable.");
break;
case EventSeverity.Error:
throw new Exception(\$"Unable to convert document to {conformance} because of critical conversion events.");
}
// Check if critical conversion events occurred
switch (el.getEventsSeverity())
{
case INFORMATION:
System.out.println("Successfully converted document to " + outDoc.getConformance() + ".");
break;
case WARNING:
System.out.println("Warnings occurred during the conversion of document to " + outDoc.getConformance() + ".");
System.out.println("Check the output file to decide if the result is acceptable.");
break;
case ERROR:
throw new Exception("Unable to convert document to " + conformance + " because of critical conversion events.");
}
Here's an example of the output that is generated by this sample code:
- Information: ManagedColors: Created calibrated color space substitute for DeviceRGB. (content of page 1)
Successfully converted document to PDF/A-2u.
Full example
- .NET
- Java
// Open input document
using var inStr = File.OpenRead(inPath);
using var inDoc = Document.Open(inStr);
// Create a Conformance object that specifies the PDF/A level against which the document is to be validated prior to conversion.
// Here, PDF/A-2b is specified.
var conformance = new Conformance(2, Conformance.PdfALevel.B);
// Create the Validator object, and use the Conformance object to create
// an AnalysisOptions object that controls the behavior of the Validator.
var validator = new Validator();
var analysisOptions = new AnalysisOptions() { Conformance = conformance };
// Run the analysis, and check the results.
// Only proceed if document is not conforming.
var analysisResult = validator.Analyze(inDoc, analysisOptions);
if (analysisResult.IsConversionRecommended) {
return; // No conversion is required.
}
// Create a converter object
var converter = new Converter();
// Add handler for conversion events
var eventsSeverity = EventSeverity.Information;
converter.ConversionEvent += (s, e) =>
{
// Get the event's suggested severity
var severity = e.Severity;
// Optionally, the suggested severity can be changed according to
// the requirements of your conversion process and, for example,
// the event's category (e.Category).
if (severity > eventsSeverity)
eventsSeverity = severity;
// Report conversion event
Console.WriteLine("- {0} {1}: {2} ({3}{4})",
severity.ToString()[0], e.Category, e.Message, e.Context, e.PageNo > 0 ? " page " + e.PageNo : ""
);
};
// Create stream for output file
using var outStr = File.Create(outPath);
// Convert the input document to PDF/A using the converter object
// and its conversion event handler
using var outDoc = converter.Convert(analysisResult, inDoc, outStr);
// Check if critical conversion events occurred
switch (eventsSeverity)
{
case EventSeverity.Information:
Console.WriteLine(\$"Successfully converted document to {outDoc.Conformance}.");
break;
case EventSeverity.Warning:
Console.WriteLine(\$"Warnings occurred during the conversion of document to {outDoc.Conformance}.");
Console.WriteLine(\$"Check the output file to decide if the result is acceptable.");
break;
case EventSeverity.Error:
throw new Exception(\$"Unable to convert document to {conformance} because of critical conversion events.");
}
// Open input document
try (FileStream inStr = new FileStream(inPath, FileStream.Mode.READ_ONLY);
Document inDoc = Document.open(inStr))
{
// Create a Conformance object that specifies the PDF/A level against which the document is to be validated prior to conversion.
// Here, PDF/A-2b is specified.
Conformance conformance = new Conformance(new Conformance.PdfAVersion(2, Conformance.PdfAVersion.Level.B));
// Create the Validator object, and use the Conformance object to create
// an AnalysisOptions object that controls the behavior of the Validator.
Validator validator = new Validator();
AnalysisOptions analysisOptions = new AnalysisOptions();
analysisOptions.setConformance(conformance);
// Run the analysis, and check the results.
// Only proceed if document is not conforming.
AnalysisResult analysisResult = validator.analyze(inDoc, analysisOptions);
if (analysisResult.getIsConversionRecommended())
{
return; // No conversion is required.
}
// Create output stream
try (FileStream outStr = new FileStream(outPath, FileStream.Mode.READ_WRITE_NEW))
{
// Create a converter object
Converter converter = new Converter();
// Add handler for conversion events
class EventListener implements ConversionEventListener
{
private EventSeverity eventsSeverity = EventSeverity.INFORMATION;
public EventSeverity getEventsSeverity() {
return eventsSeverity;
}
@Override
public void conversionEvent(ConversionEvent event) {
// Get the event's suggested severity
EventSeverity severity = event.getSeverity();
// Optionally, the suggested severity can be changed according to
// the requirements of your conversion process and, for example,
// the event's category (e.Category).
if (severity.ordinal() > eventsSeverity.ordinal())
eventsSeverity = severity;
// Report conversion event
System.out.format("- %c %s: %s (%s%s)%n", severity.toString().charAt(0), event.getCategory(), event.getMessage(), event.getContext(), event.getPageNo() > 0 ? " on page " + event.getPageNo() : "");
}
}
EventListener el = new EventListener();
converter.addConversionEventListener(el);
// Convert the input document to PDF/A using the converter object
// and its conversion event handler
try (Document outDoc = converter.convert(analysisResult, inDoc, outStr))
{
// Check if critical conversion events occurred
switch (el.getEventsSeverity())
{
case INFORMATION:
System.out.println("Successfully converted document to " + outDoc.getConformance() + ".");
break;
case WARNING:
System.out.println("Warnings occurred during the conversion of document to " + outDoc.getConformance() + ".");
System.out.println("Check the output file to decide if the result is acceptable.");
break;
case ERROR:
throw new Exception("Unable to convert document to " + conformance + " because of critical conversion events.");
}
}
}
}
If you convert a signed PDF to PDF/A, any signatures present in the document are removed before conversion. Therefore, if you need to include a signature in a PDF/A conformant document, first convert to PDF/A and then sign the document.