From b4b272b6af9d1f3c51011a407cdc29f64b812865 Mon Sep 17 00:00:00 2001 From: Andreas Fitzek Date: Thu, 10 Apr 2014 16:59:08 +0200 Subject: Memory optimizations, added Version to web --- .../placeholder/SignaturePlaceholderExtractor.java | 547 ++++++++++----------- 1 file changed, 271 insertions(+), 276 deletions(-) (limited to 'pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderExtractor.java') diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderExtractor.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderExtractor.java index 816ca04f..93162bd3 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderExtractor.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderExtractor.java @@ -89,8 +89,6 @@ import com.google.zxing.common.HybridBinarizer; ////// - - /** * Extract all relevant information from a placeholder image. * @@ -98,279 +96,276 @@ import com.google.zxing.common.HybridBinarizer; * */ public class SignaturePlaceholderExtractor extends PDFStreamEngine { - /** - * The log. - */ - private static Log log = LogFactory.getLog(SignaturePlaceholderExtractor.class); - - public static final String QR_PLACEHOLDER_IDENTIFIER = "PDF-AS-POS"; - public static final int PLACEHOLDER_MATCH_MODE_STRICT = 0; - public static final int PLACEHOLDER_MATCH_MODE_MODERATE = 1; - public static final int PLACEHOLDER_MATCH_MODE_LENIENT = 2; - - private List placeholders = new Vector(); - private int currentPage = 0; - - private SignaturePlaceholderExtractor(String placeholderId, int placeholderMatchMode) throws IOException { - super(ResourceLoader.loadProperties("placeholder/pdfbox-reader.properties", - true)); - } - - /** - * Search the document for placeholder images and possibly included - * additional info.
- * Searches only for the first placeholder page after page from top. - * - * @param inputStream - * @return all available info from the first found placeholder. - * @throws PDFDocumentException if the document could not be read. - * @throws PlaceholderExtractionException if STRICT matching mode was requested and no suitable placeholder could be found. - */ - public static SignaturePlaceholderData extract(InputStream inputStream, String placeholderId, int matchMode) - throws PdfAsException { - SignaturePlaceholderContext.setSignaturePlaceholderData(null); - PDDocument doc = null; - try - { - try { - doc = PDDocument.load(inputStream); - } catch (IOException e) { - throw new PDFIOException("error.pdf.io.04", e); - } - SignaturePlaceholderExtractor extractor; - try - { - extractor = new SignaturePlaceholderExtractor(placeholderId, matchMode); - } catch (IOException e2) { - throw new PDFIOException("error.pdf.io.04", e2); - } - List pages = doc.getDocumentCatalog().getAllPages(); - Iterator iter = pages.iterator(); - int pageNr = 0; - while (iter.hasNext()) { - pageNr++; - PDPage page = (PDPage) iter.next(); - try { - extractor.setCurrentPage(pageNr); - extractor.processStream( page, page.findResources(), page.getContents().getStream() ); - SignaturePlaceholderData ret = matchPlaceholderPage(extractor.placeholders, placeholderId, matchMode); - if (ret != null){ - SignaturePlaceholderContext.setSignaturePlaceholderData(ret); - return ret; - } - } catch (IOException e1) { - throw new PDFIOException("error.pdf.io.04", e1); - } - - } - if (extractor.placeholders.size() > 0){ - SignaturePlaceholderData ret = matchPlaceholderDocument(extractor.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; - } finally { - if (doc != null) - try { - doc.close(); - } catch (IOException e) { - log.debug("Could not close document.", e); - } - } - - } - - private static SignaturePlaceholderData matchPlaceholderDocument( - List 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; - - 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 static SignaturePlaceholderData matchPlaceholderPage(List placeholders, - String placeholderId, int matchMode) { - 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(PDFOperator operator, List arguments) throws IOException - { - String operation = operator.getOperation(); - if( operation.equals( "Do" ) ) - { - COSName objectName = (COSName)arguments.get( 0 ); - Map xobjects = getResources().getXObjects(); - PDXObject xobject = (PDXObject)xobjects.get( objectName.getName() ); - if( xobject instanceof PDXObjectImage ) - { - try - { - PDXObjectImage image = (PDXObjectImage)xobject; - SignaturePlaceholderData data = checkImage(image); - if (data != null) - { - PDPage page = getCurrentPage(); - Matrix ctm = getGraphicsState().getCurrentTransformationMatrix(); - double rotationInRadians = (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 y = unrotatedCTM.getYPosition() + unrotatedCTM.getYScale(); - float w = unrotatedCTM.getXScale(); - - String posString = "p:" + currentPage + ";x:" + x + ";y:" + y + ";w:" + w; - try - { - data.setTablePos(new TablePos(posString)); - data.setPlaceholderName(objectName.getName()); - placeholders.add(data); - } catch (PdfAsException e) { - throw new WrappedIOException(e); - } - } - } - catch( NoninvertibleTransformException e ) - { - throw new WrappedIOException( e ); - } - } - } - else - { - super.processOperator(operator, arguments); - } - } - - /** - * Checks an image if it is a placeholder for a signature. - * - * @param image - * @return - * @throws IOException - */ - private SignaturePlaceholderData checkImage(PDXObjectImage image) throws IOException { - BufferedImage bimg = image.getRGBImage(); - 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; - } - - LuminanceSource source = new BufferedImageLuminanceSource(bimg); - BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); - Result result; - long before = System.currentTimeMillis(); - try { - Hashtable> hints = new Hashtable>(); - Vector formats = new Vector(); - 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) { - 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 (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); - } - } - } catch(ArrayIndexOutOfBoundsException e){ - if (log.isInfoEnabled()) { - log.info("Failed to decode image. Probably a zxing bug", e); - } - } - return null; - } + /** + * The log. + */ + private static Log log = LogFactory + .getLog(SignaturePlaceholderExtractor.class); + + public static final String QR_PLACEHOLDER_IDENTIFIER = "PDF-AS-POS"; + public static final int PLACEHOLDER_MATCH_MODE_STRICT = 0; + public static final int PLACEHOLDER_MATCH_MODE_MODERATE = 1; + public static final int PLACEHOLDER_MATCH_MODE_LENIENT = 2; + + private List placeholders = new Vector(); + private int currentPage = 0; + + private SignaturePlaceholderExtractor(String placeholderId, + int placeholderMatchMode) throws IOException { + super(ResourceLoader.loadProperties( + "placeholder/pdfbox-reader.properties", true)); + } + + /** + * Search the document for placeholder images and possibly included + * additional info.
+ * Searches only for the first placeholder page after page from top. + * + * @param inputStream + * @return all available info from the first found placeholder. + * @throws PDFDocumentException + * if the document could not be read. + * @throws PlaceholderExtractionException + * if STRICT matching mode was requested and no suitable + * placeholder could be found. + */ + public static SignaturePlaceholderData extract(PDDocument doc, + String placeholderId, int matchMode) throws PdfAsException { + SignaturePlaceholderContext.setSignaturePlaceholderData(null); + + SignaturePlaceholderExtractor extractor; + try { + extractor = new SignaturePlaceholderExtractor(placeholderId, + matchMode); + } catch (IOException e2) { + throw new PDFIOException("error.pdf.io.04", e2); + } + List pages = doc.getDocumentCatalog().getAllPages(); + Iterator iter = pages.iterator(); + int pageNr = 0; + while (iter.hasNext()) { + pageNr++; + PDPage page = (PDPage) iter.next(); + try { + extractor.setCurrentPage(pageNr); + extractor.processStream(page, page.findResources(), page + .getContents().getStream()); + SignaturePlaceholderData ret = matchPlaceholderPage( + extractor.placeholders, placeholderId, matchMode); + if (ret != null) { + SignaturePlaceholderContext + .setSignaturePlaceholderData(ret); + return ret; + } + } catch (IOException e1) { + throw new PDFIOException("error.pdf.io.04", e1); + } + + } + if (extractor.placeholders.size() > 0) { + SignaturePlaceholderData ret = matchPlaceholderDocument( + extractor.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; + } + + private static SignaturePlaceholderData matchPlaceholderDocument( + List 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; + + 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 static SignaturePlaceholderData matchPlaceholderPage( + List placeholders, String placeholderId, + int matchMode) { + 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(PDFOperator operator, List arguments) + throws IOException { + String operation = operator.getOperation(); + if (operation.equals("Do")) { + COSName objectName = (COSName) arguments.get(0); + Map xobjects = getResources().getXObjects(); + PDXObject xobject = (PDXObject) xobjects.get(objectName.getName()); + if (xobject instanceof PDXObjectImage) { + try { + PDXObjectImage image = (PDXObjectImage) xobject; + SignaturePlaceholderData data = checkImage(image); + if (data != null) { + PDPage page = getCurrentPage(); + Matrix ctm = getGraphicsState() + .getCurrentTransformationMatrix(); + double rotationInRadians = (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 y = unrotatedCTM.getYPosition() + + unrotatedCTM.getYScale(); + float w = unrotatedCTM.getXScale(); + + String posString = "p:" + currentPage + ";x:" + x + + ";y:" + y + ";w:" + w; + try { + data.setTablePos(new TablePos(posString)); + data.setPlaceholderName(objectName.getName()); + placeholders.add(data); + } catch (PdfAsException e) { + throw new WrappedIOException(e); + } + } + } catch (NoninvertibleTransformException e) { + throw new WrappedIOException(e); + } + } + } else { + super.processOperator(operator, arguments); + } + } + + /** + * Checks an image if it is a placeholder for a signature. + * + * @param image + * @return + * @throws IOException + */ + private SignaturePlaceholderData checkImage(PDXObjectImage image) + throws IOException { + BufferedImage bimg = image.getRGBImage(); + 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; + } + + LuminanceSource source = new BufferedImageLuminanceSource(bimg); + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + Result result; + long before = System.currentTimeMillis(); + try { + Hashtable> hints = new Hashtable>(); + Vector formats = new Vector(); + 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) { + 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 (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); + } + } + } catch (ArrayIndexOutOfBoundsException e) { + if (log.isInfoEnabled()) { + log.info("Failed to decode image. Probably a zxing bug", e); + } + } + return null; + } } - - -- cgit v1.2.3