/** Enum class for PDF/A modes. */
public enum PDFAMode {
- /** PDF/A disabled */
+ /** PDF/A disabled. */
DISABLED("PDF/A disabled"),
- /** PDF/A-1a enabled */
- PDFA_1A("PDF/A-1a"),
- /** PDF/A-1b enabled */
- PDFA_1B("PDF/A-1b");
+ /** PDF/A-1a enabled. */
+ PDFA_1A(1, 'A'),
+ /** PDF/A-1b enabled. */
+ PDFA_1B(1, 'B'),
+ /** PDF/A-2a enabled. */
+ PDFA_2A(2, 'A'),
+ /** PDF/A-2b enabled. */
+ PDFA_2B(2, 'B'),
+ /** PDF/A-2u enabled. */
+ PDFA_2U(2, 'U');
- private String name;
+ private final String name;
+
+ private final int part;
+
+ private final char level;
/**
* Constructor to add a new named item.
*/
private PDFAMode(String name) {
this.name = name;
+ this.part = 0;
+ this.level = 0;
+ }
+
+ private PDFAMode(int part, char level) {
+ this.name = "PDF/A-" + part + Character.toLowerCase(level);
+ this.part = part;
+ this.level = level;
}
/** @return the name of the enum */
}
/**
- * Indicates whether this mode obeys the restrictions established by PDF/A-1a.
- * @return true if this mode obeys the restrictions established by PDF/A-1a.
+ * Returns {@code true} if this enum corresponds to one of the available PDF/A modes.
+ *
+ * @return {@code true} if this is not DISABLED
+ */
+ public boolean isEnabled() {
+ return this != DISABLED;
+ }
+
+ /**
+ * Returns the part of the specification this enum corresponds to.
+ *
+ * @return 1 for PDF/A-1 (ISO 19005-1), 2 for PDF/A-2 (ISO 19005-2)
+ */
+ public int getPart() {
+ return part;
+ }
+
+ /**
+ * Returns {@code true} if this enum corresponds to PDF/A-1 (ISO 19005-1).
+ */
+ public boolean isPart1() {
+ return part == 1;
+ }
+
+ /**
+ * Returns {@code true} if this enum corresponds to PDF/A-2 (ISO 19005-2).
+ */
+ public boolean isPart2() {
+ return part == 1 || part == 2;
+ }
+
+ /**
+ * Returns the conformance level for this enum.
+ *
+ * @return 'A', 'B' or 'U'
*/
- public boolean isPDFA1LevelA() {
- return (this == PDFA_1A);
+ public char getConformanceLevel() {
+ return level;
}
/**
- * Indicates whether this mode obeys the restrictions established by PDF/A-1b.
- * @return true if this mode obeys the restrictions established by PDF/A-1b.
+ * Returns {@code true} if this enum corresponds to conformance level A.
*/
- public boolean isPDFA1LevelB() {
- return (this != DISABLED);
- //PDF/A-1a is a superset of PDF/A-1b!
+ public boolean isLevelA() {
+ return level == 'A';
}
/**
* @return the PDFAMode enum object (DISABLED will be returned if no match is found)
*/
public static PDFAMode getValueOf(String s) {
- if (PDFA_1A.getName().equalsIgnoreCase(s)) {
- return PDFA_1A;
- } else if (PDFA_1B.getName().equalsIgnoreCase(s)) {
- return PDFA_1B;
- } else {
- return DISABLED;
+ for (PDFAMode mode : values()) {
+ if (mode.name.equalsIgnoreCase(s)) {
+ return mode;
+ }
}
+ return DISABLED;
}
/** {@inheritDoc} */
public String toPDFString() {
getDocumentSafely().getProfile().verifyAnnotAllowed();
String fFlag = "";
- if (getDocumentSafely().getProfile().getPDFAMode().isPDFA1LevelB()) {
+ if (getDocumentSafely().getProfile().getPDFAMode().isEnabled()) {
int f = 0;
f |= 1 << (3 - 1); //Print, bit 3
f |= 1 << (4 - 1); //NoZoom, bit 4
/** {@inheritDoc} */
protected void populateStreamDict(Object lengthEntry) {
final String filterEntry = getFilterList().buildFilterDictEntries();
- if (getDocumentSafely().getProfile().getPDFAMode().isPDFA1LevelB()
+ if (getDocumentSafely().getProfile().getPDFAMode().isPart1()
&& filterEntry != null && filterEntry.length() > 0) {
throw new PDFConformanceException(
"The Filter key is prohibited when PDF/A-1 is active");
//PDF/A identification
PDFAMode pdfaMode = pdfDoc.getProfile().getPDFAMode();
- if (pdfaMode.isPDFA1LevelB()) {
+ if (pdfaMode.isEnabled()) {
PDFAAdapter pdfa = PDFAXMPSchema.getAdapter(meta);
- pdfa.setPart(1);
- if (pdfaMode == PDFAMode.PDFA_1A) {
- pdfa.setConformance("A"); //PDF/A-1a
- } else {
- pdfa.setConformance("B"); //PDF/A-1b
- }
+ pdfa.setPart(pdfaMode.getPart());
+ pdfa.setConformance(String.valueOf(pdfaMode.getConformanceLevel()));
}
//XMP Basic Schema
*/
public void verifyTransparencyAllowed(String context) {
final String err = "{0} does not allow the use of transparency. ({1})";
- if (isPDFAActive()) {
+ if (pdfAMode.isPart1()) {
throw new PDFConformanceException(MessageFormat.format(err,
new Object[] {getPDFAMode(), context}));
}
/** Checks if the right PDF version is set. */
public void verifyPDFVersion() {
final String err = "PDF version must be 1.4 for {0}";
- if (getPDFAMode().isPDFA1LevelB()
+ if (getPDFAMode().isPart1()
&& !Version.V1_4.equals(getDocument().getPDFVersion())) {
throw new PDFConformanceException(format(err, getPDFAMode()));
}
* Checks a few things required for tagged PDF.
*/
public void verifyTaggedPDF() {
- if (getPDFAMode().isPDFA1LevelA()) {
+ if (getPDFAMode().isLevelA()) {
final String err = "{0} requires the {1} dictionary entry to be set";
PDFDictionary markInfo = getDocument().getRoot().getMarkInfo();
if (markInfo == null) {
} else if (issRGB()) {
pdfICCStream = setupsRGBColorProfile(doc);
}
- if (doc.getProfile().getPDFAMode().isPDFA1LevelB()) {
+ if (doc.getProfile().getPDFAMode().isPart1()) {
if (pdfCS != null
&& pdfCS.getColorSpace() != PDFDeviceColorSpace.DEVICE_RGB
&& pdfCS.getColorSpace() != PDFDeviceColorSpace.DEVICE_GRAY
import org.apache.fop.pdf.PDFInfo;
import org.apache.fop.pdf.PDFMetadata;
import org.apache.fop.pdf.PDFNames;
-import org.apache.fop.pdf.PDFNumsArray;
import org.apache.fop.pdf.PDFOutputIntent;
import org.apache.fop.pdf.PDFPageLabels;
import org.apache.fop.pdf.PDFReference;
private void initialize() {
rendererConfig = PDFRendererOptionsConfig.DEFAULT.merge(createFromUserAgent(userAgent));
- if (rendererConfig.getPDFAMode().isPDFA1LevelA()) {
- //Enable accessibility if PDF/A-1a is enabled because it requires tagged PDF.
+ if (rendererConfig.getPDFAMode().isLevelA()) {
+ // PDF/A Level A requires tagged PDF
userAgent.getRendererOptions().put(Accessibility.ACCESSIBILITY, Boolean.TRUE);
}
}
addPDFXOutputIntent();
}
PDFAMode pdfAMode = rendererConfig.getPDFAMode();
- if (pdfAMode.isPDFA1LevelB()) {
+ if (pdfAMode.isEnabled()) {
log.debug("PDF/A is active. Conformance Level: " + pdfAMode);
addPDFA1OutputIntent();
}
//TODO Handle this in PDFColorHandler by automatically converting the color.
//This won't work properly anyway after the redesign of ColorExt
if (col.getColorSpace().getType() == ColorSpace.TYPE_CMYK) {
- if (pdfDoc.getProfile().getPDFAMode().isPDFA1LevelB()) {
+ if (pdfDoc.getProfile().getPDFAMode().isPart1()) {
//See PDF/A-1, ISO 19005:1:2005(E), 6.2.3.3
//FOP is currently restricted to DeviceRGB if PDF/A-1 is active.
throw new PDFConformanceException(
documents. Example: the fix of marks layering will be such a case when it's done.
-->
<release version="FOP Trunk" date="TBD">
+ <action context="Renderers" dev="VH" type="add" fixes-bug="54038">
+ Added PDF/A-2 output option.
+ </action>
<action context="Renderers" dev="VH" type="add" fixes-bug="54037">
PDF output: Issue a warning when accessibility is enabled and language information is
missing.
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.pdf;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class PDFAModeTestCase {
+
+ private static class PDFAModeChecker {
+
+ private final PDFAMode mode;
+
+ PDFAModeChecker(PDFAMode mode) {
+ this.mode = mode;
+ }
+
+ PDFAModeChecker isEnabled() {
+ assertTrue(mode.isEnabled());
+ return this;
+ }
+
+ PDFAModeChecker isDisabled() {
+ assertFalse(mode.isEnabled());
+ return this;
+ }
+
+ PDFAModeChecker isPart1() {
+ assertEquals(1, mode.getPart());
+ assertTrue(mode.isPart1());
+ return this;
+ }
+
+ PDFAModeChecker isNotPart1() {
+ assertFalse(mode.getPart() == 1);
+ assertFalse(mode.isPart1());
+ return this;
+ }
+
+ PDFAModeChecker isPart2() {
+ assertTrue(mode.getPart() == 1 || mode.getPart() == 2);
+ assertTrue(mode.isPart2());
+ return this;
+ }
+
+ PDFAModeChecker isNotPart2() {
+ assertFalse(mode.getPart() == 2);
+ assertFalse(mode.isPart2());
+ return this;
+ }
+
+ PDFAModeChecker hasConformanceLevel(char level) {
+ assertEquals(level, mode.getConformanceLevel());
+ return this;
+ }
+
+ PDFAModeChecker isLevelA() {
+ assertEquals('A', mode.getConformanceLevel());
+ assertTrue(mode.isLevelA());
+ return this;
+ }
+
+ PDFAModeChecker isNotLevelA() {
+ assertFalse(mode.getConformanceLevel() == 'A');
+ assertFalse(mode.isLevelA());
+ return this;
+ }
+ }
+
+ @Test
+ public void checkDisabled() {
+ new PDFAModeChecker(PDFAMode.DISABLED)
+ .isDisabled()
+ .isNotPart1()
+ .isNotPart2()
+ .isNotLevelA();
+ }
+
+ @Test
+ public void checkPDFA_1a() {
+ new PDFAModeChecker(PDFAMode.PDFA_1A)
+ .isEnabled()
+ .isPart1()
+ .isPart2()
+ .isLevelA();
+ }
+
+ @Test
+ public void checkPDFA_1b() {
+ new PDFAModeChecker(PDFAMode.PDFA_1B)
+ .isEnabled()
+ .isPart1()
+ .isPart2()
+ .isNotLevelA();
+ }
+
+ @Test
+ public void checkPDFA_2a() {
+ new PDFAModeChecker(PDFAMode.PDFA_2A)
+ .isEnabled()
+ .isNotPart1()
+ .isPart2()
+ .isLevelA();
+ }
+
+ @Test
+ public void checkPDFA_2b() {
+ new PDFAModeChecker(PDFAMode.PDFA_2B)
+ .isEnabled()
+ .isNotPart1()
+ .isPart2()
+ .isNotLevelA();
+ }
+
+ @Test
+ public void checkPDFA_2u() {
+ new PDFAModeChecker(PDFAMode.PDFA_2U)
+ .isEnabled()
+ .isNotPart1()
+ .isPart2()
+ .isNotLevelA()
+ .hasConformanceLevel('U');
+ }
+
+}