001/* 002 * (C) Copyright 2016-2018 Nuxeo (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Thibaud Arguillere 018 * Miguel Nixo 019 */ 020package org.nuxeo.ecm.platform.pdf; 021 022import static org.apache.pdfbox.pdmodel.font.PDType1Font.COURIER; 023import static org.apache.pdfbox.pdmodel.font.PDType1Font.COURIER_BOLD; 024import static org.apache.pdfbox.pdmodel.font.PDType1Font.COURIER_BOLD_OBLIQUE; 025import static org.apache.pdfbox.pdmodel.font.PDType1Font.COURIER_OBLIQUE; 026import static org.apache.pdfbox.pdmodel.font.PDType1Font.HELVETICA; 027import static org.apache.pdfbox.pdmodel.font.PDType1Font.HELVETICA_BOLD; 028import static org.apache.pdfbox.pdmodel.font.PDType1Font.HELVETICA_BOLD_OBLIQUE; 029import static org.apache.pdfbox.pdmodel.font.PDType1Font.HELVETICA_OBLIQUE; 030import static org.apache.pdfbox.pdmodel.font.PDType1Font.SYMBOL; 031import static org.apache.pdfbox.pdmodel.font.PDType1Font.TIMES_BOLD; 032import static org.apache.pdfbox.pdmodel.font.PDType1Font.TIMES_BOLD_ITALIC; 033import static org.apache.pdfbox.pdmodel.font.PDType1Font.TIMES_ITALIC; 034import static org.apache.pdfbox.pdmodel.font.PDType1Font.TIMES_ROMAN; 035import static org.apache.pdfbox.pdmodel.font.PDType1Font.ZAPF_DINGBATS; 036 037import java.io.File; 038import java.io.IOException; 039import java.io.InputStream; 040import java.util.Collections; 041import java.util.HashMap; 042import java.util.List; 043import java.util.Map; 044 045import org.apache.commons.lang3.StringUtils; 046import org.apache.pdfbox.pdmodel.PDDocument; 047import org.apache.pdfbox.pdmodel.PDDocumentInformation; 048import org.apache.pdfbox.pdmodel.font.PDType1Font; 049import org.nuxeo.ecm.core.api.Blob; 050import org.nuxeo.ecm.core.api.Blobs; 051import org.nuxeo.ecm.core.api.NuxeoException; 052import org.nuxeo.ecm.core.api.impl.blob.FileBlob; 053 054/** 055 * Grouping miscellaneous utilities in this class. 056 * 057 * @since 8.10 058 */ 059public class PDFUtils { 060 061 public static final String DEFAULT_BLOB_XPATH = "file:content"; 062 063 protected static final Map<String, PDType1Font> STANDARD_14; 064 static { 065 Map<String, PDType1Font> map = new HashMap<>(); 066 for (PDType1Font font : List.of( // 067 TIMES_ROMAN, TIMES_BOLD, TIMES_ITALIC, TIMES_BOLD_ITALIC, // 068 HELVETICA, HELVETICA_BOLD, HELVETICA_OBLIQUE, HELVETICA_BOLD_OBLIQUE, // 069 COURIER, COURIER_BOLD, COURIER_OBLIQUE, COURIER_BOLD_OBLIQUE, // 070 SYMBOL, ZAPF_DINGBATS)) { 071 map.put(font.getBaseFont(), font); 072 } 073 STANDARD_14 = Collections.unmodifiableMap(map); 074 } 075 076 /** 077 * Gets one of the Standard 14 Type 1 Fonts. 078 * 079 * @since 11.1 080 */ 081 public static PDType1Font getStandardType1Font(String name) { 082 return STANDARD_14.get(name); 083 } 084 085 public static int[] hex255ToRGB(String inHex) { 086 int[] result = { 0, 0, 0 }; 087 if (inHex != null) { 088 inHex = inHex.toLowerCase().replace("#", "").replace("0x", ""); 089 if (inHex.length() >= 6) { 090 for (int i = 0; i < 3; i++) { 091 result[i] = Integer.parseInt(inHex.substring(i * 2, i * 2 + 2), 16); 092 } 093 } 094 } 095 return result; 096 } 097 098 /** 099 * This is just a shortcut. We often load() and openProtection(). 100 * 101 * @param inBlob Input Blob. 102 * @param inPwd Input password. 103 */ 104 public static PDDocument load(Blob inBlob, String inPwd) throws NuxeoException { 105 PDDocument pdfDoc; 106 try { 107 pdfDoc = PDDocument.load(inBlob.getStream(), inPwd); 108 } catch (IOException e) { 109 throw new NuxeoException("Failed to load the PDF", e); 110 } 111 return pdfDoc; 112 } 113 114 /** 115 * Create a temporary PDF file and return a FileBlob built from this file. 116 * <p> 117 * Mainly a utility used just by this plug-in actually. 118 * 119 * @param inPdfDoc Input PDF document. 120 * @return FileBlob 121 */ 122 public static FileBlob saveInTempFile(PDDocument inPdfDoc) throws IOException { 123 return saveInTempFile(inPdfDoc, null); 124 } 125 126 public static FileBlob saveInTempFile(PDDocument inPdfDoc, String inFileName) throws IOException { 127 Blob result = Blobs.createBlobWithExtension(".pdf"); 128 File resultFile = result.getFile(); 129 inPdfDoc.save(result.getFile()); 130 result.setMimeType("application/pdf"); 131 if (StringUtils.isNotBlank(inFileName)) { 132 result.setFilename(inFileName); 133 } 134 FileBlob fb = new FileBlob(resultFile); 135 fb.setMimeType("application/pdf"); 136 return fb; 137 } 138 139 /** 140 * Convenience method: If a parameter is null or "", it is not modified. 141 * 142 * @param inPdfDoc Input PDF document. 143 * @param inTitle Title of the PDF document. 144 * @param inSubject Subject of the PDF document. 145 * @param inAuthor Author of the PDF document. 146 */ 147 public static void setInfos(PDDocument inPdfDoc, String inTitle, String inSubject, String inAuthor) { 148 if (inTitle != null && inTitle.isEmpty()) { 149 inTitle = null; 150 } 151 if (inSubject != null && inSubject.isEmpty()) { 152 inSubject = null; 153 } 154 if (inAuthor != null && inAuthor.isEmpty()) { 155 inAuthor = null; 156 } 157 if (inTitle != null || inAuthor != null || inSubject != null) { 158 PDDocumentInformation docInfo = inPdfDoc.getDocumentInformation(); 159 if (inTitle != null) { 160 docInfo.setTitle(inTitle); 161 } 162 if (inSubject != null) { 163 docInfo.setSubject(inSubject); 164 } 165 if (inAuthor != null) { 166 docInfo.setAuthor(inAuthor); 167 } 168 inPdfDoc.setDocumentInformation(docInfo); 169 } 170 } 171 172 public static String checkXPath(String inXPath) { 173 if (StringUtils.isBlank(inXPath)) { 174 inXPath = DEFAULT_BLOB_XPATH; 175 } 176 return inXPath; 177 } 178 179 public static void closeSilently(PDDocument... inPdfDocs) { 180 for (PDDocument doc : inPdfDocs) { 181 if (doc != null) { 182 try { 183 doc.close(); 184 } catch (IOException e) { 185 // Ignore 186 } 187 } 188 } 189 } 190 191}