【问题标题】:replace string in PDF document (ITextSharp or PdfSharp)替换 PDF 文档中的字符串(ITextSharp 或 PdfSharp)
【发布时间】:2015-08-10 23:32:13
【问题描述】:

我们使用具有功能的非管理 DLL 来替换 PDF 文档中的文本 (http://www.debenu.com/docs/pdf_library_reference/ReplaceTag.php)。 我们正在尝试转向托管解决方案(ITextSharp 或 PdfSharp)。 我知道以前有人问过这个问题,答案是“你不应该这样做”或“PDF 不容易支持”。 然而,有一个适合我们的解决方案,我们只需要将它转换为 C#。 任何想法我应该如何处理它?

【问题讨论】:

    标签: pdf itextsharp pdfsharp


    【解决方案1】:

    根据您的library reference link,您使用Debenu PDFLibrary 函数ReplaceTag。根据this Debenu knowledge base article

    ReplaceTag 函数只是替换页面内容流中的文本,因此对于大多数文档来说它不会有任何效果。对于一些简单的文档,它可能能够替换内容,但这实际上取决于 PDF 的构建方式。本质上和做的一样:

    DPL.CombineContentStreams();
    string content = DPL.GetContentStreamToString();
    DPL.SetPageContentFromString(content.Replace("Moby", "Mary"));
    

    这对于任何通用 PDF 库都应该是可能的,绝对是 iText(Sharp):

    void VerySimpleReplaceText(string OrigFile, string ResultFile, string origText, string replaceText)
    {
        using (PdfReader reader = new PdfReader(OrigFile))
        {
            byte[] contentBytes = reader.GetPageContent(1);
            string contentString = PdfEncodings.ConvertToString(contentBytes, PdfObject.TEXT_PDFDOCENCODING);
            contentString = contentString.Replace(origText, replaceText);
            reader.SetPageContent(1, PdfEncodings.ConvertToBytes(contentString, PdfObject.TEXT_PDFDOCENCODING));
    
            new PdfStamper(reader, new FileStream(ResultFile, FileMode.Create, FileAccess.Write)).Close();
        }
    }
    

    警告:就像在 Debenu 函数的情况下一样,对于大多数文档,此代码不会产生任何影响,甚至会具有破坏性。对于一些简单的文档,它可能能够替换内容,但这实际上取决于 PDF 的构建方式。

    顺便说一句,Debenu knowledge base article 继续:

    如果您使用 Debenu Quick PDF Library 和标准字体创建了 PDF,则 ReplaceTag 功能应该可以工作 - 但是,对于使用执行子集字体甚至字距调整(单词将被拆分)的工具创建的 PDF,然后搜索文本可能不会以简单的格式出现在内容中。

    因此,简而言之,ReplaceTag 功能仅适用于某些有限的场景,并不是您可以依赖的用于搜索和替换文本的功能。

    因此,如果在您迁移到托管解决方案期间您还更改了源文档的创建方式,那么 Debenu PDFLibrary 函数ReplaceTag 和上面的代码都可能无法更改内容随心所欲。

    【讨论】:

    • 伟大的深潜!我真的很好奇他们到底在做什么
    【解决方案2】:

    对于 pdfsharp 用户来说,这里有一个有点可用的功能,我从我的项目中复制了它,它使用了一种实用方法,该方法被其他方法使用,因此未使用结果。

    它会忽略由 Kerning 创建的空格,因此可能会根据源材料混淆结果(同一空格中的所有字符)

        public static void ReplaceTextInPdfPage(PdfPage contentPage, string source, string target)
        {
            ModifyPdfContentStreams(contentPage, stream =>
            {
                if (!stream.TryUnfilter())
                    return false;
                var search = string.Join("\\s*", source.Select(c => c.ToString()));
                var stringStream = Encoding.Default.GetString(stream.Value, 0, stream.Length);
                if (!Regex.IsMatch(stringStream, search))
                    return false;
                stringStream = Regex.Replace(stringStream, search, target);
                stream.Value = Encoding.Default.GetBytes(stringStream);
                stream.Zip();
                return false;
            });
        }
    
    
        public static void ModifyPdfContentStreams(PdfPage contentPage,Func<PdfDictionary.PdfStream, bool> Modification)
        {
    
            for (var i = 0; i < contentPage.Contents.Elements.Count; i++)
                if (Modification(contentPage.Contents.Elements.GetDictionary(i).Stream))
                    return;
            var resources = contentPage.Elements?.GetDictionary("/Resources");
            var xObjects = resources?.Elements.GetDictionary("/XObject");
            if (xObjects == null)
                return;
            foreach (var item in xObjects.Elements.Values.OfType<PdfReference>())
            {
                var stream = (item.Value as PdfDictionary)?.Stream;
                if (stream != null)
                    if (Modification(stream))
                        return;
            }
        }
    

    【讨论】:

    • 适用于 Debenu 知识库中原始ReplaceTag 方法的模拟警告:"因此,简而言之,ReplaceTag 功能仅适用于某些有限的场景,不是功能您可以依靠它来搜索和替换文本。”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-14
    • 1970-01-01
    相关资源
    最近更新 更多