diff options
Diffstat (limited to 'pdf-as-pdfbox-2/src')
7 files changed, 636 insertions, 768 deletions
| diff --git a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/PDFBoxPlaceholderExtractor.java b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/PDFBoxPlaceholderExtractor.java index 63b006bf..ad874bc0 100644 --- a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/PDFBoxPlaceholderExtractor.java +++ b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/PDFBoxPlaceholderExtractor.java @@ -1,5 +1,7 @@  package at.gv.egiz.pdfas.lib.impl.pdfbox2.placeholder; +import java.io.IOException; +  import at.gv.egiz.pdfas.common.exceptions.PDFIOException;  import at.gv.egiz.pdfas.common.exceptions.PdfAsException;  import at.gv.egiz.pdfas.lib.impl.pdfbox2.PDFBOXObject; @@ -7,9 +9,6 @@ import at.gv.egiz.pdfas.lib.impl.placeholder.PlaceholderExtractor;  import at.gv.egiz.pdfas.lib.impl.placeholder.SignaturePlaceholderData;  import at.gv.egiz.pdfas.lib.impl.status.PDFObject; -import java.io.IOException; -import java.util.List; -  public class PDFBoxPlaceholderExtractor implements PlaceholderExtractor { @@ -18,27 +17,8 @@ public class PDFBoxPlaceholderExtractor implements PlaceholderExtractor {  		if (doc instanceof PDFBOXObject) {  			PDFBOXObject object = (PDFBOXObject) doc;  			try { -				SignaturePlaceholderExtractor extractor = new SignaturePlaceholderExtractor(placeholderId, -						matchMode, object.getDocument()); -				return extractor.extract(object.getDocument(), -						placeholderId, matchMode); -			} catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e2) { -				throw new PDFIOException("error.pdf.io.04", e2); -			} - -		} -		throw new PdfAsException("INVALID STATE"); -	} - -	@Override -	public List<SignaturePlaceholderData> extractList(PDFObject doc, String placeholderId, int matchMode) throws PdfAsException { -		if (doc instanceof PDFBOXObject) { -			PDFBOXObject object = (PDFBOXObject) doc; -			try { -				SignaturePlaceholderExtractor extractor = new SignaturePlaceholderExtractor(placeholderId, -						matchMode, object.getDocument()); -				return extractor.extractList(object.getDocument(), -						placeholderId, matchMode); +				SignaturePlaceholderExtractor extractor = new SignaturePlaceholderExtractor(); +				return extractor.extract(object.getDocument(), placeholderId, matchMode);  			} catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e2) {  				throw new PDFIOException("error.pdf.io.04", e2);  			} diff --git a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/SignatureFieldsAndPlaceHolderExtractor.java b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/SignatureFieldsAndPlaceHolderExtractor.java index 609f8254..8e5e5d4e 100644 --- a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/SignatureFieldsAndPlaceHolderExtractor.java +++ b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/SignatureFieldsAndPlaceHolderExtractor.java @@ -1,106 +1,58 @@  package at.gv.egiz.pdfas.lib.impl.pdfbox2.placeholder; -import at.gv.egiz.pdfas.lib.impl.placeholder.PlaceholderExtractorConstants; -import at.gv.egiz.pdfas.lib.impl.placeholder.SignaturePlaceholderData; +import java.util.ArrayList; +import java.util.List; +  import org.apache.pdfbox.pdmodel.PDDocument;  import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;  import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;  import org.apache.pdfbox.pdmodel.interactive.form.PDField;  import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; +import at.gv.egiz.pdfas.lib.impl.placeholder.PlaceholderExtractorConstants; +import at.gv.egiz.pdfas.lib.impl.placeholder.SignaturePlaceholderData;  public class SignatureFieldsAndPlaceHolderExtractor { -    //Search for empty signature fields -    public static List<String> findEmptySignatureFields(PDDocument doc) -    { -        PDSignature signature; -        List<PDField> signatureField; -        List<String> signatureFieldNames = new ArrayList<>(); -        PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm(); -        if (acroForm != null) { -            signatureField = acroForm.getFields(); -            for (PDField pdField : signatureField) { -                if(pdField instanceof PDSignatureField && pdField.getPartialName()!=null) -                { -                    signature = ((PDSignatureField) pdField).getSignature(); -                    if(signature == null) signatureFieldNames.add(pdField.getPartialName()); -                } -            } -        } -        return signatureFieldNames; -    } -    /* -    Needed by PDF-OVER -     */ - -    /** -     * Returns the next unused signature placeholder -     * @param doc The document to be searched for signature placeholders -     * @return The next unused signature placeholder or null in case there is none -     */ -    public static SignaturePlaceholderData getNextUnusedSignaturePlaceHolder(PDDocument doc) { -        try { -            String placeholderId = "1"; -            int mode = PlaceholderExtractorConstants.PLACEHOLDER_MATCH_MODE_SORTED; -            SignaturePlaceholderExtractor signaturePlaceholderExtractor = new SignaturePlaceholderExtractor( placeholderId, -                mode, doc); -            List<SignaturePlaceholderData> results = signaturePlaceholderExtractor.extractList(doc, placeholderId, -                mode); -            if (results == null) { -                return null; -            } -            List<String> used = getExistingSignatureLocations(doc); -            //return first not used -            for(SignaturePlaceholderData result : results) { -                if(!used.contains(result.getPlaceholderName())) -                    return result; -            } -            return null; -        } catch (Exception e) { -            e.printStackTrace(); -            return null; -        } -    } - -    public static SignaturePlaceholderData getSignaturePlaceHolder(PDDocument doc, String placeholderId, -                                                                   int mode) { -        try { -            SignaturePlaceholderExtractor signaturePlaceholderExtractor = new SignaturePlaceholderExtractor( placeholderId, -                mode, doc); -            return signaturePlaceholderExtractor.extract(doc, placeholderId, mode); -        } catch (Exception e) { -            e.printStackTrace(); -            return null; +  // Search for empty signature fields +  public static List<String> findEmptySignatureFields(PDDocument doc) { +    PDSignature signature; +    List<PDField> signatureField; +    final List<String> signatureFieldNames = new ArrayList<>(); +    final PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm(); +    if (acroForm != null) { +      signatureField = acroForm.getFields(); +      for (final PDField pdField : signatureField) { +        if (pdField instanceof PDSignatureField && pdField.getPartialName() != null) { +          signature = ((PDSignatureField) pdField).getSignature(); +          if (signature == null) { +            signatureFieldNames.add(pdField.getPartialName()); +          }          } +      }      } - -    public static List<SignaturePlaceholderData> getSignaturePlaceHolderList(PDDocument doc, String placeholderId, int mode) { -        try { -            SignaturePlaceholderExtractor signaturePlaceholderExtractor = new SignaturePlaceholderExtractor( placeholderId, -                mode, doc); -            return signaturePlaceholderExtractor.extractList(doc, placeholderId, mode); -        } catch (Exception e) { -            e.printStackTrace(); -            return null; -        } -    } - -    public static List<String> getExistingSignatureLocations(PDDocument doc) { -        List<String> existingLocations = new ArrayList<>(); -        try { -            List <PDSignature> pdSignatureList =  doc.getSignatureDictionaries(); -            if(pdSignatureList.size() != 0) { -                for(PDSignature sig : pdSignatureList) { -                    existingLocations.add(sig.getLocation()); -                } -            } -        } catch (IOException e) { -            e.printStackTrace(); -        } -        return existingLocations; +    return signatureFieldNames; +  } +  /* +   * Needed by PDF-OVER +   */ + +  /** +   * Returns the next unused signature placeholder +   * +   * @param doc The document to be searched for signature placeholders +   * @return The next unused signature placeholder or null in case there is none +   */ +  public static SignaturePlaceholderData getNextUnusedSignaturePlaceHolder(PDDocument doc) { +    try { +      final String placeholderId = "1"; +      final int mode = PlaceholderExtractorConstants.PLACEHOLDER_MATCH_MODE_SORTED; +      final SignaturePlaceholderExtractor signaturePlaceholderExtractor = new SignaturePlaceholderExtractor(); +      return signaturePlaceholderExtractor.extract(doc, placeholderId, mode); + +    } catch (final Exception e) { +      e.printStackTrace(); +      return null;      } +  }  } diff --git a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/SignaturePlaceholderExtractor.java b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/SignaturePlaceholderExtractor.java index b62b660a..99027be0 100644 --- a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/SignaturePlaceholderExtractor.java +++ b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/SignaturePlaceholderExtractor.java @@ -3,19 +3,19 @@   * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a   * joint initiative of the Federal Chancellery Austria and Graz University of   * Technology. - *  + *   * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by   * the European Commission - subsequent versions of the EUPL (the "Licence");   * You may not use this work except in compliance with the Licence.   * You may obtain a copy of the Licence at:   * http://www.osor.eu/eupl/ - *  + *   * Unless required by applicable law or agreed to in writing, software   * distributed under the Licence is distributed on an "AS IS" basis,   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   * See the Licence for the specific language governing permissions and   * limitations under the Licence. - *  + *   * This product combines work with different licenses. See the "NOTICE" text   * file for details on the various modules and licenses.   * The "NOTICE" text file is part of the distribution. Any derivative works @@ -51,30 +51,26 @@ import java.awt.geom.NoninvertibleTransformException;  import java.awt.image.BufferedImage;  import java.io.IOException;  import java.util.ArrayList; -import java.util.HashMap; +import java.util.Collections;  import java.util.Hashtable;  import java.util.List; -import java.util.Map;  import java.util.Map.Entry;  import java.util.Properties;  import java.util.Set;  import java.util.Vector; +import java.util.stream.Collectors;  import org.apache.pdfbox.contentstream.PDFStreamEngine;  import org.apache.pdfbox.contentstream.operator.Operator;  import org.apache.pdfbox.contentstream.operator.OperatorProcessor;  import org.apache.pdfbox.cos.COSBase; -import org.apache.pdfbox.cos.COSDictionary;  import org.apache.pdfbox.cos.COSName;  import org.apache.pdfbox.pdmodel.PDDocument;  import org.apache.pdfbox.pdmodel.PDPage; -import org.apache.pdfbox.pdmodel.font.PDFont; -import org.apache.pdfbox.pdmodel.font.PDFontFactory;  import org.apache.pdfbox.pdmodel.graphics.PDXObject;  import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;  import org.apache.pdfbox.util.Matrix; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory;  import com.google.zxing.BarcodeFormat;  import com.google.zxing.BinaryBitmap; @@ -91,10 +87,10 @@ import at.gv.egiz.pdfas.common.exceptions.PDFIOException;  import at.gv.egiz.pdfas.common.exceptions.PdfAsException;  import at.gv.egiz.pdfas.common.exceptions.PlaceholderExtractionException;  import at.gv.egiz.pdfas.lib.impl.placeholder.PlaceholderExtractorConstants; -import at.gv.egiz.pdfas.lib.impl.placeholder.SignaturePlaceholderContext;  import at.gv.egiz.pdfas.lib.impl.placeholder.SignaturePlaceholderData;  import at.knowcenter.wag.egov.egiz.pdf.TablePos;  import javassist.bytecode.stackmap.TypeData.ClassName; +import lombok.extern.slf4j.Slf4j;  /**   * Extract all relevant information from a placeholder image. @@ -102,423 +98,393 @@ import javassist.bytecode.stackmap.TypeData.ClassName;   * @author exthex   *   */ -public class SignaturePlaceholderExtractor extends PDFStreamEngine implements PlaceholderExtractorConstants{ -	/** -	 * The log. -	 */ -	private static Logger logger = LoggerFactory -			.getLogger(SignaturePlaceholderExtractor.class); - -	private List<SignaturePlaceholderData> placeholders = new ArrayList<>(); -	private int currentPage = 0; -	private PDDocument doc; - -	protected SignaturePlaceholderExtractor(String placeholderId, -			int placeholderMatchMode, PDDocument doc) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { -		super(); -		 -		final Properties properties = new Properties(); -		properties.load(ClassName.class.getClassLoader().getResourceAsStream("placeholder/pdfbox-reader-2.properties")); -		 -		Set<Entry<Object, Object>> entries = properties.entrySet(); -		for(Entry<Object, Object> entry:entries){ -			String processorClassName = (String)entry.getValue(); -			Class<?> klass = Class.forName( processorClassName ); -            org.apache.pdfbox.contentstream.operator.OperatorProcessor processor = -                (OperatorProcessor) klass.newInstance(); -             -            addOperator( processor ); -		} -		this.doc = doc; -	} - -	/** -	 * Search the document for placeholder images and possibly included -	 * additional info.<br/> -	 * Searches only for the first placeholder page after page from top. -	 * -	 * @return all available info from the first found placeholder. -	 * @throws PdfAsException -	 *             if the document could not be read. -	 * @throws PlaceholderExtractionException -	 *             if STRICT matching mode was requested and no suitable -	 *             placeholder could be found. -	 */ -	public SignaturePlaceholderData extract(PDDocument doc, -			String placeholderId, int matchMode) throws PdfAsException { -		SignaturePlaceholderContext.setSignaturePlaceholderData(null); -//		SignaturePlaceholderExtractor extractor; -//		try { -//			extractor = new SignaturePlaceholderExtractor(placeholderId, -//					matchMode, doc); -//		} catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e2) { -//			throw new PDFIOException("error.pdf.io.04", e2); -//		} - -		int pageNr = 0; -		for(PDPage page : doc.getPages()){ -			pageNr++; - -			try { -				setCurrentPage(pageNr); -				if(page.getContents() != null && page.getResources() != null && page.getContentStreams() != null) { -						processPage(page); //TODO: pdfbox2 - right? -					 -				} -				SignaturePlaceholderData ret = matchPlaceholderPage( -						placeholders, placeholderId, matchMode); -				if (ret != null) { -					SignaturePlaceholderContext -							.setSignaturePlaceholderData(ret); -					return ret; -				} -			} catch (IOException e1) { -				throw new PDFIOException("error.pdf.io.04", e1); -			} catch(Throwable e) { -				throw new PDFIOException("error.pdf.io.04", e); -			} -		} -		if (placeholders.size() > 0) { -			SignaturePlaceholderData ret = matchPlaceholderDocument( -					placeholders, placeholderId, matchMode); -			SignaturePlaceholderContext.setSignaturePlaceholderData(ret); -			return ret; -		} -		// no placeholders found, apply strict mode if set -		if (matchMode == PLACEHOLDER_MATCH_MODE_STRICT) { -			throw new PlaceholderExtractionException("error.pdf.stamp.09"); -		} - -		return null; -	} - -	public List<SignaturePlaceholderData> extractList(PDDocument doc, -																								 String placeholderId, int matchMode) throws PdfAsException { -		SignaturePlaceholderContext.setSignaturePlaceholderData(null); - -		int pageNr = 0; -		for(PDPage page : doc.getPages()){ -			pageNr++; - -			try { -				setCurrentPage(pageNr); -				if(page.getContents() != null && page.getResources() != null && page.getContentStreams() != null) { -					processPage(page); //TODO: pdfbox2 - right? - -				} -				SignaturePlaceholderData ret = matchPlaceholderPage( -						placeholders, placeholderId, matchMode); -				if (ret != null) { -					SignaturePlaceholderContext -							.setSignaturePlaceholderData(ret); -					return placeholders; -				} -			} catch (IOException e1) { -				throw new PDFIOException("error.pdf.io.04", e1); -			} catch(Throwable e) { -				throw new PDFIOException("error.pdf.io.04", e); -			} -		} -		if (placeholders.size() > 0) { -			SignaturePlaceholderData ret = matchPlaceholderDocument( -					placeholders, placeholderId, matchMode); -			SignaturePlaceholderContext.setSignaturePlaceholderData(ret); -			return placeholders; -		} -		// no placeholders found, apply strict mode if set -		if (matchMode == PLACEHOLDER_MATCH_MODE_STRICT) { -			throw new PlaceholderExtractionException("error.pdf.stamp.09"); -		} -		return null; -	} - -	private SignaturePlaceholderData matchPlaceholderDocument( -			List<SignaturePlaceholderData> placeholders, String placeholderId, -			int matchMode) throws PlaceholderExtractionException { - -		if (matchMode == PLACEHOLDER_MATCH_MODE_STRICT) -			throw new PlaceholderExtractionException("error.pdf.stamp.09"); - -		if (placeholders.size() == 0) -			return null; - -		if (matchMode == PLACEHOLDER_MATCH_MODE_SORTED) { -			// sort all placeholders by the id string if all ids are null do nothing -			SignaturePlaceholderData currentFirstSpd = null; -			for (int i = 0; i < placeholders.size(); i++) { -				SignaturePlaceholderData spd = placeholders.get(i); -				if (spd.getId() != null) { -					if(currentFirstSpd == null) { -						currentFirstSpd = spd; -						logger.debug("Setting new current ID: {}",  -								currentFirstSpd.getId()); -					} else { -						String currentID = currentFirstSpd.getId(); -						String testID = spd.getId(); -						logger.debug("Testing placeholder current: {} compare to {}",  -								currentID, testID); -						if(testID.compareToIgnoreCase(currentID) < 0) { -							currentFirstSpd = spd; -							logger.debug("Setting new current ID: {}",  -									testID); -						} -					} -				} -			} -			 -			if(currentFirstSpd != null) { -				logger.info("Running Placeholder sorted mode: using id: {}", currentFirstSpd.getId()); -				return currentFirstSpd; -			} else { -				logger.info("Running Placeholder sorted mode: no placeholder with id found, fallback to first placeholder"); -			} -		} -		 -		for (int i = 0; i < placeholders.size(); i++) { -			SignaturePlaceholderData spd = placeholders.get(i); -			if (spd.getId() == null) -				return spd; -		} - -		if (matchMode == PLACEHOLDER_MATCH_MODE_LENIENT) -			return placeholders.get(0); - -		return null; -	} - -	private SignaturePlaceholderData matchPlaceholderPage( -			List<SignaturePlaceholderData> placeholders, String placeholderId, -			int matchMode) { -		 -		if(matchMode == PLACEHOLDER_MATCH_MODE_SORTED) -			return null; -		 -		if (placeholders.size() == 0) -			return null; -		for (int i = 0; i < placeholders.size(); i++) { -			SignaturePlaceholderData data = placeholders.get(i); -			if (placeholderId != null && placeholderId.equals(data.getId())) -				return data; -			if (placeholderId == null && data.getId() == null) -				return data; -		} -		return null; -	} - - - -	private void setCurrentPage(int pageNr) { -		this.currentPage = pageNr; -	} - -	@Override -	protected void processOperator(Operator operator, List<COSBase> arguments) -			throws IOException { -		String operation = operator.getName(); -		if (operation.equals("Do")) { -			COSName objectName = (COSName) arguments.get(0); -			PDXObject xobject = (PDXObject) getResources().getXObject(objectName); -			if (xobject instanceof PDImageXObject) { -				try { -					PDImageXObject image = (PDImageXObject) xobject; -					SignaturePlaceholderData data = checkImage(image); -					if (data != null) { -						PDPage page = getCurrentPage(); -						Matrix ctm = getGraphicsState() -								.getCurrentTransformationMatrix(); -						int pageRotation = page.getRotation(); -						pageRotation = pageRotation % 360; -						double rotationInRadians = Math.toRadians(pageRotation);//(page.findRotation() * Math.PI) / 180; - -						AffineTransform rotation = new AffineTransform(); -						rotation.setToRotation(rotationInRadians); -						AffineTransform rotationInverse = rotation -								.createInverse(); -						Matrix rotationInverseMatrix = new Matrix(); -						rotationInverseMatrix -								.setFromAffineTransform(rotationInverse); -						Matrix rotationMatrix = new Matrix(); -						rotationMatrix.setFromAffineTransform(rotation); - -						Matrix unrotatedCTM = ctm -								.multiply(rotationInverseMatrix); - -						float x = unrotatedCTM.getXPosition(); -						float yPos = unrotatedCTM.getYPosition(); -						float yScale = unrotatedCTM.getScaleY(); -						float y = yPos + yScale; -						float w = unrotatedCTM.getScaleX(); - -						logger.debug("Page height: {}", page.getCropBox().getHeight()); -						logger.debug("Page width: {}", page.getCropBox().getWidth()); -						 -						if(pageRotation == 90) { -							y = page.getCropBox().getWidth() - (y * (-1)); -						} else if(pageRotation == 180) { -							x = page.getCropBox().getWidth() + x; -							y = page.getCropBox().getHeight() - (y * (-1)); -						} else if(pageRotation == 270) { -							x = page.getCropBox().getHeight() + x; -						} -						 -						 - -						 -						 -						String posString = "p:" + currentPage + ";x:" + Math.floor(x) -								+ ";y:" + Math.ceil(y) + ";w:" + Math.ceil(w); - -						logger.debug("Found Placeholder at: {}", posString); -						try { -							data.setTablePos(new TablePos(posString)); -							data.setPlaceholderName(objectName.getName()); -							placeholders.add(data); -						} catch (PdfAsException e) { -							throw new IOException(); -						} -					} -				} catch (NoninvertibleTransformException e) { -					throw new IOException(e); -				} -			} -		} else { -			super.processOperator(operator, arguments); -		} -	} - -	private  Map<String, PDFont> fonts; -	 -	//TODO: pdfbox2 - was override -	public Map<String, PDFont> getFonts() { -		if (fonts == null) { -            // at least an empty map will be returned -            // TODO we should return null instead of an empty map -            fonts = new HashMap<String, PDFont>(); -            if(this.getResources() != null && this.getResources().getCOSObject() != null) { -            COSDictionary fontsDictionary = (COSDictionary) this.getResources().getCOSObject().getDictionaryObject(COSName.FONT); -            if (fontsDictionary == null) { -            	// ignore we do not want to set anything, never when creating a signature!!!!! -                //fontsDictionary = new COSDictionary(); -                //this.getResources().getCOSDictionary().setItem(COSName.FONT, fontsDictionary); +@Slf4j +public class SignaturePlaceholderExtractor extends PDFStreamEngine implements PlaceholderExtractorConstants { + +  private final List<SignaturePlaceholderData> placeholders = new ArrayList<>(); +  private int currentPage = 0; + +  protected SignaturePlaceholderExtractor() throws IOException, ClassNotFoundException, +      InstantiationException, IllegalAccessException { +    super(); + +    final Properties properties = new Properties(); +    properties.load(ClassName.class.getClassLoader().getResourceAsStream( +        "placeholder/pdfbox-reader-2.properties")); + +    final Set<Entry<Object, Object>> entries = properties.entrySet(); +    for (final Entry<Object, Object> entry : entries) { +      final String processorClassName = (String) entry.getValue(); +      final Class<?> klass = Class.forName(processorClassName); +      final org.apache.pdfbox.contentstream.operator.OperatorProcessor processor = +          (OperatorProcessor) klass.newInstance(); + +      addOperator(processor); +       +    } +  } +     +  /** +   * Search the document for placeholder images and possibly included additional +   * info.<br/> +   * Searches only for the first placeholder page after page from top. +   * +   * @return available info from the first found placeholder. +   * @throws PdfAsException                 if the document could not be read. +   * @throws PlaceholderExtractionException if STRICT matching mode was requested +   *                                        and no suitable placeholder could be +   *                                        found. +   */ +  public SignaturePlaceholderData extract(PDDocument doc, +      String placeholderId, int matchMode) throws PdfAsException { + +    List<String> extistingSignatureNames = existingExistingSignatureNames(doc); +     +     +    int pageNr = 0; +    for (final PDPage page : doc.getPages()) { +      pageNr++; + +      try { +        this.currentPage = pageNr;         +        if (page.getContents() != null && page.getResources() != null && page.getContentStreams() != null) { +          processPage(page); // TODO: pdfbox2 - right? + +        } +         +        final SignaturePlaceholderData ret = matchPlaceholderPage( +            removeAlreadyUsePlaceholders(placeholders, extistingSignatureNames), placeholderId, matchMode);         +        if (ret != null) { +          return ret; +           +        } +         +      } catch (final IOException e1) { +        throw new PDFIOException("error.pdf.io.04", e1); +         +      } catch (final Throwable e) { +        throw new PDFIOException("error.pdf.io.04", e); +         +      } +    } +     +    if (placeholders.size() > 0) { +      final SignaturePlaceholderData ret = matchPlaceholderDocument( +          removeAlreadyUsePlaceholders(placeholders, extistingSignatureNames), placeholderId, matchMode); +      return ret; +       +    } +    // no placeholders found, apply strict mode if set +    if (matchMode == PLACEHOLDER_MATCH_MODE_STRICT) { +      throw new PlaceholderExtractionException("error.pdf.stamp.09"); +       +    } +    return null; +  } + +  @Override +  protected void processOperator(Operator operator, List<COSBase> arguments) +      throws IOException { +    final String operation = operator.getName(); +    if (operation.equals("Do")) { +      final COSName objectName = (COSName) arguments.get(0); +      final PDXObject xobject = getResources().getXObject(objectName); +      if (xobject instanceof PDImageXObject) { +        try { +          final PDImageXObject image = (PDImageXObject) xobject; +          final SignaturePlaceholderData data = checkImage(image); +          if (data != null) { +            final PDPage page = getCurrentPage(); +            final Matrix ctm = getGraphicsState() +                .getCurrentTransformationMatrix(); +            int pageRotation = page.getRotation(); +            pageRotation = pageRotation % 360; +            final double rotationInRadians = Math.toRadians(pageRotation);// (page.findRotation() * Math.PI) / +                                                                          // 180; + +            final AffineTransform rotation = new AffineTransform(); +            rotation.setToRotation(rotationInRadians); +            final AffineTransform rotationInverse = rotation +                .createInverse(); +            final Matrix rotationInverseMatrix = new Matrix(); +            rotationInverseMatrix +                .setFromAffineTransform(rotationInverse); +            final Matrix rotationMatrix = new Matrix(); +            rotationMatrix.setFromAffineTransform(rotation); + +            final Matrix unrotatedCTM = ctm +                .multiply(rotationInverseMatrix); + +            float x = unrotatedCTM.getXPosition(); +            final float yPos = unrotatedCTM.getYPosition(); +            final float yScale = unrotatedCTM.getScaleY(); +            float y = yPos + yScale; +            final float w = unrotatedCTM.getScaleX(); + +            log.debug("Page height: {}", page.getCropBox().getHeight()); +            log.debug("Page width: {}", page.getCropBox().getWidth()); + +            if (pageRotation == 90) { +              y = page.getCropBox().getWidth() - y * -1; +            } else if (pageRotation == 180) { +              x = page.getCropBox().getWidth() + x; +              y = page.getCropBox().getHeight() - y * -1; +            } else if (pageRotation == 270) { +              x = page.getCropBox().getHeight() + x;              } -            else { -                for (COSName fontName : fontsDictionary.keySet()) { -                    COSBase font = fontsDictionary.getDictionaryObject(fontName); -                    // data-000174.pdf contains a font that is a COSArray, looks to be an error in the -                    // PDF, we will just ignore entries that are not dictionaries. -                    if (font instanceof COSDictionary) { -                        PDFont newFont = null; -                        try { -                            newFont = PDFontFactory.createFont((COSDictionary) font); -                        } -                        catch (IOException exception) { -                            logger.error("error while creating a font", exception); -                        } -                        if (newFont != null) { -                            fonts.put(fontName.getName(), newFont); -                        } -                    } -                } + +            final String posString = "p:" + currentPage + ";x:" + Math.floor(x) +                + ";y:" + Math.ceil(y) + ";w:" + Math.ceil(w); + +            log.debug("Found Placeholder at: {}", posString); +            try { +              data.setTablePos(new TablePos(posString)); +              data.setPlaceholderName(objectName.getName()); +              placeholders.add(data); +               +            } catch (final PdfAsException e) { +              throw new IOException(); +                            } +          } +        } catch (final NoninvertibleTransformException e) { +          throw new IOException(e); +        } +      } +    } else { +      super.processOperator(operator, arguments); +    } +  } +   +  private SignaturePlaceholderData matchPlaceholderDocument( +      List<SignaturePlaceholderData> placeholders, String placeholderId, +      int matchMode) throws PlaceholderExtractionException { + +    if (matchMode == PLACEHOLDER_MATCH_MODE_STRICT) { +      throw new PlaceholderExtractionException("error.pdf.stamp.09"); +    } + +    if (placeholders.size() == 0) { +      return null; +    } + +    if (matchMode == PLACEHOLDER_MATCH_MODE_SORTED) { +      // sort all placeholders by the id string if all ids are null do nothing +      SignaturePlaceholderData currentFirstSpd = null; +      for (final SignaturePlaceholderData spd : placeholders) { +        if (spd.getId() != null) { +          if (currentFirstSpd == null) { +            currentFirstSpd = spd; +            log.debug("Setting new current ID: {}", +                currentFirstSpd.getId()); +          } else { +            currentFirstSpd = placeHolderIdMatcher(currentFirstSpd, spd); + +          } +        } +      } + +      if (currentFirstSpd != null) { +        log.info("Running Placeholder sorted mode: using id: {}", currentFirstSpd.getId()); +        return currentFirstSpd; +         +      } else { +        log.info( +            "Running Placeholder sorted mode: no placeholder with id found, fallback to first placeholder"); +      } +    } + +    for (final SignaturePlaceholderData spd : placeholders) { +      if (spd.getId() == null) { +        return spd; +      } +    } + +    if (matchMode == PLACEHOLDER_MATCH_MODE_LENIENT) { +      return placeholders.get(0); +    } + +    return null; +  } + +  private SignaturePlaceholderData placeHolderIdMatcher(SignaturePlaceholderData currentFirstSpd, +      SignaturePlaceholderData spd) { +    try { +      Integer currentIDInt = Integer.valueOf(currentFirstSpd.getId()); +      Integer testIDInt = Integer.valueOf(spd.getId()); +       +      if (testIDInt < currentIDInt) { +        log.debug("Setting new current ID: {}", testIDInt); +        return spd; +         +      } else { +        return currentFirstSpd; +         +      }             +    } catch (NumberFormatException e) { +      log.trace("Can not compare placeholderId's on integer level. Using String compare ... "); +      final String currentID = currentFirstSpd.getId(); +      final String testID = spd.getId(); +      log.debug("Testing placeholder current: {} compare to {}", +          currentID, testID); +      if (testID.compareToIgnoreCase(currentID) < 0) {       +        log.debug("Setting new current ID: {}", +            testID);       +        return spd; +         +      } else { +        return currentFirstSpd; +             +      } +    }        +  } + +  private SignaturePlaceholderData matchPlaceholderPage( +      List<SignaturePlaceholderData> placeholders, String placeholderId, +      int matchMode) { + +    if ((matchMode == PLACEHOLDER_MATCH_MODE_SORTED) || (placeholders.size() == 0)) {       +      return null; +    } +     +    for (final SignaturePlaceholderData data : placeholders) { +      if (placeholderId != null && placeholderId.equals(data.getId())) { +        return data; +         +      } +      if (placeholderId == null && data.getId() == null) { +        return data; +         +      } +    } +     +    return null; +  } + +  private List<String> existingExistingSignatureNames(PDDocument doc) { +    final List<String> existingLocations = new ArrayList<>(); +    try { +      final List<PDSignature> pdSignatureList = doc.getSignatureDictionaries(); +      if (pdSignatureList.size() != 0) { +        for (final PDSignature sig : pdSignatureList) { +          existingLocations.add(sig.getLocation()); +        } +      } +    } catch (final IOException e) { +      e.printStackTrace(); +    } +    return existingLocations; +  } +   +  private List<SignaturePlaceholderData> removeAlreadyUsePlaceholders( +      List<SignaturePlaceholderData> placeholders, List<String> existingPlaceholders) { +    if (placeholders != null) { +      return placeholders.stream() +          .filter(el -> !existingPlaceholders.contains(el.getPlaceholderName())) +          .collect(Collectors.toList());              +       +    } else { +      return Collections.emptyList(); +       +    } +  } +   +  /** +   * Checks an image if it is a placeholder for a signature. +   * +   * @param image +   * @return +   * @throws IOException +   */ +  private SignaturePlaceholderData checkImage(PDImageXObject image) +      throws IOException { +    final BufferedImage bimg = image.getImage(); +    if (bimg == null) { +      String type = image.getSuffix(); +      if (type != null) { +        type = type.toUpperCase() + " images"; +      } else { +        type = "Image type"; +      } +      log.info("Unable to extract image for QRCode analysis. " +          + type +          + " not supported. Add additional JAI Image filters to your classpath. Refer to https://jai.dev.java.net. Skipping image."); +      return null; +       +    } +     +    if (bimg.getHeight() < 10 || bimg.getWidth() < 10) { +      log.debug("Image too small for QRCode. Skipping image."); +      return null; +    } + +    final LuminanceSource source = new BufferedImageLuminanceSource(bimg); +    final BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); +    Result result; +    final long before = System.currentTimeMillis(); +    try { +      final Hashtable<DecodeHintType, Object> hints = new Hashtable<>(); +      final Vector<BarcodeFormat> formats = new Vector<>(); +      formats.add(BarcodeFormat.QR_CODE); +      hints.put(DecodeHintType.POSSIBLE_FORMATS, formats); +      result = new MultiFormatReader().decode(bitmap, hints); + +      final String text = result.getText(); +      String profile = null; +      String type = null; +      String sigKey = null; +      String id = null; +      if (text != null) { +        if (text.startsWith(QR_PLACEHOLDER_IDENTIFIER)) { + +          final String[] data = text.split(";"); +          if (data.length > 1) { +            for (int i = 1; i < data.length; i++) { +              final String kvPair = data[i]; +              final String[] kv = kvPair.split("="); +              if (kv.length != 2) { +                log.debug("Invalid parameter in placeholder data: " +                    + kvPair); +              } else { +                if (kv[0] +                    .equalsIgnoreCase(SignaturePlaceholderData.ID_KEY)) { +                  id = kv[1]; +                } else if (kv[0] +                    .equalsIgnoreCase(SignaturePlaceholderData.PROFILE_KEY)) { +                  profile = kv[1]; +                } else if (kv[0] +                    .equalsIgnoreCase(SignaturePlaceholderData.SIG_KEY_KEY)) { +                  sigKey = kv[1]; +                } else if (kv[0] +                    .equalsIgnoreCase(SignaturePlaceholderData.TYPE_KEY)) { +                  type = kv[1]; +                } +              }              } +          } +          return new SignaturePlaceholderData(profile, type, sigKey, +              id); +        } else { +          log.warn("QR-Code found but does not start with \"" +              + QR_PLACEHOLDER_IDENTIFIER +              + "\". Ignoring QR placeholder."); +        } +      } +    } catch (final ReaderException re) { +      if (log.isDebugEnabled()) { +        log.debug("Could not decode - not a placeholder. needed: " +            + (System.currentTimeMillis() - before)); +      } +      if (!(re instanceof NotFoundException)) { +        if (log.isInfoEnabled()) { +          log.info("Failed to decode image", re);          } -        return fonts; -	} - -	/** -	 * Checks an image if it is a placeholder for a signature. -	 * -	 * @param image -	 * @return -	 * @throws IOException -	 */ -	private SignaturePlaceholderData checkImage(PDImageXObject image) -			throws IOException { -		BufferedImage bimg = image.getImage(); -		if (bimg == null) { -			String type = image.getSuffix(); -			if (type != null) { -				type = type.toUpperCase() + " images"; -			} else { -				type = "Image type"; -			} -			logger.info("Unable to extract image for QRCode analysis. " -					+ type -					+ " not supported. Add additional JAI Image filters to your classpath. Refer to https://jai.dev.java.net. Skipping image."); -			return null; -		} -		if (bimg.getHeight() < 10 || bimg.getWidth() < 10) { -			logger.debug("Image too small for QRCode. Skipping image."); -			return null; -		} - -		LuminanceSource source = new BufferedImageLuminanceSource(bimg); -		BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); -		Result result; -		long before = System.currentTimeMillis(); -		try { -			Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(); -			Vector<BarcodeFormat> formats = new Vector<BarcodeFormat>(); -			formats.add(BarcodeFormat.QR_CODE); -			hints.put(DecodeHintType.POSSIBLE_FORMATS, formats); -			result = new MultiFormatReader().decode(bitmap, hints); - -			String text = result.getText(); -			String profile = null; -			String type = null; -			String sigKey = null; -			String id = null; -			if (text != null) { -				if (text.startsWith(QR_PLACEHOLDER_IDENTIFIER)) { - -					String[] data = text.split(";"); -					if (data.length > 1) { -						for (int i = 1; i < data.length; i++) { -							String kvPair = data[i]; -							String[] kv = kvPair.split("="); -							if (kv.length != 2) { -								logger.debug("Invalid parameter in placeholder data: " -										+ kvPair); -							} else { -								if (kv[0] -										.equalsIgnoreCase(SignaturePlaceholderData.ID_KEY)) { -									id = kv[1]; -								} else if (kv[0] -										.equalsIgnoreCase(SignaturePlaceholderData.PROFILE_KEY)) { -									profile = kv[1]; -								} else if (kv[0] -										.equalsIgnoreCase(SignaturePlaceholderData.SIG_KEY_KEY)) { -									sigKey = kv[1]; -								} else if (kv[0] -										.equalsIgnoreCase(SignaturePlaceholderData.TYPE_KEY)) { -									type = kv[1]; -								} -							} -						} -					} -					return new SignaturePlaceholderData(profile, type, sigKey, -							id); -				} else { -					logger.warn("QR-Code found but does not start with \"" -							+ QR_PLACEHOLDER_IDENTIFIER -							+ "\". Ignoring QR placeholder."); -				} -			} -		} catch (ReaderException re) { -			if (logger.isDebugEnabled()) { -				logger.debug("Could not decode - not a placeholder. needed: " -						+ (System.currentTimeMillis() - before)); -			} -			if (!(re instanceof NotFoundException)) { -				if (logger.isInfoEnabled()) { -					logger.info("Failed to decode image", re); -				} -			} -		} catch (ArrayIndexOutOfBoundsException e) { -			if (logger.isInfoEnabled()) { -				logger.info("Failed to decode image. Probably a zxing bug", e); -			} -		} -		return null; -	} +      } +    } catch (final ArrayIndexOutOfBoundsException e) { +      if (log.isInfoEnabled()) { +        log.info("Failed to decode image. Probably a zxing bug", e); +      } +    } +    return null; +  }  } diff --git a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox2/PADESPDFBOXSigner.java b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox2/PADESPDFBOXSigner.java index b827abe6..e555cb39 100644 --- a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox2/PADESPDFBOXSigner.java +++ b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox2/PADESPDFBOXSigner.java @@ -70,8 +70,6 @@ import org.apache.pdfbox.rendering.PDFRenderer;  import org.apache.xmpbox.XMPMetadata;  import org.apache.xmpbox.schema.PDFAIdentificationSchema;  import org.apache.xmpbox.xml.DomXmpParser; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory;  import at.gv.egiz.pdfas.common.exceptions.PDFASError;  import at.gv.egiz.pdfas.common.exceptions.PdfAsException; @@ -83,7 +81,6 @@ import at.gv.egiz.pdfas.lib.api.sign.IPlainSigner;  import at.gv.egiz.pdfas.lib.api.sign.SignParameter;  import at.gv.egiz.pdfas.lib.impl.ErrorExtractor;  import at.gv.egiz.pdfas.lib.impl.SignaturePositionImpl; -import at.gv.egiz.pdfas.lib.impl.configuration.PlaceholderWebConfiguration;  import at.gv.egiz.pdfas.lib.impl.configuration.SignatureProfileConfiguration;  import at.gv.egiz.pdfas.lib.impl.pdfbox2.PDFBOXObject;  import at.gv.egiz.pdfas.lib.impl.pdfbox2.positioning.Positioning; @@ -107,40 +104,32 @@ import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction;  import at.knowcenter.wag.egov.egiz.pdf.TablePos;  import at.knowcenter.wag.egov.egiz.table.Table;  import iaik.x509.X509Certificate; +import lombok.extern.slf4j.Slf4j; +@Slf4j  public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants { -  private static final Logger logger = LoggerFactory.getLogger(PADESPDFBOXSigner.class); -  private boolean isAdobeSigForm = false; +    @Override    public void signPDF(PDFObject genericPdfObject, RequestedSignature requestedSignature,        PDFASSignatureInterface genericSigner) throws PdfAsException {      PDFAsVisualSignatureProperties properties = null; -    List<SignaturePlaceholderData> placeholders; -    List<SignaturePlaceholderData> availablePlaceholders; -    SignaturePlaceholderData signaturePlaceholderData = null; - -    String placeholder_id = ""; - -    if (PlaceholderWebConfiguration.getValue(PLACEHOLDER_WEB_ID) != null && !PlaceholderWebConfiguration -        .getValue(PLACEHOLDER_WEB_ID).equalsIgnoreCase("")) { -      placeholder_id = PlaceholderWebConfiguration.getValue(PLACEHOLDER_WEB_ID); -    } - +     +    boolean isAdobeSigForm = false; +          if (!(genericPdfObject instanceof PDFBOXObject)) { -      // tODO: -      throw new PdfAsException(); +      throw new PdfAsException("PDF to signObject is of wrong type: " + genericPdfObject.getClass().getName()); +            } -    final PDFBOXObject pdfObject = (PDFBOXObject) genericPdfObject; -      if (!(genericSigner instanceof PDFASPDFBOXSignatureInterface)) { -      // tODO: -      throw new PdfAsException(); +      throw new PdfAsException("PDF signerObject is of wrong type:" + genericSigner.getClass().getName()); +            } - +     +    final PDFBOXObject pdfObject = (PDFBOXObject) genericPdfObject;      final PDFASPDFBOXSignatureInterface signer = (PDFASPDFBOXSignatureInterface) genericSigner;      String pdfaVersion = null; @@ -148,76 +137,42 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {      PDDocument doc = null;      SignatureOptions options = new SignatureOptions();      try { -        doc = pdfObject.getDocument(); -      // if signature already exists dont create new page -      final List<PDSignatureField> pdSignatureFieldList = doc.getSignatureFields(); -      PDSignature signature; +              // sign a PDF with an existing empty signature, as created by the        // CreateEmptySignatureForm example. -      String sigFieldName = pdfObject.getStatus().getSettings().getValue(SIGNATURE_FIELD_NAME); -      signature = findExistingSignature(doc, sigFieldName); +      PDSignature signature = findExistingSignature(doc, getSignatureFieldNameConfig(pdfObject));         if (signature == null) {          // create signature dictionary          signature = new PDSignature(); +                } else {          isAdobeSigForm = true; +                }        signature.setFilter(COSName.getPDFName(signer.getPDFFilter()));        signature.setSubFilter(COSName.getPDFName(signer.getPDFSubFilter())); -//			SignaturePlaceholderData signaturePlaceholderDataInit = -      placeholders = PlaceholderFilter.checkPlaceholderSignatureLocationList(pdfObject.getStatus(), -          pdfObject.getStatus().getSettings(), placeholder_id); - -//            placeholders = SignaturePlaceholderExtractor.getPlaceholders(); -      availablePlaceholders = listAvailablePlaceholders(placeholders, existingSignatureLocations(doc)); - -      if (placeholder_id.equalsIgnoreCase("")) { -        if (checkAvailablePlaceholders(placeholders, existingSignatureLocations(doc)) != null) { -          placeholder_id = checkAvailablePlaceholders(placeholders, existingSignatureLocations(doc)).getId(); -        } -      } - -      if (availablePlaceholders != null) { -        signaturePlaceholderData = PlaceholderFilter -            .checkPlaceholderSignatureLocation(pdfObject.getStatus(), pdfObject.getStatus().getSettings(), -                placeholder_id); -      } - -      TablePos tablePos = null; - -      if (signaturePlaceholderData != null) { -        signature.setLocation(signaturePlaceholderData.getPlaceholderName()); -      } - -      if (signaturePlaceholderData != null) { -        // Placeholder found! -        placeholders.clear(); -        logger.info("Placeholder data found."); -        if (signaturePlaceholderData.getProfile() != null) { -          logger.debug("Placeholder Profile set to: " + signaturePlaceholderData.getProfile()); -          requestedSignature.setSignatureProfileID(signaturePlaceholderData.getProfile()); -        } - -        tablePos = signaturePlaceholderData.getTablePos(); -        if (tablePos != null) { - -          final SignatureProfileConfiguration signatureProfileConfiguration = pdfObject.getStatus() -              .getSignatureProfileConfiguration(requestedSignature.getSignatureProfileID()); - -          final float minWidth = signatureProfileConfiguration.getMinWidth(); - -          if (minWidth > 0) { -            if (tablePos.getWidth() < minWidth) { -              tablePos.width = minWidth; -              logger.debug("Correcting placeholder with to minimum width {}", minWidth); -            } -          } -          logger.debug("Placeholder Position set to: " + tablePos.toString()); +       +       +      String placeholder_id = pdfObject.getStatus().getSignParamter().getPlaceHolderId();       +       +      SignaturePlaceholderData nextPlaceholderData = PlaceholderFilter.checkPlaceholderSignatureLocation( +          pdfObject.getStatus(), pdfObject.getStatus().getSettings(), placeholder_id); + +      if (nextPlaceholderData != null) { +        log.info("Placeholder data found."); +        signature.setLocation(nextPlaceholderData.getPlaceholderName()); +                         +        if (nextPlaceholderData.getProfile() != null) {                     +          log.debug("Placeholder Profile set to: {}", nextPlaceholderData.getProfile()); +          requestedSignature.setSignatureProfileID(nextPlaceholderData.getProfile()); +                    }        } +       +                        final SignatureProfileSettings signatureProfileSettings = TableFactory.createProfile(            requestedSignature.getSignatureProfileID(), pdfObject.getStatus().getSettings()); @@ -243,9 +198,11 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {        }        signature.setReason(signerReason); -      logger.debug("Signing reason: " + signerReason); +      log.debug("Signing reason: " + signerReason); -      logger.debug("Signing @ " + signer.getSigningDate().getTime().toString()); +       +       +      log.debug("Signing @ " + signer.getSigningDate().getTime().toString());        // the signing date, needed for valid signature        // signature.setSignDate(signer.getSigningDate()); @@ -257,9 +214,9 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {          if (reservedSignatureSizeString != null) {            signatureSize = Integer.parseInt(reservedSignatureSizeString);          } -        logger.debug("Reserving {} bytes for signature", signatureSize); +        log.debug("Reserving {} bytes for signature", signatureSize);        } catch (final NumberFormatException e) { -        logger.warn("Invalid configuration value: {} should be a number using 0x1000", SIG_RESERVED_SIZE); +        log.warn("Invalid configuration value: {} should be a number using 0x1000", SIG_RESERVED_SIZE);        }        options.setPreferredSignatureSize(signatureSize); @@ -269,44 +226,15 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {        }        // Is visible Signature -      if (requestedSignature.isVisual()) { -        logger.info("Creating visual siganture block"); - -        final SignatureProfileConfiguration signatureProfileConfiguration = pdfObject.getStatus() -            .getSignatureProfileConfiguration(requestedSignature.getSignatureProfileID()); - -        if (tablePos == null) { -          // ================================================================ -          // PositioningStage (visual) -> find position or use -          // fixed -          // position - -          final String posString = pdfObject.getStatus().getSignParamter().getSignaturePosition(); - -          TablePos signaturePos = null; - -          final String signaturePosString = signatureProfileConfiguration.getDefaultPositioning(); - -          if (signaturePosString != null) { -            logger.debug("using signature Positioning: " + signaturePos); -            signaturePos = new TablePos(signaturePosString); -          } - -          logger.debug("using Positioning: " + posString); - -          if (posString != null) { -            // Merge Signature Position -            tablePos = new TablePos(posString, signaturePos); -          } else { -            // Fallback to signature Position! -            tablePos = signaturePos; -          } - -          if (tablePos == null) { -            // Last Fallback default position -            tablePos = new TablePos(); -          } -        } +      if (requestedSignature.isVisual()) {                 +        log.info("Creating visual siganture block"); +         +        final SignatureProfileConfiguration signatureProfileConfiguration =  +            pdfObject.getStatus().getSignatureProfileConfiguration(requestedSignature.getSignatureProfileID()); +        TablePos tablePos = prepareTablePosition(nextPlaceholderData, signatureProfileConfiguration, +            pdfObject.getStatus().getSignParamter().getSignaturePosition()); +         +                  // Legacy Modes not supported with pdfbox2 anymore  //				boolean legacy32Position = signatureProfileConfiguration.getLegacy32Positioning(); @@ -331,7 +259,7 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {              "",              doc, visualObject, pdfObject.getStatus().getSettings(), signatureProfileSettings); -        logger.debug("Positioning: {}", positioningInstruction.toString()); +        log.debug("Positioning: {}", positioningInstruction.toString());          if (!isAdobeSigForm) {            if (positioningInstruction.isMakeNewPage()) { @@ -347,11 +275,11 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {            // handle rotated page            final int targetPageNumber = positioningInstruction.getPage(); -          logger.debug("Target Page: " + targetPageNumber); +          log.debug("Target Page: " + targetPageNumber);            final PDPage targetPage = doc.getPages().get(targetPageNumber - 1);            final int rot = targetPage.getRotation(); -          logger.debug("Page rotation: " + rot); -          logger.debug("resulting Sign rotation: " + positioningInstruction.getRotation()); +          log.debug("Page rotation: " + rot); +          log.debug("resulting Sign rotation: " + positioningInstruction.getRotation());            final SignaturePositionImpl position = new SignaturePositionImpl();            position.setX(positioningInstruction.getX()); @@ -386,7 +314,7 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {           * int pageNumber = positioningInstruction.getPage(); PDPage page =           * doc.getPages().get(pageNumber - 1);           *  -         * logger.info("Placeholder name: " + +         * log.info("Placeholder name: " +           * signaturePlaceholderData.getPlaceholderName()); COSDictionary           * xobjectsDictionary = (COSDictionary) page.getResources().getCOSObject()           * .getDictionaryObject(COSName.XOBJECT); @@ -395,7 +323,7 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {           * xobjectsDictionary.setItem(signaturePlaceholderData.getPlaceholderName(),           * img); xobjectsDictionary.setNeedToBeUpdated(true);           * page.getResources().getCOSObject().setNeedToBeUpdated(true); -         * logger.info("Placeholder name: " + +         * log.info("Placeholder name: " +           * signaturePlaceholderData.getPlaceholderName()); }           */ @@ -418,7 +346,7 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {              root.setOutputIntents(oi);              root.getCOSObject().setNeedToBeUpdated(true); -            logger.info("added Output Intent"); +            log.info("added Output Intent");            } catch (final Throwable e) {              e.printStackTrace();              throw new PdfAsException("Failed to add Output Intent", e); @@ -432,6 +360,8 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {        doc.addSignature(signature, signer, options); +      String sigFieldName = getSignatureFieldNameConfig(pdfObject); +              if (sigFieldName == null) {          sigFieldName = "PDF-AS Signatur";        } @@ -473,7 +403,7 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {                }              }            } else { -            logger.warn("Failed to name Signature Field! [Cannot find Field list in acroForm!]"); +            log.warn("Failed to name Signature Field! [Cannot find Field list in acroForm!]");            }            if (signatureField != null) { @@ -485,7 +415,7 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {              signatureField.setAlternateFieldName(sigFieldName);            }          } else { -          logger.warn("Failed to name Signature Field! [Cannot find acroForm!]"); +          log.warn("Failed to name Signature Field! [Cannot find acroForm!]");          }        } @@ -496,16 +426,16 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {        }        // PDF-UA -      logger.info("Adding pdf/ua content."); +      log.info("Adding pdf/ua content.");        try {          final PDDocumentCatalog root = doc.getDocumentCatalog();          final PDStructureTreeRoot structureTreeRoot = root.getStructureTreeRoot();          if (structureTreeRoot != null) { -          logger.info("Tree Root: {}", structureTreeRoot.toString()); +          log.info("Tree Root: {}", structureTreeRoot.toString());            final List<Object> kids = structureTreeRoot.getKids();            if (kids == null) { -            logger.info("No kid-elements in structure tree Root, maybe not PDF/UA document"); +            log.info("No kid-elements in structure tree Root, maybe not PDF/UA document");            }            PDStructureElement docElement = null; @@ -549,7 +479,7 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {            PDNumberTreeNode ntn = structureTreeRoot.getParentTree();            if (ntn == null) {              ntn = new PDNumberTreeNode(objectDic, null); -            logger.info("No number-tree-node found!"); +            log.info("No number-tree-node found!");            }            final COSArray ntnKids = (COSArray) ntn.getCOSObject().getDictionaryObject(COSName.KIDS); @@ -622,10 +552,10 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {          }        } catch (final Throwable e) {          if (signatureProfileSettings.isPDFUA() == true) { -          logger.error("Could not create PDF-UA conform document!"); +          log.error("Could not create PDF-UA conform document!");            throw new PdfAsException("error.pdf.sig.pdfua.1", e);          } else { -          logger.info("Could not create PDF-UA conform signature"); +          log.info("Could not create PDF-UA conform signature");          }        } @@ -642,19 +572,19 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {          }        } catch (final IOException e1) { -        logger.error("Can not save incremental update", e1); +        log.error("Can not save incremental update", e1);        }        System.gc(); -      logger.debug("Signature done!"); +      log.debug("Signature done!");      } catch (final IOException e) { -      logger.warn(MessageResolver.resolveMessage("error.pdf.sig.01"), e); +      log.warn(MessageResolver.resolveMessage("error.pdf.sig.01"), e);        throw new PdfAsException("error.pdf.sig.01", e);      } catch (PDFASError e2) { -      logger.warn(e2.getInfo()); +      log.warn(e2.getInfo());        throw new PdfAsException("error.pdf.sig.01", e2);      } finally { @@ -664,7 +594,7 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {              options.getVisualSignature().close();              options.close();            } catch (IOException e) { -            logger.debug("Failed to close VisualSignature!", e); +            log.debug("Failed to close VisualSignature!", e);            }          }        } @@ -674,13 +604,60 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {            doc.close();            // SignaturePlaceholderExtractor.getPlaceholders().clear();          } catch (final IOException e) { -          logger.debug("Failed to close COS Doc!", e); +          log.debug("Failed to close COS Doc!", e);            // Ignore          }        }      }    } +  private TablePos prepareTablePosition(SignaturePlaceholderData nextPlaceholderData,  +      SignatureProfileConfiguration signatureProfileConfiguration, String profilePosParam) throws PdfAsException { + +                             +    if (nextPlaceholderData != null && nextPlaceholderData.getTablePos() != null) { +      final float minWidth = signatureProfileConfiguration.getMinWidth(); +      TablePos tablePos = nextPlaceholderData.getTablePos();          +      if (minWidth > 0) { +        if (tablePos.getWidth() < minWidth) { +          tablePos.width = minWidth; +          log.debug("Correcting placeholder with to minimum width {}", minWidth); +        } +      } +      log.debug("Placeholder Position set to: " + tablePos.toString()); +      return tablePos; +       +    } else { +      TablePos signaturePos = null; +      final String signaturePosString = signatureProfileConfiguration.getDefaultPositioning(); + +      if (signaturePosString != null) { +        log.debug("using signature Positioning: " + signaturePosString); +        signaturePos = new TablePos(signaturePosString); +         +      } + +      log.debug("using Positioning: " + profilePosParam); + +      if (profilePosParam != null) { +        // Merge Signature Position +        return new TablePos(profilePosParam, signaturePos);         +       +      } else if (signaturePos != null){ +        // Fallback to signature Position! +        return signaturePos; +         +      } else { +        return new TablePos(); +         +      } +    } +  } + +  private String getSignatureFieldNameConfig(PDFBOXObject pdfObject) { +    return pdfObject.getStatus().getSettings().getValue(SIGNATURE_FIELD_NAME); +  } +    private int getParentTreeNextKey(PDStructureTreeRoot structureTreeRoot) throws IOException {      int nextKey = structureTreeRoot.getParentTreeNextKey();      if (nextKey < 0) { @@ -717,31 +694,31 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {        document.close();        result = document.getResult(); -      logger.info("PDF-A Validation Result: " + result.isValid()); +      log.info("PDF-A Validation Result: " + result.isValid());        if (result.getErrorsList().size() > 0) { -        logger.error("The following validation errors occured for PDF-A validation"); +        log.error("The following validation errors occured for PDF-A validation");        }        for (final ValidationResult.ValidationError ve : result.getErrorsList()) { -        logger.error("\t" + ve.getErrorCode() + ": " + ve.getDetails()); +        log.error("\t" + ve.getErrorCode() + ": " + ve.getDetails());        }        if (!result.isValid()) { -        logger.info("The file is not a valid PDF-A document"); +        log.info("The file is not a valid PDF-A document");        }      } catch (final SyntaxValidationException e) { -      logger.error("The file is syntactically invalid.", e); +      log.error("The file is syntactically invalid.", e);        throw new PdfAsException("Resulting PDF Document is syntactically invalid.");      } catch (final ValidationException e) { -      logger.error("The file is not a valid PDF-A document.", e); +      log.error("The file is not a valid PDF-A document.", e);      } catch (final IOException e) { -      logger.error("An IOException (" + e.getMessage() +      log.error("An IOException (" + e.getMessage()            + ") occurred, while validating the PDF-A conformance", e);        throw new PdfAsException("Failed validating PDF Document IOException.");      } catch (final RuntimeException e) { -      logger.debug("An RuntimeException (" + e.getMessage() +      log.debug("An RuntimeException (" + e.getMessage()            + ") occurred, while validating the PDF-A conformance", e);        throw new PdfAsException("Failed validating PDF Document RuntimeException.");      } finally { @@ -876,10 +853,10 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {        return cutOut;      } catch (final PdfAsException e) { -      logger.warn("PDF-AS  Exception", e); +      log.warn("PDF-AS  Exception", e);        throw ErrorExtractor.searchPdfAsError(e, status);      } catch (final Throwable e) { -      logger.warn("Unexpected Throwable  Exception", e); +      log.warn("Unexpected Throwable  Exception", e);        throw ErrorExtractor.searchPdfAsError(e, status);      }    } @@ -897,7 +874,7 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {            if (pdfaIdentificationSchema != null) {              final Integer pdfaversion = pdfaIdentificationSchema.getPart();              final String conformance = pdfaIdentificationSchema.getConformance(); -            logger.info("Detected PDF/A Version: {} - {}", pdfaversion, conformance); +            log.info("Detected PDF/A Version: {} - {}", pdfaversion, conformance);              if (pdfaversion != null) {                return String.valueOf(pdfaversion); @@ -906,7 +883,7 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {          }        }      } catch (final Throwable e) { -      logger.warn("Failed to determine PDF/A Version!", e); +      log.warn("Failed to determine PDF/A Version!", e);      }      return null;    } @@ -931,74 +908,7 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants {      }      return signature;    } - -  private List<String> existingSignatureLocations(PDDocument doc) { -    final List<String> existingLocations = new ArrayList<>(); -    try { -      final List<PDSignature> pdSignatureList = doc.getSignatureDictionaries(); -      if (pdSignatureList.size() != 0) { -        for (final PDSignature sig : pdSignatureList) { -          existingLocations.add(sig.getLocation()); -        } -      } -    } catch (final IOException e) { -      e.printStackTrace(); -    } -    return existingLocations; -  } - -  // find first placeholder_id -  public SignaturePlaceholderData checkAvailablePlaceholders(List<SignaturePlaceholderData> placeholders, -      List<String> existingPlaceholders) { -    SignaturePlaceholderData result = null; - -    if (placeholders != null) { -      for (int i = 0; i < placeholders.size(); ++i) { -        // take smallest id -        if (!existingPlaceholders.contains(placeholders.get(i).getPlaceholderName())) { -          final SignaturePlaceholderData spd = placeholders.get(i); -          if (spd.getId() != null) { -            if (result == null) { -              result = spd; -            } else { -              try { -                final int currentID = Integer.parseInt(result.getId()); -                final int testID = Integer.parseInt(spd.getId()); -                if (testID < currentID) { -                  result = spd; -                } -              } catch (final Exception e) { -                // fallback to string compare -                final String currentID = result.getId(); -                final String testID = spd.getId(); -                if (testID.compareToIgnoreCase(currentID) < 0) { -                  result = spd; -                } -              } -            } -          } -        } -      } -    } -    return result; -  } - -  // find first placeholder_id -  public List<SignaturePlaceholderData> listAvailablePlaceholders(List<SignaturePlaceholderData> placeholders, -      List<String> existingPlaceholders) { -    final List<SignaturePlaceholderData> result = new ArrayList<>(); - -    if (placeholders != null) { -      for (int i = 0; i < placeholders.size(); ++i) { -        // take smallest id -        if (!existingPlaceholders.contains(placeholders.get(i).getPlaceholderName())) { -          result.add(placeholders.get(i)); -        } -      } -    }  -    return result; -  } - +      static Map<Integer, COSObjectable> getNumberTreeAsMap(PDNumberTreeNode tree)        throws IOException {      Map<Integer, COSObjectable> numbers = tree.getNumbers(); diff --git a/pdf-as-pdfbox-2/src/test/java/at/gv/egiz/pdfas/lib/testpdfbox/PDFBoxPlaceholderExtractorTest.java b/pdf-as-pdfbox-2/src/test/java/at/gv/egiz/pdfas/lib/testpdfbox/PDFBoxPlaceholderExtractorTest.java new file mode 100644 index 00000000..fbe3cdea --- /dev/null +++ b/pdf-as-pdfbox-2/src/test/java/at/gv/egiz/pdfas/lib/testpdfbox/PDFBoxPlaceholderExtractorTest.java @@ -0,0 +1,51 @@ +package at.gv.egiz.pdfas.lib.testpdfbox; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.io.IOException; +import java.util.List; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.junit.Test; + +import at.gv.egiz.pdfas.lib.impl.pdfbox2.placeholder.SignatureFieldsAndPlaceHolderExtractor; +import at.gv.egiz.pdfas.lib.impl.placeholder.SignaturePlaceholderData; +import lombok.SneakyThrows; + +public class PDFBoxPlaceholderExtractorTest { + +  @Test +  @SneakyThrows +  public void nextPlaceholder() { +    SignaturePlaceholderData result = getNextSignaturePlaceHolder("/data/platzhalter_en_de_test.pdf"); +    assertEquals("Im48", result.getPlaceholderName()); + +  } + +  @Test +  @SneakyThrows +  public void allPlaceHolders() { +    List<String> listOfPlaceHolders = getPlaceHolders("/data/platzhalter_en_de_test.pdf"); +    assertNotNull(listOfPlaceHolders); + +  } + +  private static List<String> getPlaceHolders(String filePath) throws IOException { +    final PDDocument doc = PDDocument.load(PDFBoxPlaceholderExtractorTest.class.getResourceAsStream( +        filePath)); +    final List<String> results = SignatureFieldsAndPlaceHolderExtractor.findEmptySignatureFields(doc); +    return results; + +  } + +  private static SignaturePlaceholderData getNextSignaturePlaceHolder(String filePath) throws IOException { +    final PDDocument doc = PDDocument.load(PDFBoxPlaceholderExtractorTest.class.getResourceAsStream( +        filePath)); +    final SignaturePlaceholderData result = +        SignatureFieldsAndPlaceHolderExtractor.getNextUnusedSignaturePlaceHolder(doc); +    return result; + +  } + +} diff --git a/pdf-as-pdfbox-2/src/test/java/at/gv/egiz/pdfas/lib/testpdfbox/SignatureFieldsAndPlaceHolderExtractorTest.java b/pdf-as-pdfbox-2/src/test/java/at/gv/egiz/pdfas/lib/testpdfbox/SignatureFieldsAndPlaceHolderExtractorTest.java index 0d85c82b..61a1199d 100644 --- a/pdf-as-pdfbox-2/src/test/java/at/gv/egiz/pdfas/lib/testpdfbox/SignatureFieldsAndPlaceHolderExtractorTest.java +++ b/pdf-as-pdfbox-2/src/test/java/at/gv/egiz/pdfas/lib/testpdfbox/SignatureFieldsAndPlaceHolderExtractorTest.java @@ -1,16 +1,17 @@  package at.gv.egiz.pdfas.lib.testpdfbox; -import at.gv.egiz.pdfas.lib.impl.pdfbox2.placeholder.SignatureFieldsAndPlaceHolderExtractor; -import at.gv.egiz.pdfas.lib.impl.placeholder.SignaturePlaceholderData; -import org.apache.pdfbox.pdmodel.PDDocument; -import org.junit.Assert; -import org.junit.Test; -  import java.io.File;  import java.util.ArrayList;  import java.util.Arrays;  import java.util.List; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.junit.Assert; +import org.junit.Test; + +import at.gv.egiz.pdfas.lib.impl.pdfbox2.placeholder.SignatureFieldsAndPlaceHolderExtractor; +import at.gv.egiz.pdfas.lib.impl.placeholder.SignaturePlaceholderData; +  public class SignatureFieldsAndPlaceHolderExtractorTest {    public String getPath(String resourceName) { @@ -48,6 +49,14 @@ public class SignatureFieldsAndPlaceHolderExtractorTest {      SignaturePlaceholderData result = getNextSignaturePlaceHolder(getPath("manySignFields.pdf"));      Assert.assertEquals(null,result);    } +   +  @Test +  public void firstQrCodeOnUnsignedDoc() { +    SignaturePlaceholderData result = getNextSignaturePlaceHolder(getPath("new_qr_2-2.pdf")); +    Assert.assertEquals("Image5",result.getPlaceholderName()); +     +  } +      @Test    public void subsequentCalls(){      SignaturePlaceholderData result = getNextSignaturePlaceHolder(getPath("new_qr_2_signed_signed_signed.pdf")); diff --git a/pdf-as-pdfbox-2/src/test/resources/data/platzhalter_en_de_test.pdf b/pdf-as-pdfbox-2/src/test/resources/data/platzhalter_en_de_test.pdfBinary files differ new file mode 100644 index 00000000..06b9aa0e --- /dev/null +++ b/pdf-as-pdfbox-2/src/test/resources/data/platzhalter_en_de_test.pdf | 
