如何使用 iTextSharp 将 XMP 元数据添加到现有 PDF 的每一页
How do I add XMP metadata to each page of an existing PDF using iTextSharp
到目前为止,所有示例似乎都涉及在创建新文档时添加元数据。我想使用现有的 PDF 并使用 stamper
将 GUID 添加到每个页面的 XMP
XMP 在 PDF 上下文中最常见的用法是为从 PDF 的根字典(也称为目录)引用的整个文档添加 XMP 流。
但是,如果您查阅 PDF 规范,您会注意到 XMP 可以在 PDF 中的许多其他对象的上下文中使用,页面级别就是其中之一。如果查看规范,您会发现 /Metadata
是页面字典中的可选键。它需要对 XMP 流的引用。
如果您要使用 iText 从头开始创建 PDF 文档,您将找不到添加此元数据的特定方法,但您可以使用 [=19= 中提供的通用 addPageDictEntry()
].您可以将 PdfName.METADATA
作为键传递,并将对已添加到 PdfWriter
的流的引用作为值传递。
您的问题不是关于从头开始创建 PDF,而是关于修改现有 PDF。在这种情况下,您还需要页面字典。这些词典很容易获得:
PdfReader reader = new PdfReader(src);
int n = reader.getNumberOfPages();
PdfDictionary page;
for (int p = 1; p <= n; p++) {
page = reader.getPageN(p);
// do stuff with the page dictionary
}
此片段取自 Rotate90Degrees
示例。在该示例中,我们查看 /Rotate
条目,它是一个数字:
PdfNumber rotate = page.getAsNumber(PdfName.ROTATE);
您需要查找 /Metadata
条目,它是一个流:
PRStream stream = (PRStream) page.getAsStream(PdfName.METADATA);
也许这个流是 null
,在这种情况下,您需要添加一个 /Metadata
条目,如 AddXmpToPage 示例所示:
// We create some XMP bytes
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XmpWriter xmp = new XmpWriter(baos, new PdfDictionary());
xmp.close();
// We add the XMP bytes to the writer
PdfIndirectObject ref = stamper.getWriter().addToBody(new PdfStream(baos.toByteArray()));
// We add a reference to the XMP bytes to the page dictionary
page.put(PdfName.METADATA, ref.getIndirectReference());
如果有 XMP 流,您想保留它并向其中添加一些内容。
这是您获取 XMP 字节的方式:
byte[] xmpBytes = PdfReader.getStreamBytes(stream);
您对这些字节施展了 XML 魔法,产生了一个名为 newXmpBytes 的新 byte[]
。您可以像这样用这些新字节替换原始字节:
stream.setData(newXmpBytes);
所有这些操作都是在驻留在 PdfReader
对象中的现有文件上完成的。您现在必须坚持这样的更改:
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
stamper.close();
reader.close();
到目前为止,所有示例似乎都涉及在创建新文档时添加元数据。我想使用现有的 PDF 并使用 stamper
将 GUID 添加到每个页面的 XMPXMP 在 PDF 上下文中最常见的用法是为从 PDF 的根字典(也称为目录)引用的整个文档添加 XMP 流。
但是,如果您查阅 PDF 规范,您会注意到 XMP 可以在 PDF 中的许多其他对象的上下文中使用,页面级别就是其中之一。如果查看规范,您会发现 /Metadata
是页面字典中的可选键。它需要对 XMP 流的引用。
如果您要使用 iText 从头开始创建 PDF 文档,您将找不到添加此元数据的特定方法,但您可以使用 [=19= 中提供的通用 addPageDictEntry()
].您可以将 PdfName.METADATA
作为键传递,并将对已添加到 PdfWriter
的流的引用作为值传递。
您的问题不是关于从头开始创建 PDF,而是关于修改现有 PDF。在这种情况下,您还需要页面字典。这些词典很容易获得:
PdfReader reader = new PdfReader(src);
int n = reader.getNumberOfPages();
PdfDictionary page;
for (int p = 1; p <= n; p++) {
page = reader.getPageN(p);
// do stuff with the page dictionary
}
此片段取自 Rotate90Degrees
示例。在该示例中,我们查看 /Rotate
条目,它是一个数字:
PdfNumber rotate = page.getAsNumber(PdfName.ROTATE);
您需要查找 /Metadata
条目,它是一个流:
PRStream stream = (PRStream) page.getAsStream(PdfName.METADATA);
也许这个流是 null
,在这种情况下,您需要添加一个 /Metadata
条目,如 AddXmpToPage 示例所示:
// We create some XMP bytes
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XmpWriter xmp = new XmpWriter(baos, new PdfDictionary());
xmp.close();
// We add the XMP bytes to the writer
PdfIndirectObject ref = stamper.getWriter().addToBody(new PdfStream(baos.toByteArray()));
// We add a reference to the XMP bytes to the page dictionary
page.put(PdfName.METADATA, ref.getIndirectReference());
如果有 XMP 流,您想保留它并向其中添加一些内容。
这是您获取 XMP 字节的方式:
byte[] xmpBytes = PdfReader.getStreamBytes(stream);
您对这些字节施展了 XML 魔法,产生了一个名为 newXmpBytes 的新 byte[]
。您可以像这样用这些新字节替换原始字节:
stream.setData(newXmpBytes);
所有这些操作都是在驻留在 PdfReader
对象中的现有文件上完成的。您现在必须坚持这样的更改:
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
stamper.close();
reader.close();