【问题标题】:iTextSharp replace image with another PDFiTextSharp 用另一个 PDF 替换图像
【发布时间】:2021-06-23 12:33:04
【问题描述】:

我有一个包含一些图像的 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 损坏。

【问题讨论】:

    标签: c# itext itext7


    【解决方案1】:

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

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

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

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

    所以我们会感觉一切正常,但视觉效果仍然很差。问题在于,对于普通光栅图像和矢量 XObject(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));
    }
    

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

    【讨论】:

    • 确实,现在只缺少adjustXObjectSize 实现:)。而且我认为当您将纵向页面放入横向图像区域时,结果页面看起来会比预览时更受挤压......(或者我可能高估了它的效果......)
    • @mkl 多么疏忽,谢谢!我已经添加了:)
    • 图像确实有点挤压,但我可以想象 PDF 或多或少为此做好了准备,因为占位符和 PDF 具有 1:1 匹配:)
    • 根据具体的用例,使用transform.Scale(1 / pageXObject.GetWidth(), 1 / pageXObject.GetHeight()) 可能会更好。在答案中的示例中,这将更加挤压,但如果图像和页面具有相同的纵横比,它将改善外观。
    • 结果确实被挤压了。但是,使用@mkl 提供的公式,结果就好了。谢谢。
    猜你喜欢
    • 2013-06-29
    • 2011-05-17
    • 2022-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多