使用PDFBox从PDF获取可见签名?

使用PDFBox从PDF获取可见签名?,pdf,digital-signature,capture,signature,pdfbox,Pdf,Digital Signature,Capture,Signature,Pdfbox,是否可以使用OSS库PDFBox提取签名PDF的可见签名(图像) 工作流程: 列出文件的所有签名 显示包含可见签名的签名 显示哪些是有效的 提取签名图像(需要为每个签名提取正确的图像) 下面这种oop风格的东西会很棒: PDFSignatures [] sigs = document.getPDFSignatures() sig[0].getCN() ... (Buffered)Image visibleSig = sig[0].getVisibleSignature() 找到了类PDSign

是否可以使用OSS库PDFBox提取签名PDF的可见签名(图像)

工作流程:

  • 列出文件的所有签名
  • 显示包含可见签名的签名
  • 显示哪些是有效的
  • 提取签名图像(需要为每个签名提取正确的图像)
  • 下面这种oop风格的东西会很棒:

    PDFSignatures [] sigs = document.getPDFSignatures()
    sig[0].getCN()
    ...
    (Buffered)Image visibleSig = sig[0].getVisibleSignature()
    

    找到了类PDSignature和如何签署PDF,但没有将可见签名提取为图像的解决方案。

    由于没有人来回答,我自己在对您的问题的评论中尝试了我的建议。第一个结果是:

    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.convertToImage(int-imageType,int-resolution)的参数。

    当心,这已经发生了

    a。已根据PDFBox 1.8.2进行黑客攻击;它可能包含特定版本的代码;
    B只是检查了一些我在这里看到的签名注释;它可能不完整,特别是对于其他注释类型,它可能会失败。

    是的,这是可能的,但不是,它不像仅仅调用一个方法那么简单,但也不是什么神奇的事情。只需研究
    PDPage.convertToImage
    PageDrawer.drawPage中发生的情况。
    在后一种方法中,您可以看到页面内容之后如何绘制页面批注的外观。基本上,您必须找到签名字段的注释,并仅在各自大小的画布上绘制它们。透明度不受尊重(因此我将在此位置获取可见的捕获+文档)2。两个重叠的签名不可恢复。posion对添加的注释进行匹配并不是很聪明。这就是为什么您应该研究这些方法,并(不幸的是,我没有清楚地阐明)将它们作为自己代码的灵感,只呈现签名注释,并且单独呈现每个注释。感谢您的回复,但实现起来很复杂。在评估一个实现时,我没有发现有可能获得嵌入图像的原始大小(没有DPI),不知道是否真的需要,但我的目标是以原始大小提取图像,而不进行任何缩放。要以原始大小提取图像,这是什么意思?PDF本质上不是光栅化格式(即使它可能包含光栅化图像),但您希望将其渲染为光栅化格式。因此,您可以决定使用哪种分辨率,这意味着可以选择大小。这太棒了!非常感谢,比我想象的简单多了。非常好的示例。获得正常图像的近似分辨率是多少?这里的图像以何种方式不正常?
    AnnotationDrawer drawer = new AnnotationDrawer(8, 288);
    Map<String, BufferedImage> images = drawer.convertToImages(page);