itextpdf 提取数字签名签章图片

itextpdf 提取数字签名签章图片

因业务需求,需要对签名的pdf进行签名验证,政府的电子验证的功能是除了提取pdf表单内容外,还可以提取签章的图片,研究了好久,特此记录一下。

/** * 获取pdf签名图片信息 * @param path pdf文件 * @param fileBasePath 图片保存基础路径 * @return 提取结果 */
public static PdfSignInfo getImageFromPdf(String path, String fileBasePath) { 
    PdfSignInfo pdfSignInfo = new PdfSignInfo();
    try { 
        FileInputStream fis = new FileInputStream(path);
        PdfReader reader = new PdfReader(fis);

        String fileName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
        if (!fileBasePath.endsWith("/")) { 
            fileBasePath = fileBasePath + "/";
        }
        fileBasePath = fileBasePath + fileName + "/";
        File file = new File(fileBasePath);
        file.mkdirs();

        pdfSignInfo.setName(path.substring(path.lastIndexOf("/") + 1));

        Field rsaDataField = PdfPKCS7.class.getDeclaredField("RSAdata");
        rsaDataField.setAccessible(true);

        int numberOfPages = reader.getNumberOfPages();
        // pdf 页码数量
        log.debug("page size: {}", numberOfPages);

        int xrefSize = reader.getXrefSize();

        ExtImageRenderListener listener = new ExtImageRenderListener();
        listener.setBasePath(fileBasePath);

        // 获取acro字段
        AcroFields fields = reader.getAcroFields();
        Rectangle pageSize = reader.getPageSize(numberOfPages - 1);
        // pdf 作用域尺寸(全屏)
        log.info("pdf rectangle: {},{},{},{}", pageSize.getLeft(), pageSize.getBottom(), pageSize.getRight(), pageSize.getTop());

        // 获取签名名称
        ArrayList<String> signatureNames = fields.getSignatureNames();
        for (String name : signatureNames) { 
            // 指定提供者 获取签名的pkcs7数据
            PdfPKCS7 pkcs7 = fields.verifySignature(name);
            X509Certificate certificate = pkcs7.getSigningCertificate();

            PdfSignInfo.SignatureDetail info = new PdfSignInfo.SignatureDetail();

            String[] appearanceStates = fields.getAppearanceStates(name);
            // 表单域的位置
            List<AcroFields.FieldPosition> fieldPositions = fields.getFieldPositions(name);
            for (AcroFields.FieldPosition fieldPosition : fieldPositions) { 
                Rectangle position = fieldPosition.position;
                log.info("field {} position: {}, {}, {}, {}, {}", name, fieldPosition.page,
                        position.getLeft(), position.getBottom(), position.getRight(), position.getTop());
                info.page = fieldPosition.page;
                info.llx = position.getLeft();
                info.lly = position.getBottom();
                info.urx = position.getRight();
                info.ury = position.getTop();
            }

            AcroFields.Item fieldItem = fields.getFieldItem(name);
            int size = fieldItem.size();
            for (int i = 0; i < size; i++) { 
                PdfDictionary value = fieldItem.getValue(i);
                Set<PdfName> keys = value.getKeys();
                for (PdfName key : keys) { 
                    String keyName = PdfName.decodeName(new String(key.getBytes()));
                    if ("Rect".equalsIgnoreCase(keyName)) { 
                        log.debug("签名域的坐标为:{}", value.get(key));
                    }
                }
                PdfObject pdfObject = value.get(PdfName.AP);
                if (pdfObject != null) { 
                    PdfDictionary dictionary = (PdfDictionary) pdfObject;
                    PdfIndirectReference ref = (PdfIndirectReference) dictionary.get(PdfName.N);
                    int number = ref.getNumber();
                    log.debug("fieldName: {}, idx: {}", name, number);

                    // 根据ap 获取签章图片
                    PdfObject pdfObjectRelease = reader.getPdfObject(number);
                    if (pdfObjectRelease instanceof PdfStream) { 
                        PdfStream s = (PdfStream) pdfObjectRelease;
                        PdfDictionary resources = s.getAsDict(PdfName.RESOURCES);
                        listener.setI(number);
                        try { 
                            PdfContentStreamProcessor processor = new PdfContentStreamProcessor(listener);
                            processor.processContent(ContentByteUtils.getContentBytesFromContentObject(s), resources);
                            info.filePath = fileBasePath + number + ".png";
                        } catch (Exception ignore) { }
                    }
                }

            }

            // 签名信息
            info.name = name;
            info.time = pkcs7.getSignDate().getTime();
            info.notBefore = certificate.getNotBefore();
            info.notAfter = certificate.getNotAfter();
            info.dnName = certificate.getSubjectDN().getName();
            info.serialNumber = certificate.getSerialNumber();
            info.pubKey = Base64Encoder.encode(certificate.getPublicKey().getEncoded());
            info.pubKeyFormat = certificate.getPublicKey().getFormat();
            info.sigAlgName = certificate.getSigAlgName();
            info.userDnName = certificate.getIssuerDN().getName();
            info.reason = pkcs7.getReason();
            info.location = pkcs7.getLocation();

            info.res = pkcs7.verify();

            pdfSignInfo.getSignatureDetails().add(info);
        }
        log.info(JSON.toJSONString(pdfSignInfo));
    } catch (Exception e) { 
        e.printStackTrace();
    }
    return pdfSignInfo;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PdfSignInfo { 

    private String name;

    private List<SignatureDetail> signatureDetails = new ArrayList<>();

    public static class SignatureDetail { 
        public String name;
        // 签名日期时间
        public Date time;
        // 有效期开始时间
        public Date notBefore;
        // 有效期
        public Date notAfter;
        // 证书名称
        public String dnName;
        // 序列号
        public BigInteger serialNumber;
        // 证书格式 // 证书颁发者
        public String pubKey, pubKeyFormat, sigAlgName, userDnName;
        public boolean res;
        public String imageContent, imagePath;

        public String reason, location;

        public int page;
        public float llx, lly, urx, ury;

        public String filePath;
    }

}
@Slf4j
@Data
public class ExtImageRenderListener implements RenderListener { 
    private int i;
    private String basePath;
    @Override
    public void beginTextBlock() { 

    }

    public void setBasePath(String basePath) { 
        if (basePath.endsWith("/")) { 
            this.basePath = basePath;
        } else { 
            this.basePath = basePath + "/";
        }
    }

    @Override
    public void renderText(TextRenderInfo renderInfo) { 

    }

    @Override
    public void endTextBlock() { 

    }

    PdfDictionary resources;

    List<List<Integer>> numbers = new ArrayList<>();

    @SneakyThrows
    @Override
    public void renderImage(ImageRenderInfo renderInfo) { 
        PdfImageObject image = renderInfo.getImage();
        if (image == null) { 
            log.debug("Image {} could not be read", renderInfo.getRef().getNumber());
            return;
        }

        BufferedImage bufferedImage = image.getBufferedImage();
        if (bufferedImage != null) { 
            log.debug("bufferedImage: {}", bufferedImage.getHeight());
            writeImage(bufferedImage);
        }

// PRStream maskStream = (PRStream) image.getDictionary().getAsStream(PdfName.SMASK);
// if (maskStream != null) { 
// PdfImageObject pdfImageObject = new PdfImageObject(maskStream);
// log.debug("mask image: {}", pdfImageObject.getFileType());
// BufferedImage mask = pdfImageObject.getBufferedImage();
// writeImage(mask);
// }
    }

    private void writeImage(BufferedImage bufferedImage) { 
        try { 
            File file = new File(basePath + i + ".png");
            if (file.exists()) { 
                return;
            }
            log.debug("generated image: {}", file.getPath());
            ImageIO.write(bufferedImage, "png", file);
        } catch (IOException e) { 
            e.printStackTrace();
        }
    }
}

    原文作者:fangdengfu123
    原文地址: https://blog.csdn.net/fangdengfu123/article/details/124439187
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