iTextSharp 用另一个 PDF 替换图像

iTextSharp replace image with another PDF

我有一个包含一些图像的 PDF 文件,我想将其替换为其他 PDF。代码通过 pdf 并获取图像引用:

PdfDocument pdf = new PdfDocument(new PdfReader(args[0]), new PdfWriter(args[1]));
for(int i=1; i<=pdf.GetNumberOfPages(); ++i)
{
    PdfDictionary pageDict  = pdf.GetPage(i).GetPdfObject();
    PdfDictionary resources = pageDict.GetAsDictionary(PdfName.Resources);
    PdfDictionary xObjects  = resources.GetAsDictionary(PdfName.XObject);

    foreach (PdfName imgRef in xObjects.KeySet())
    {
        // image reference
    }
}

对于我所有的图像,我都有一个相应的 PDF,我想用它来替换图像。我尝试的是 Put 另一个 PDF(始终是单页)作为对象:

PdfDocument other = new PdfDocument(new PdfReader("replacement.pdf"));
xObjects.Put(imgRef, other.GetFirstPage().GetPdfObject().Clone());

但是在关闭 PdfDocument 时抛出异常:

iText.Kernel.PdfException: 'Pdf indirect object belongs to other PDF document. Copy object to current pdf document.'

如何实现用另一个 PDF(的内容)替换图像?


更新

我还尝试了一些其他方法,这些方法可能会改善结果。为了克服之前的错误信息,我通过以下方式将页面复制到原始 pdf:

var page = other.GetFirstPage().CopyTo(pdf);

但是,替换 xObject 不起作用:

xObjects.Put(imgRef, page.GetPdfObject());

导致 PDF 损坏。

要将原始页面复制到另一个文档中以用作图像替换,您可以使用 PdfPage#CopyAsFormXObject

所以假设我们有这个 PDF 作为模板,我们想用另一个 PDF 的内容替换沙漠的图像:

我们还假设我们要用作替换的 PDF 如下所示:

问题在于,如果我们盲目地将原始图像替换为 PDF 的内容,很可能会得到这样的结果:

因此我们会感觉一切正常,但视觉效果仍然很差。问题是坐标对于普通光栅图像和矢量 XObjects(PDF 替换)的工作方式有点不同。所以我们还需要调整我们新建的XObject的变换矩阵(/Matrix键)。

因此代码可能如下所示:

PdfDocument pdf = new PdfDocument(new PdfReader(@"template.pdf"), new PdfWriter(@"out.pdf"));
for(int i=1; i<=pdf.GetNumberOfPages(); ++i) {
    PdfDictionary pageDict  = pdf.GetPage(i).GetPdfObject();
    PdfDictionary resources = pageDict.GetAsDictionary(PdfName.Resources);
    PdfDictionary xObjects  = resources.GetAsDictionary(PdfName.XObject);

    IDictionary<PdfName, PdfStream> toReplace = new Dictionary<PdfName, PdfStream>();
    
    foreach (PdfName imgRef in xObjects.KeySet()) {
        PdfStream previousXobject = xObjects.GetAsStream(imgRef);
        PdfDocument imageReplacementDoc =
            new PdfDocument(new PdfReader(@"insert.pdf"));
        PdfXObject imageReplacement = imageReplacementDoc.GetPage(1).CopyAsFormXObject(pdf);
        toReplace[imgRef] = imageReplacement.GetPdfObject();
        adjustXObjectSize(imageReplacement);
        imageReplacementDoc.Close();
    }

    foreach (var x in toReplace) {
        xObjects.Put(x.Key, x.Value);
    }
}
pdf.Close();

UPD:adjustXObjectSize的实现(感谢mkl):

private void adjustXObjectSize(PdfXObject pageXObject) {
    float scaleXobject = 1 / Math.Max(pageXObject.GetWidth(), pageXObject.GetHeight());
    AffineTransform transform = new AffineTransform();
    transform.Scale(scaleXobject, scaleXobject);
    float[] matrix = new float[6];
    transform.GetMatrix(matrix);
    pageXObject.GetPdfObject().Put(PdfName.Matrix, new PdfArray(matrix));
}

在 运行 我描述的示例的上述代码之后的视觉结果如下所示: