替换 PDF 中的特定文档

Posted

技术标签:

【中文标题】替换 PDF 中的特定文档【英文标题】:Replace Specific Document in PDF 【发布时间】:2016-01-12 16:11:37 【问题描述】:

包括:

using Ghostscript.NET;
using Ghostscript.NET.Processor;
using Ghostscript.NET.Rasterizer;

现在,我正在使用 Ghostscript.Net 将几个单独的 PDF 合并到一个文档中:

/// <summary>
/// Ghostscripts the file specified in parameter 1 as a PDF to the file specified in parameter 2
/// </summary>
/// <param name="fileNames">String[]. Array of Full Paths to a file to convert to a single PDF</param>
/// <param name="outputPath">String. Full Path to where Ghostscript will write the PDF</param>
public static void GhostscriptNetJoin(String[] fileNames, String outputPath)

    var sb = new StringBuilder();
    foreach (var fileName in fileNames)
    
        var source = (fileName.IndexOf(' ') == -1) ? fileName : String.Format("\"0\"", fileName);
        sb.Append(source + " ");
    
    var output_file = (outputPath.IndexOf(' ') == -1) ? outputPath : String.Format("\"0\"", outputPath);
    var gsArgs = new List<String>();
    gsArgs.Add("-empty"); // first argument is ignored. REF: http://***.com/q/25202577/153923
    gsArgs.Add("-dBATCH");
    gsArgs.Add("-q");
    gsArgs.Add("-dNOPAUSE");
    gsArgs.Add("-dNOPROMPT");
    gsArgs.Add("-sDEVICE=pdfwrite");
    gsArgs.Add("-dPDFSETTINGS=/prepress");
    gsArgs.Add(String.Format(@"-sOutputFile=0", output_file));
    gsArgs.Add(sb.ToString());
    var version = GhostscriptVersionInfo.GetLastInstalledVersion();
    using (var processor = new GhostscriptProcessor(version, false))
    
        processor.Process(gsArgs.ToArray());
    

我以后如何才能返回到 REPLACE 或 UPDATE 第 N 页?

我已经完成了一个有我计划的例程,但此时我不知道如何完成它。我可以提供arg 值还是我应该使用其他工具?

/// <summary>
/// Replace Specific Document from source PDF file
/// </summary>
/// <param name="source">String. Full path to the multi-page PDF</param>
/// <param name="documentN">String. Full path to the document to insert</param>
/// <param name="indexN">int. Page Index where the new document should be inserted</param>
public static void GhostscriptNetReplace(String source, String documentN, int indexN)

    var list = new List<String>();
    var version = GhostscriptVersionInfo.GetLastInstalledVersion();
    using (var processor = new GhostscriptProcessor(version, false))
    
        var gsArgs = new List<String>();
        // what arguments are needed?
        throw new NotImplementedException("I don't know how to code for this yet.");
        processor.Process(gsArgs.ToArray());
    
    list.RemoveAt(indexN);
    list.Insert(indexN, documentN);
    var sb = new StringBuilder();
    foreach (var fileName in list)
    
        var fmtSource = (fileName.IndexOf(' ') == -1) ? fileName : String.Format("\"0\"", fileName);
        sb.Append(fmtSource + " ");
    
    var output_file = (source.IndexOf(' ') == -1) ? source : String.Format("\"0\"", source);
    using (var processor = new GhostscriptProcessor(version, false))
    
        var gsArgs = new List<String>();
        gsArgs.Add("-empty"); // first argument is ignored. REF: http://***.com/q/25202577/153923
        gsArgs.Add("-dBATCH");
        gsArgs.Add("-q");
        gsArgs.Add("-dNOPAUSE");
        gsArgs.Add("-dNOPROMPT");
        gsArgs.Add("-sDEVICE=pdfwrite");
        gsArgs.Add("-dPDFSETTINGS=/prepress");
        gsArgs.Add(String.Format(@"-sOutputFile=0", output_file));
        gsArgs.Add(sb.ToString());
        processor.Process(gsArgs.ToArray());
    

【问题讨论】:

这显然适用于 Windows。 How to use Ghostscript 似乎没有说明如何从 PDF 中提取文件……或者如果使用 Ghostscript 也可以。 这个问题的简单答案是,你不能,至少不使用 Ghostscript。在使用 pdfwrite 设备时,您需要始终牢记的一件事是它确实以任何方式修改 PDF 文件。它所做的是根据其输入创建全新的 PDF 文件。如果您不断循环使用输出作为输入,那么您将反复面临信息或质量损失的风险。另外,有什么办法可以让我们拥有一个 Ghostscript.NET 论坛?这些不是真正的 Ghostscript 问题 @KenS:做不到?大鼠。感谢您的信息。 我的意思是“不能通过更改 PDF 文件来完成”,有很多方法可以用 Ghostscript 实现您想要的,但它们都涉及多次转换,这可能很糟糕(而且很慢)。您可以使用 %d 语法将原始 PDF '突发'成 N 个单页 PDF,然后按所需顺序将它们全部作为输入提供,以创建新的多页 PDF。 【参考方案1】:

你也许可以做这样的事情(现在无法测试代码,但它的原理是基于 Ghostscript.NET repo):

var prcPath = "PATH"; //a path to store the temporary files
var pageCount = GetPDFPageCount(source);
var list = SplitPDFatIndex(source, prcPath, indexN);

