1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 /* $Id: PDFProfile.java 1753357 2016-07-19 09:25:55Z ssteiner $ */ 19 20 package org.apache.fop.pdf; 21 22 import java.text.MessageFormat; 23 24 /** 25 * This class allows tracks the enabled PDF profiles (PDF/A and PDF/X) and provides methods to 26 * the libarary and its users to enable the generation of PDFs conforming to the enabled PDF 27 * profiles. 28 * <p> 29 * Some profile from PDF/X and PDF/A can be active simultaneously (example: PDF/A-1 and 30 * PDF/X-3:2003). 31 */ 32 public class PDFProfile { 33 34 /** 35 * Indicates the PDF/A mode currently active. Defaults to "no restrictions", i.e. 36 * PDF/A not active. 37 */ 38 protected PDFAMode pdfAMode = PDFAMode.DISABLED; 39 40 protected PDFUAMode pdfUAMode = PDFUAMode.DISABLED; 41 42 /** 43 * Indicates the PDF/X mode currently active. Defaults to "no restrictions", i.e. 44 * PDF/X not active. 45 */ 46 protected PDFXMode pdfXMode = PDFXMode.DISABLED; 47 48 protected PDFVTMode pdfVTMode = PDFVTMode.DISABLED; 49 50 private PDFDocument doc; 51 52 /** 53 * Main constructor 54 * @param doc the PDF document 55 */ PDFProfile(PDFDocument doc)56 public PDFProfile(PDFDocument doc) { 57 this.doc = doc; 58 } 59 60 /** 61 * Validates if the requested profile combination is compatible. 62 */ validateProfileCombination()63 protected void validateProfileCombination() { 64 if (pdfAMode != PDFAMode.DISABLED) { 65 if (pdfAMode == PDFAMode.PDFA_1B) { 66 if (pdfXMode != PDFXMode.DISABLED && pdfXMode != PDFXMode.PDFX_3_2003 && pdfXMode != PDFXMode.PDFX_4) { 67 throw new PDFConformanceException( 68 pdfAMode + " and " + pdfXMode + " are not compatible!"); 69 } 70 } 71 } 72 if (pdfVTMode != PDFVTMode.DISABLED && pdfXMode != PDFXMode.PDFX_4) { 73 throw new PDFConformanceException(pdfVTMode.name() + " requires " + PDFXMode.PDFX_4.getName() + " enabled"); 74 } 75 } 76 77 /** @return the PDFDocument this profile is attached to */ getDocument()78 public PDFDocument getDocument() { 79 return this.doc; 80 } 81 82 /** @return the PDF/A mode */ getPDFAMode()83 public PDFAMode getPDFAMode() { 84 return this.pdfAMode; 85 } 86 getPDFUAMode()87 public PDFUAMode getPDFUAMode() { 88 return this.pdfUAMode; 89 } 90 91 /** @return true if any PDF/A mode is active */ isPDFAActive()92 public boolean isPDFAActive() { 93 return getPDFAMode() != PDFAMode.DISABLED; 94 } 95 96 /** 97 * Sets the PDF/A mode 98 * @param mode the PDF/A mode 99 */ setPDFAMode(PDFAMode mode)100 public void setPDFAMode(PDFAMode mode) { 101 if (mode == null) { 102 mode = PDFAMode.DISABLED; 103 } 104 this.pdfAMode = mode; 105 validateProfileCombination(); 106 } 107 setPDFUAMode(PDFUAMode mode)108 public void setPDFUAMode(PDFUAMode mode) { 109 if (mode == null) { 110 mode = PDFUAMode.DISABLED; 111 } 112 this.pdfUAMode = mode; 113 validateProfileCombination(); 114 } 115 116 /** @return the PDF/X mode */ getPDFXMode()117 public PDFXMode getPDFXMode() { 118 return this.pdfXMode; 119 } 120 getPDFVTMode()121 public PDFVTMode getPDFVTMode() { 122 return this.pdfVTMode; 123 } 124 125 /** @return true if any PDF/X mode is active */ isPDFXActive()126 public boolean isPDFXActive() { 127 return getPDFXMode() != PDFXMode.DISABLED; 128 } 129 isPDFVTActive()130 public boolean isPDFVTActive() { 131 return getPDFVTMode() != PDFVTMode.DISABLED; 132 } 133 134 /** 135 * Sets the PDF/X mode 136 * @param mode the PDF/X mode 137 */ setPDFXMode(PDFXMode mode)138 public void setPDFXMode(PDFXMode mode) { 139 if (mode == null) { 140 mode = PDFXMode.DISABLED; 141 } 142 this.pdfXMode = mode; 143 validateProfileCombination(); 144 } 145 146 /** 147 * Sets the PDF/X mode 148 * @param mode the PDF/X mode 149 */ setPDFVTMode(PDFVTMode mode)150 public void setPDFVTMode(PDFVTMode mode) { 151 if (mode == null) { 152 mode = PDFVTMode.DISABLED; 153 } 154 this.pdfVTMode = mode; 155 validateProfileCombination(); 156 } 157 158 /** {@inheritDoc} */ toString()159 public String toString() { 160 StringBuffer sb = new StringBuffer(); 161 if (isPDFAActive() && isPDFXActive()) { 162 sb.append("[").append(getPDFAMode()).append(",").append(getPDFXMode()).append("]"); 163 } else if (isPDFAActive()) { 164 sb.append(getPDFAMode()); 165 } else if (isPDFXActive()) { 166 sb.append(getPDFXMode()); 167 } else if (getPDFUAMode().isEnabled()) { 168 sb.append(getPDFUAMode()); 169 } else { 170 sb.append(super.toString()); 171 } 172 return sb.toString(); 173 } 174 175 //---------=== Info and validation methods ===--------- 176 format(String pattern, Object[] args)177 private String format(String pattern, Object[] args) { 178 return MessageFormat.format(pattern, args); 179 } 180 format(String pattern, Object arg)181 private String format(String pattern, Object arg) { 182 return format(pattern, new Object[] {arg}); 183 } 184 185 /** Checks if encryption is allowed. */ verifyEncryptionAllowed()186 public void verifyEncryptionAllowed() { 187 final String err = "{0} doesn't allow encrypted PDFs"; 188 if (isPDFAActive()) { 189 throw new PDFConformanceException(format(err, getPDFAMode())); 190 } 191 if (isPDFXActive()) { 192 throw new PDFConformanceException(format(err, getPDFXMode())); 193 } 194 } 195 196 /** Checks if PostScript XObjects are allowed. */ verifyPSXObjectsAllowed()197 public void verifyPSXObjectsAllowed() { 198 final String err = "PostScript XObjects are prohibited when {0}" 199 + " is active. Convert EPS graphics to another format."; 200 if (isPDFAActive()) { 201 throw new PDFConformanceException(format(err, getPDFAMode())); 202 } 203 if (isPDFXActive()) { 204 throw new PDFConformanceException(format(err, getPDFXMode())); 205 } 206 } 207 208 /** 209 * Checks if the use of transparency is allowed. 210 * @param context Context information for the user to identify the problem spot 211 */ verifyTransparencyAllowed(String context)212 public void verifyTransparencyAllowed(String context) { 213 Object profile = isTransparencyAllowed(); 214 if (profile != null) { 215 throw new TransparencyDisallowedException(profile, context); 216 } 217 } 218 219 /** 220 * Returns {@code null} if transparency is allowed, otherwise returns the profile that 221 * prevents it. 222 * 223 * @return {@code null}, or an object whose {@code toString} method returns the name 224 * of the profile that disallows transparency 225 */ isTransparencyAllowed()226 public Object isTransparencyAllowed() { 227 if (pdfAMode.isPart1()) { 228 return getPDFAMode(); 229 } 230 if (getPDFXMode() == PDFXMode.PDFX_3_2003) { 231 return getPDFXMode(); 232 } 233 return null; 234 } 235 236 /** Checks if the right PDF version is set. */ verifyPDFVersion()237 public void verifyPDFVersion() { 238 String err = "PDF version must be 1.4 for {0}"; 239 if (getPDFAMode().isPart1() 240 && !Version.V1_4.equals(getDocument().getPDFVersion())) { 241 throw new PDFConformanceException(format(err, getPDFAMode())); 242 } 243 if (getPDFXMode() == PDFXMode.PDFX_3_2003 244 && !Version.V1_4.equals(getDocument().getPDFVersion())) { 245 throw new PDFConformanceException(format(err, getPDFXMode())); 246 } 247 } 248 249 /** 250 * Checks a few things required for tagged PDF. 251 */ verifyTaggedPDF()252 public void verifyTaggedPDF() { 253 if (getPDFAMode().isLevelA() || getPDFUAMode().isEnabled()) { 254 final String err = "{0} requires the {1} dictionary entry to be set"; 255 String mode = getPDFAMode().toString(); 256 if (getPDFUAMode().isEnabled()) { 257 mode = getPDFUAMode().toString(); 258 } 259 PDFDictionary markInfo = getDocument().getRoot().getMarkInfo(); 260 if (markInfo == null) { 261 throw new PDFConformanceException(format( 262 "{0} requires that the accessibility option in the configuration file be enabled", mode)); 263 } 264 if (!Boolean.TRUE.equals(markInfo.get("Marked"))) { 265 throw new PDFConformanceException(format(err, 266 new Object[] {mode, "Marked"})); 267 } 268 if (getDocument().getRoot().getStructTreeRoot() == null) { 269 throw new PDFConformanceException(format(err, 270 new Object[] {mode, "StructTreeRoot"})); 271 } 272 if (getDocument().getRoot().getLanguage() == null) { 273 throw new PDFConformanceException(format(err, 274 new Object[] {mode, "Lang"})); 275 } 276 } 277 } 278 279 /** @return true if the ID entry must be present in the trailer. */ isIDEntryRequired()280 public boolean isIDEntryRequired() { 281 return isPDFAActive() || isPDFXActive(); 282 } 283 284 /** @return true if all fonts need to be embedded. */ isFontEmbeddingRequired()285 public boolean isFontEmbeddingRequired() { 286 return isPDFAActive() || isPDFXActive() || getPDFUAMode().isEnabled(); 287 } 288 289 /** Checks if a title may be absent. */ verifyTitleAbsent()290 public void verifyTitleAbsent() { 291 final String err = "{0} requires the title to be set."; 292 if (getPDFUAMode().isEnabled()) { 293 throw new PDFConformanceException(format(err, getPDFUAMode())); 294 } 295 if (isPDFXActive()) { 296 throw new PDFConformanceException(format(err, getPDFXMode())); 297 } 298 } 299 300 /** @return true if the ModDate Info entry must be present. */ isModDateRequired()301 public boolean isModDateRequired() { 302 return getPDFXMode() != PDFXMode.DISABLED; 303 } 304 305 /** @return true if the Trapped Info entry must be present. */ isTrappedEntryRequired()306 public boolean isTrappedEntryRequired() { 307 return getPDFXMode() != PDFXMode.DISABLED; 308 } 309 310 /** @return true if annotations are allowed */ isAnnotationAllowed()311 public boolean isAnnotationAllowed() { 312 return !isPDFXActive(); 313 } 314 315 /** Checks if annotations are allowed. */ verifyAnnotAllowed()316 public void verifyAnnotAllowed() { 317 if (!isAnnotationAllowed()) { 318 final String err = "{0} does not allow annotations inside the printable area."; 319 //Note: this rule is simplified. Refer to the standard for details. 320 throw new PDFConformanceException(format(err, getPDFXMode())); 321 } 322 } 323 324 /** Checks if Actions are allowed. */ verifyActionAllowed()325 public void verifyActionAllowed() { 326 if (isPDFXActive()) { 327 final String err = "{0} does not allow Actions."; 328 throw new PDFConformanceException(format(err, getPDFXMode())); 329 } 330 } 331 332 /** Checks if embedded files are allowed. */ verifyEmbeddedFilesAllowed()333 public void verifyEmbeddedFilesAllowed() { 334 final String err = "{0} does not allow embedded files."; 335 if (isPDFAActive() && getPDFAMode().getPart() < 3) { 336 throw new PDFConformanceException(format(err, getPDFAMode())); 337 } 338 if (isPDFXActive()) { 339 //Implicit since file specs are forbidden 340 throw new PDFConformanceException(format(err, getPDFXMode())); 341 } 342 } 343 344 } 345