java - 如何检索 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 真的很陌生,经过数小时的研究,我被困在这一点上......
解决方案
首先,您将无法取回原始图像。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;
}
它返回从图像字节数组到要使用的文件扩展名的映射。
我在这个辅助方法中使用了它:
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 示例的输出中的注释中提取所有图像并获得一张图像:
顺便说一句,你会发现这里缺少透明度。PDF 中的透明度是通过第二张图像(蒙版图像)建模的,它有效地代表了类似于 Alpha 通道的东西。可以从ImageRenderInfo.getImage()
对象中检索此掩码。
推荐阅读
- sql-server - 同一个站号(参考号),如何对比2小时前的记录
- ssas - SSAS 如何填充 MDSCHEMA_LEVELS 行集中的 LEVEL_TYPE 信息
- typescript - NestJs 是否支持 WebSocket 网关的速率限制?
- ios - 使用 Interface Builder 创建了 UIButton。现在我想使用约束更改该按钮的位置和大小
- dart - 如何使用相机应用程序流式传输具有正确像素数的图像?
- css - 如何使链接的活动状态(在 CSS 中)工作?
- java - 查找具有名字和姓氏的演员使用 Java 8 Streams、map、filter、reduce 工作过的电影
- spring - @Transactional 具有多个事务管理器和多个数据库
- ssis - 如何在 DataFlow 任务中访问 ScriptComponent 中的变量并分配给局部变量
- android - Firebase 存储视频解码器