private static List<String> SplitPDFatIndex(String pathToFile, String tempPath, int index)

    var outList = new List<String>();
    outList.Add(SlicePDFatIndex(pathToFile, tempPath, index, true);
    outlist.Add(null); // Alternatively modify method below to permit pulling page N
    outList.Add(SlicePDFatIndex(pathToFile, tempPath, index, false);

    return outList;


private static String SlicePDFatIndex(String pathToFile, String tempPath, int index, bool lessThanIndex)

    using (var processor = new GhostscriptProcessor(version, false))
    
        var pageFrom = 1;
        var pageTo = index - 1;
        var name = tempPath + "temp_left.pdf";

        if (!lessThanIndex)
        
            pageFrom = index + 1;
            pageTo = pageCount;
            name = tempPath + "temp_right.pdf";
        

        var gsArgs = new List<String>();
        gsArgs.Add("-empty");
        gsArgs.Add("-dBATCH");
        gsArgs.Add("-q");
        gsArgs.Add("-dNOPAUSE");
        gsArgs.Add("-dNOPROMPT");
        gsArgs.Add("-sDEVICE=pdfwrite");
        gsArgs.Add("-dPDFSETTINGS=/prepress");
        gsArgs.Add(String.Format(@"-f0", pathToFile);
        gsArgs.Add("-dFirstPage=" + pageFrom.ToString());
        gsArgs.Add("-dLastPage=" + pageTo.ToString());
        gsArgs.Add(String.Format(@"-sOutputFile=0", name));
        processor.Process(@"-f0", pathToFile);

        return name;


private static int GetPDFPageCount(String pathToFile)

    var count;
    var GhostscriptViewer viewer;

    viewer = new GhostscriptViewer();
    viewer.ShowPageAfterOpen = false;
    viewer.ProgressiveUpdate = false;
    viewer.Open(source); // try (source, version, false) or (source, version, true) if for some reason it hangs up here
    count = viewer.LastPageNumber;
    viewer.Close()

    return count;

【讨论】:

【参考方案2】:

我将根据我在 baaron 的帖子中读到的内容添加一个答案:

Convert PDF to JPG / Images without using a specific C# Library

我修改了他的代码,我认为它会满足我的需求。不过,就像上面评论中发布的 KenS 一样,每次运行它都会继续降低质量。

/// <summary>
/// Replaces document at provided index with new document.
/// Use with Caution! If you continuously cycle using the output as the input,
/// then you run repeated risks of information or quality loss.
/// </summary>
/// <param name="source">String. Full File Path to Source</param>
/// <param name="documentN">String. Full File Path to new document</param>
/// <param name="indexN">int. Index where file needs to go</param>
public static void GhostscriptNetReplace(String source, String documentN, int indexN)

    var list = new List<String>();
    var version = GhostscriptVersionInfo.GetLastInstalledVersion();
    var fullPath = Path.GetFullPath(source);
    int index = -1;
    using (var rasterizer = new Ghostscript.NET.Rasterizer.GhostscriptRasterizer())
    
        rasterizer.Open(source, version, false);
        for (index = 0; index < rasterizer.PageCount; index++)
        
            if (index != indexN)
            
                var extracted = Path.Combine(fullPath, String.Format("~1_0.jpg", index));
                if (File.Exists(extracted))
                
                    File.Delete(extracted);
                
                var img = rasterizer.GetPage(300, 300, index);
                img.Save(extracted, ImageFormat.Jpeg);
                list.Add(extracted);
             else
            
                list.Add(documentN);
            
        
        if (index == indexN) // occurs if adding a page to the end
        
            list.Add(documentN);
        
    
    var output_file = (source.IndexOf(' ') == -1) ? source : String.Format("\"0\"", source);
    using (var processor = new GhostscriptProcessor(version, false))
    
        var gsArgs = new List<String>();
        gsArgs.Add("-empty"); // first argument is ignored. REF: https://***.com/q/25202577/153923
        gsArgs.Add("-dBATCH");
        gsArgs.Add("-q");
        gsArgs.Add("-dNOPAUSE");
        gsArgs.Add("-dNOPROMPT");
        gsArgs.Add("-sDEVICE=pdfwrite");
        gsArgs.Add("-dPDFSETTINGS=/prepress");
        gsArgs.Add(String.Format(@"-sOutputFile=0", output_file));
        foreach (var fileName in list)
        
            var source = (fileName.IndexOf(' ') == -1) ? fileName : String.Format("\"0\"", fileName);
            gsArgs.Add(source);
        
        processor.Process(gsArgs.ToArray());
    
    foreach (var fileName in list) // delete the temp files
    
        File.Delete(fileName);
    

Work 决定暂时推迟这项工作,因为他们还没有准备好冒失去信息质量的风险。

然后,此代码未经测试就被放在那里。

理论上应该可以的。

如果有帮助,请告诉我。如果没有人看到,我讨厌跟进我自己的问题的答案。

【讨论】:

【参考方案3】:

来自我的related post:

您可以使用 PDF 工具包PDFtk:

例子:

pdftk A=inA.pdf B=inB.pdf cat A1-12 B3 A14-end output out1.pdf

输出包括inA.pdf 的前 12 页,然后是 inB.pdf 的第 3 页,然后是第 14 页直到 inA.pdf 的结尾。

许多 Linux 发行版都提供 PDFtk 包,您可以使用它们的包管理器下载和安装。

【讨论】:

我以前看过你的回答,阿克塞尔。我的问题是有人告诉我使用 Ghostscript。现在和我一起工作的很多年长的人都是 UNIX 人,他们希望永远继续使用他们所拥有的东西。不过,PDFtk 看起来确实很强大。

以上是关于替换 PDF 中的特定文档的主要内容,如果未能解决你的问题,请参考以下文章

word文档中的图片怎么替换成别的图片

如何全局替换PDF中的字体

使用 ghostscript 替换 PDF 中的颜色

Java 添加替换删除PDF中的图片

用 html 文档中的“易碎”nbsp 替换空格

如何通过Java代码在PDF中插入替换或删除图像?