首页 > 解决方案 > 如何检索 PdfStampAnnotation 的图像

问题描述

我使用以下示例创建了一个 pdf: https ://developers.itextpdf.com/examples/actions-and-annotations/clone-creating-and-adding-annotations#2260-addstamp.java

@Category(SampleTest.class)
public class AddStamp extends GenericTest {
    public static final String DEST = "./target/test/resources/sandbox/annotations/add_stamp.pdf";
    public static final String IMG = "./src/test/resources/img/itext.png";
    public static final String SRC = "./src/test/resources/pdfs/hello.pdf";

    public static void main(String[] args) throws Exception {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new AddStamp().manipulatePdf(DEST);
    }

    @Override
    protected void manipulatePdf(String dest) throws Exception {
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(SRC), new PdfWriter(DEST));

        ImageData img = ImageDataFactory.create(IMG);
        float w = img.getWidth();
        float h = img.getHeight();
        Rectangle location = new Rectangle(36, 770 - h, w, h);
        PdfStampAnnotation stamp = new PdfStampAnnotation(location)
            .setStampName(new PdfName("ITEXT"));
        PdfFormXObject xObj = new PdfFormXObject(new Rectangle(w, h));
        PdfCanvas canvas = new PdfCanvas(xObj, pdfDoc);
        canvas.addImage(img, 0, 0, false);
        stamp.setNormalAppearance(xObj.getPdfObject());
        stamp.setFlags(PdfAnnotation.PRINT);

        pdfDoc.getFirstPage().addAnnotation(stamp);
        pdfDoc.close();
    }
}

pdf已正确创建并包含戳记注释

我可以使用以下方法获取注释:

...
PdfStampAnnotation s = (PdfStampAnnotation) pdfDoc.getFirstPage().getAnnotations().get(0);
s.?????

我怎样才能取回邮票的图像(itext.png)(例如:byte [])?我对 itext 真的很陌生,经过数小时的研究,我被困在这一点上......

标签: javaitextitext7

解决方案


首先,您将无法取回原始图像。PDF 仅支持很少的位图图像格式:JPEG、JPEG2000、某些传真格式,但绝对不支持 PNG。PNG 被转换为 PDF 内部位图格式,并且在提取时最好将其转换回 PNG。

此外,类中没有简单getImage方法的原因PdfStampAnnotation是,印章的外观可以像普通页面的内容一样构造,它可能包含文本,可能包含矢量图形,可能包含位图图像,可能包含这些元素的任意混合物。因此,您可以从注释中检索到的只是它的外观。

如果您确定注释仅包含图像(或者您至少对图像以外的任何内容都不感兴趣),您可以使用 iText 解析器框架提取该图像,例如:

Map<byte[], String> extractAnnotationImages(PdfStream xObject) {
    final Map<byte[], String> result = new HashMap<>();
    IEventListener renderListener = new IEventListener() {
        @Override
        public Set<EventType> getSupportedEvents() {
            return Collections.singleton(RENDER_IMAGE);
        }

        @Override
        public void eventOccurred(IEventData data, EventType type) {
            if (data instanceof ImageRenderInfo) {
                ImageRenderInfo imageRenderInfo = (ImageRenderInfo) data;
                byte[] bytes = imageRenderInfo.getImage().getImageBytes();
                String extension = imageRenderInfo.getImage().identifyImageFileExtension();
                result.put(bytes, extension);
            }
        }
    };

    PdfCanvasProcessor processor = new PdfCanvasProcessor(renderListener, Collections.emptyMap());
    processor.processContent(xObject.getBytes(), new PdfResources(xObject.getAsDictionary(PdfName.Resources)));

    return result;
}

ExtractAnnotationImage方法)

它返回从图像字节数组到要使用的文件扩展名的映射。

我在这个辅助方法中使用了它:

void saveAnnotationImages(PdfDocument pdfDocument, String prefix) throws IOException {
    for (int pageNumber = 1; pageNumber <= pdfDocument.getNumberOfPages(); pageNumber++) {
        PdfPage page = pdfDocument.getPage(pageNumber);
        int index = 0;
        for (PdfAnnotation annotation : page.getAnnotations()) {
            PdfDictionary normal = annotation.getAppearanceObject(PdfName.N);
            if (normal instanceof PdfStream) {
                Map<byte[], String> images = extractAnnotationImages((PdfStream)normal);
                for (Map.Entry<byte[], String> entry : images.entrySet()) {
                    Files.write(new File(String.format("%s-%s-%s.%s", prefix, pageNumber, index++, entry.getValue())).toPath(), entry.getKey());
                }
            }
        }
    }
}

ExtractAnnotationImage辅助方法)

AddStamp从您引用的 iText 示例的输出中的注释中提取所有图像并获得一张图像:

add_stamp-1-0.png

顺便说一句,你会发现这里缺少透明度。PDF 中的透明度是通过第二张图像(蒙版图像)建模的,它有效地代表了类似于 Alpha 通道的东西。可以从ImageRenderInfo.getImage()对象中检索此掩码。


推荐阅读