PdfConformance.java
/*
This file is part of the iText (R) project.
Copyright (c) 1998-2026 Apryse Group NV
Authors: Apryse Software.
This program is offered under a commercial and under the AGPL license.
For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
AGPL licensing:
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itextpdf.kernel.pdf;
import com.itextpdf.kernel.exceptions.PdfException;
import com.itextpdf.kernel.xmp.XMPException;
import com.itextpdf.kernel.xmp.XMPMeta;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* The class represents possible PDF document conformance.
*/
public class PdfConformance {
public static final String PDF_A_4_REVISION = "2020";
public static final PdfConformance PDF_A_1A = new PdfConformance(PdfAConformance.PDF_A_1A);
public static final PdfConformance PDF_A_1B = new PdfConformance(PdfAConformance.PDF_A_1B);
public static final PdfConformance PDF_A_2A = new PdfConformance(PdfAConformance.PDF_A_2A);
public static final PdfConformance PDF_A_2B = new PdfConformance(PdfAConformance.PDF_A_2B);
public static final PdfConformance PDF_A_2U = new PdfConformance(PdfAConformance.PDF_A_2U);
public static final PdfConformance PDF_A_3A = new PdfConformance(PdfAConformance.PDF_A_3A);
public static final PdfConformance PDF_A_3B = new PdfConformance(PdfAConformance.PDF_A_3B);
public static final PdfConformance PDF_A_3U = new PdfConformance(PdfAConformance.PDF_A_3U);
public static final PdfConformance PDF_A_4 = new PdfConformance(PdfAConformance.PDF_A_4);
public static final PdfConformance PDF_A_4E = new PdfConformance(PdfAConformance.PDF_A_4E);
public static final PdfConformance PDF_A_4F = new PdfConformance(PdfAConformance.PDF_A_4F);
public static final PdfConformance PDF_UA_1 = new PdfConformance(PdfUAConformance.PDF_UA_1);
public static final PdfConformance PDF_UA_2 = new PdfConformance(PdfUAConformance.PDF_UA_2);
public static final PdfConformance WELL_TAGGED_PDF_FOR_ACCESSIBILITY =
new PdfConformance(Collections.singletonList(WellTaggedPdfConformance.FOR_ACCESSIBILITY));
public static final PdfConformance WELL_TAGGED_PDF_FOR_REUSE =
new PdfConformance(Collections.singletonList(WellTaggedPdfConformance.FOR_REUSE));
public static final PdfConformance PDF_NONE_CONFORMANCE = new PdfConformance();
private static final int WTPDF_FLAG_NONE = 0;
private static final int WTPDF_FLAG_ACCESSIBILITY = 1;
private static final int WTPDF_FLAG_REUSE = 2;
private static final int WTPDF_FLAG_ACCESSIBILITY_AND_REUSE = WTPDF_FLAG_ACCESSIBILITY | WTPDF_FLAG_REUSE;
private final PdfAConformance aConformance;
private final PdfUAConformance uaConformance;
private int wtpdfFlag = WTPDF_FLAG_NONE;
/**
* Creates a new {@link PdfConformance} instance based on PDF/A, PDF/UA and Well Tagged PDF conformance.
*
* @param aConformance the PDF/A conformance
* @param uaConformance the PDF/UA conformance
* @param wtpdfConformance the Well Tagged PDF conformance
*/
public PdfConformance(PdfAConformance aConformance, PdfUAConformance uaConformance,
WellTaggedPdfConformance wtpdfConformance) {
this.aConformance = aConformance;
this.uaConformance = uaConformance;
setWtPdfFlag(wtpdfConformance);
}
/**
* Creates a new {@link PdfConformance} instance based on PDF/A, PDF/UA and Well Tagged PDF conformance.
*
* @param aConformance the PDF/A conformance
* @param uaConformance the PDF/UA conformance
* @param wtpdfConformanceList the Well Tagged PDF conformance
*/
public PdfConformance(PdfAConformance aConformance, PdfUAConformance uaConformance,
List<WellTaggedPdfConformance> wtpdfConformanceList) {
this.aConformance = aConformance;
this.uaConformance = uaConformance;
setWtPdfFlag(wtpdfConformanceList);
}
/**
* Creates a new {@link PdfConformance} instance based on PDF/A and PDF/UA conformance.
*
* @param aConformance the PDF/A conformance
* @param uaConformance the PDF/UA conformance
*/
public PdfConformance(PdfAConformance aConformance, PdfUAConformance uaConformance) {
this.aConformance = aConformance;
this.uaConformance = uaConformance;
}
/**
* Creates a new {@link PdfConformance} instance based on only PDF/A conformance.
*
* @param aConformance the PDF/A conformance
*/
public PdfConformance(PdfAConformance aConformance) {
this.aConformance = aConformance;
this.uaConformance = null;
}
/**
* Creates a new {@link PdfConformance} instance based on only PDF/UA conformance.
*
* @param uaConformance the PDF/UA conformance
*/
public PdfConformance(PdfUAConformance uaConformance) {
this.uaConformance = uaConformance;
this.aConformance = null;
}
/**
* Creates a new {@link PdfConformance} instance based on only Well Tagged PDF conformance.
*
* @param wtpdfConformance the Well Tagged PDF conformance
*/
public PdfConformance(List<WellTaggedPdfConformance> wtpdfConformance) {
setWtPdfFlag(wtpdfConformance);
this.uaConformance = null;
this.aConformance = null;
}
/**
* Creates a new {@link PdfConformance} instance based on only Well Tagged PDF conformance.
*
* @param wtpdfConformance the Well Tagged PDF conformance
*/
public PdfConformance(WellTaggedPdfConformance wtpdfConformance) {
setWtPdfFlag(wtpdfConformance);
this.uaConformance = null;
this.aConformance = null;
}
/**
* Creates a new {@link PdfConformance} instance without any conformance.
*/
public PdfConformance() {
this.aConformance = null;
this.uaConformance = null;
}
/**
* Gets {@link PdfConformance} instance from {@link XMPMeta}.
*
* @param meta the meta data to parse
*
* @return the {@link PdfConformance} instance
*/
public static PdfConformance getConformance(XMPMeta meta) {
if (meta == null) {
return PdfConformance.PDF_NONE_CONFORMANCE;
}
final PdfAConformance aLevel = PdfConformanceXmpMetaDataUtil.getAConformance(meta);
final PdfUAConformance uaLevel = PdfConformanceXmpMetaDataUtil.getUAConformanceFromXmp(meta);
final List<WellTaggedPdfConformance> wtpdfConformanceList =
PdfConformanceXmpMetaDataUtil.getWtpdfConformanceFromXmp(
meta);
return new PdfConformance(aLevel, uaLevel, wtpdfConformanceList);
}
/**
* Sets required fields into XMP metadata according to passed PDF conformance.
*
* @param xmpMeta the xmp metadata to which required PDF conformance fields will be set
* @param conformance the PDF conformance which fields should be set into XMP metadata.
*
* @throws XMPException if the file is not well-formed XML or if the parsing fails
* @deprecated Use {@link #setConformanceToXmp(XMPMeta)} method of {@link PdfConformance} instance instead.
*/
@Deprecated()
public static void setConformanceToXmp(XMPMeta xmpMeta, PdfConformance conformance) throws XMPException {
if (conformance == null) {
return;
}
conformance.setConformanceToXmp(xmpMeta);
}
/**
* Gets an instance of {@link PdfAConformance} based on passed part and level.
*
* @param part the part of PDF/A conformance
* @param level the level of PDF/A conformance
*
* @return the {@link PdfAConformance} instance or {@code null} if there is no PDF/A conformance for passed
* parameters
*
*/
public static PdfAConformance getAConformance(String part, String level) {
return PdfConformanceXmpMetaDataUtil.getAConformance(part, level);
}
/**
* Sets required fields into XMP metadata according to passed PDF conformance.
*
* @param xmpMeta the xmp metadata to which required PDF conformance fields will be set
*
* @throws XMPException if the file is not well-formed XML or if the parsing fails
*/
public void setConformanceToXmp(XMPMeta xmpMeta) throws XMPException {
PdfConformanceXmpMetaDataUtil.setConformanceToXmp(this, xmpMeta);
}
/**
* Checks if any PDF/A conformance is specified.
*
* @return {@code true} if PDF/A conformance is specified, otherwise {@code false}
*/
public boolean isPdfA() {
return aConformance != null;
}
/**
* Checks if any PDF/UA conformance is specified.
*
* @return {@code true} if PDF/UA conformance is specified, otherwise {@code false}
*/
public boolean isPdfUA() {
return uaConformance != null;
}
/**
* Checks if any Well Tagged PDF conformance is specified.
*
* @return {@code true} if Well Tagged PDF conformance is specified, otherwise {@code false}
*/
public boolean isWtpdf() {
return wtpdfFlag != 0;
}
/**
* Checks if any of PDF/A, PDF/UA or Well Tagged PDF conformance is specified
*
* @return {@code true} if PDF/A, PDF/UA or Well Tagged PDF conformance is specified, otherwise {@code false}
*/
public boolean conformsToAny() {
return isPdfA() || isPdfUA() || isWtpdf();
}
/**
* Gets the {@link PdfAConformance} instance if specified.
*
* @return the specified {@link PdfAConformance} instance or {@code null}.
*/
public PdfAConformance getAConformance() {
return aConformance;
}
/**
* Gets the {@link PdfUAConformance} instance if specified.
*
* @return the specified {@link PdfUAConformance} instance or {@code null}.
*/
public PdfUAConformance getUAConformance() {
return uaConformance;
}
/**
* Gets the list of {@link WellTaggedPdfConformance} instances if specified.
*
* @return the list of specified {@link WellTaggedPdfConformance} instances or empty list.
*/
public List<WellTaggedPdfConformance> getWtpdfConformances() {
List<WellTaggedPdfConformance> wtpdfConformanceList = new ArrayList<>();
if ((wtpdfFlag & WTPDF_FLAG_ACCESSIBILITY) != 0) {
wtpdfConformanceList.add(WellTaggedPdfConformance.FOR_ACCESSIBILITY);
}
if ((wtpdfFlag & WTPDF_FLAG_REUSE) != 0) {
wtpdfConformanceList.add(WellTaggedPdfConformance.FOR_REUSE);
}
return wtpdfConformanceList;
}
/**
* Gets the {@link WellTaggedPdfConformance} instance if specified.
*
* @param wtPdfConformance the Well Tagged PDF conformance to check
*
* @return the specified {@link WellTaggedPdfConformance} instance or {@code null}.
*/
public boolean conformsTo(WellTaggedPdfConformance wtPdfConformance) {
switch (wtPdfConformance) {
case FOR_ACCESSIBILITY:
return (wtpdfFlag & WTPDF_FLAG_ACCESSIBILITY) != 0;
case FOR_REUSE:
return (wtpdfFlag & WTPDF_FLAG_REUSE) != 0;
default:
throw new IllegalArgumentException("Unknown Well Tagged PDF conformance: " + wtPdfConformance);
}
}
/**
* Checks if specified PDF/UA conformance is present in this {@link PdfConformance} instance.
*
* @param uaConformance the PDF/UA conformance to check
*
* @return {@code true} if specified PDF/UA conformance is present in this {@link PdfConformance} instance,
* otherwise
*/
public boolean conformsTo(PdfUAConformance uaConformance) {
return this.uaConformance == uaConformance;
}
/**
* Checks if specified PDF/A conformance is present in this {@link PdfConformance} instance.
*
* @param aConformance the PDF/A conformance to check
*
* @return {@code true} if specified PDF/A conformance is present in this {@link PdfConformance} instance, otherwise
*/
public boolean conformsTo(PdfAConformance aConformance) {
return this.aConformance == aConformance;
}
/**
* Checks if any of specified conformance is present in this {@link PdfConformance} instance.
*
* @param conformanceList the conformances to check
*
* @return {@code true} if any of specified conformances is present in this {@link PdfConformance} instance,
* otherwise {@code false}
*/
public boolean conformsTo(PdfConformance... conformanceList) {
if (conformanceList == null) {
return false;
}
for (Object conformance : conformanceList) {
if (this.equals(conformance)) {
return true;
}
}
return false;
}
/**
* Checks if any PDF/A or PDF/UA conformance is specified.
*
* @return {@code true} if PDF/A or PDF/UA conformance is specified, otherwise {@code false}
*
* @deprecated Use {@link #conformsToAny()} instead, which also checks for Well Tagged PDF conformance.
*/
@Deprecated
public boolean isPdfAOrUa() {
return isPdfA() || isPdfUA();
}
@Override
public int hashCode() {
int result = aConformance != null ? aConformance.hashCode() : 0;
result = 31 * result + (uaConformance != null ? uaConformance.hashCode() : 0);
result = 31 * result + wtpdfFlag;
return result;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
PdfConformance that = (PdfConformance) o;
boolean checkConformance = aConformance == that.aConformance && uaConformance == that.uaConformance;
if (!checkConformance) {
return false;
}
if (this.wtpdfFlag != that.wtpdfFlag) {
return false;
}
return true;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("Conformance:");
if (isPdfA()) {
sb.append(" A-").append(aConformance.getPart());
if (aConformance.getLevel() != null) {
sb.append(aConformance.getLevel());
}
}
if (isPdfUA()) {
sb.append(" UA-").append(uaConformance.getPart());
}
if (isWtpdf()) {
sb.append(" WTPDF-");
switch (wtpdfFlag) {
case WTPDF_FLAG_ACCESSIBILITY:
sb.append("FOR_ACCESSIBILITY");
break;
case WTPDF_FLAG_REUSE:
sb.append("FOR_REUSE");
break;
case WTPDF_FLAG_ACCESSIBILITY_AND_REUSE:
sb.append("FOR_ACCESSIBILITY_AND_REUSE");
break;
default:
sb.append("UNKNOWN");
}
}
return sb.toString().trim();
}
private void setWtPdfFlag(List<WellTaggedPdfConformance> wtpdfConformanceList) {
if (wtpdfConformanceList == null) {
throw new PdfException("Well Tagged PDF conformance list cannot be null");
}
for (WellTaggedPdfConformance wtpdfConformance : wtpdfConformanceList) {
setWtPdfFlag(wtpdfConformance);
}
}
private void setWtPdfFlag(WellTaggedPdfConformance wtpdfConformance) {
if (wtpdfConformance == null) {
throw new PdfException("Well Tagged PDF conformance list cannot be null");
}
switch (wtpdfConformance) {
case FOR_ACCESSIBILITY:
wtpdfFlag |= WTPDF_FLAG_ACCESSIBILITY;
break;
case FOR_REUSE:
wtpdfFlag |= WTPDF_FLAG_REUSE;
break;
default:
throw new IllegalArgumentException("Unknown Well Tagged PDF conformance: " + wtpdfConformance);
}
}
}