2013-06-05 49 views
3

是否可以使用OSS庫libBox提取簽名PDF的可見簽名(捕獲圖像)?使用PDFBox從PDF獲取可見簽名?

工作流程: - 列表的文件 所有簽名 - 與簽名顯示包括可視簽名 - 顯示這是有效的 - 簽名中提取圖像(需要提取正確的圖像每個簽名)

東西在OOP風格像以下將真棒: PDFSignatures [] SIGS = document.getPDFSignatures() SIG [0] .getCN() ... (緩衝)圖像visibleSig = SIG [0] .getVisibleSignature()

找到PDSignature類以及如何簽名PDF,但不是將可見簽名提取爲圖像的解決方案。

感謝您的幫助! Greets

+0

是的,這是可能的,但不是,它不像調用一種方法那麼簡單,但它也不是魔術。只要研究'PDPage.convertToImage'和'PageDrawer.drawPage.'中發生了什麼。在後一種方法中,您將看到在頁面內容之後如何繪製頁面註釋的外觀。基本上,您必須找到簽名字段的註釋,並在* *各自的大小畫布上繪製*只*。 – mkl

+0

這兩個問題:1.透明度不被尊重(所以我會在這個位置得到可見的捕獲+文檔)2.兩個重疊的簽名是不可恢復的。通過添加評論的匹配完成的匹配不是很聰明。 – ctvoigt

+0

這就是爲什麼你應該看看這些方法和(因爲我遺憾地沒有清楚地說明)**把它們作爲自己的代碼的靈感,只渲染簽名註釋和每個單獨的代碼** – mkl

回答

6

由於沒有人回答,我在自己的問題的評論中嘗試了我的建議。第一個結果是:

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.image.BufferedImage; 
import java.io.IOException; 
import java.lang.reflect.Field; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 

import org.apache.pdfbox.cos.COSName; 
import org.apache.pdfbox.pdfviewer.PageDrawer; 
import org.apache.pdfbox.pdmodel.PDPage; 
import org.apache.pdfbox.pdmodel.common.PDRectangle; 
import org.apache.pdfbox.pdmodel.graphics.PDGraphicsState; 
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; 
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary; 
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; 

public class AnnotationDrawer extends PageDrawer 
{ 
    public AnnotationDrawer(int imageType, int resolution) throws IOException 
    { 
     super(); 
     this.imageType = imageType; 
     this.resolution = resolution; 
    } 

    public Map<String, BufferedImage> convertToImages(PDPage p) throws IOException 
    { 
     page = p; 
     final Map<String, BufferedImage> result = new HashMap<String, BufferedImage>(); 

     List<PDAnnotation> annotations = page.getAnnotations(); 
     for (PDAnnotation annotation: annotations) 
     { 
      String appearanceName = annotation.getAppearanceStream(); 
      PDAppearanceDictionary appearDictionary = annotation.getAppearance(); 
      if(appearDictionary != null) 
      { 
       if(appearanceName == null) 
       { 
        appearanceName = "default"; 
       } 
       Map<String, PDAppearanceStream> appearanceMap = appearDictionary.getNormalAppearance(); 
       if (appearanceMap != null) 
       { 
        PDAppearanceStream appearance = 
         (PDAppearanceStream)appearanceMap.get(appearanceName); 
        if(appearance != null) 
        { 
         BufferedImage image = initializeGraphics(annotation); 
         setTextMatrix(null); 
         setTextLineMatrix(null); 
         getGraphicsStack().clear(); 
         processSubStream(page, appearance.getResources(), appearance.getStream()); 

         String name = annotation.getAnnotationName(); 
         if (name == null || name.length() == 0) 
         { 
          name = annotation.getDictionary().getString(COSName.T); 
          if (name == null || name.length() == 0) 
          { 
           name = Long.toHexString(annotation.hashCode()); 
          } 
         } 

         result.put(name, image); 
        } 
       } 
      } 
     } 

     return result; 
    } 

    BufferedImage initializeGraphics(PDAnnotation annotation) 
    { 
     PDRectangle rect = annotation.getRectangle(); 
     float widthPt = rect.getWidth(); 
     float heightPt = rect.getHeight(); 
     float scaling = resolution/(float)DEFAULT_USER_SPACE_UNIT_DPI; 
     int widthPx = Math.round(widthPt * scaling); 
     int heightPx = Math.round(heightPt * scaling); 
     //TODO The following reduces accuracy. It should really be a Dimension2D.Float. 
     Dimension pageDimension = new Dimension((int)widthPt, (int)heightPt); 
     BufferedImage retval = new BufferedImage(widthPx, heightPx, imageType); 
     Graphics2D graphics = (Graphics2D)retval.getGraphics(); 
     graphics.setBackground(TRANSPARENT_WHITE); 
     graphics.clearRect(0, 0, retval.getWidth(), retval.getHeight()); 
     graphics.scale(scaling, scaling); 
     setGraphics(graphics); 
     pageSize = pageDimension; 
     graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
     graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 
     setGraphicsState(new PDGraphicsState(new PDRectangle(widthPt, heightPt))); 

     return retval; 
    } 

    void setGraphics(Graphics2D graphics) 
    { 
     try { 
      Field field = PageDrawer.class.getDeclaredField("graphics"); 
      field.setAccessible(true); 
      field.set(this, graphics); 
     } catch (Exception e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

    private static final int DEFAULT_USER_SPACE_UNIT_DPI = 72; 
    private static final Color TRANSPARENT_WHITE = new Color(255, 255, 255, 0); 

    private int imageType; 
    private int resolution; 
} 

如果你想呈現給定的PDPage page,你只是做了註解:

AnnotationDrawer drawer = new AnnotationDrawer(8, 288); 
Map<String, BufferedImage> images = drawer.convertToImages(page); 

構造函數的參數對應於那些PDPage.convertToImage(int imageType, int resolution).

當心,這有

a。基於PDFBox 1.8.2一起被黑客入侵;它可能包含版本特定的代碼; b。僅僅檢查了我在這裏的一些可見的簽名註釋;它可能不完整,尤其對其他註釋類型可能會失敗。

+0

這太棒了!非常感謝你,比我想象的要簡單得多。真的很棒的樣品。 – ctvoigt