【问题标题】:Drawing on PDF using ITextSharp, without creating a new PDF使用 ITextSharp 在 PDF 上绘图,无需创建新的 PDF
【发布时间】:2015-05-27 08:48:56
【问题描述】:

我尝试使用 ITextSharp 在现有 PDF 上绘制简单的形状(矩形、圆形......),而无需创建新的 PDF。我找到了一个谈论这个问题的帖子(itextsharp modify existing pdf (no new source pdf) and add watermark),我想知道是否有人可以告诉我更多关于它的信息。

我的目标是通过在其上添加一个圆圈来修改 pdf,当前的解决方案涉及创建一个新的 PDF (Itextsharp)。是否可以在 PDF 上添加一个圆圈而不创建一个新圆圈? 谢谢。

J.

【问题讨论】:

  • 您应该在您的问题因为“过于宽泛”而被关闭之前指定您的确切问题。
  • 我想通过在其上添加一个圆圈来修改 pdf,当前的解决方案涉及创建一个新的 PDF (Itextsharp)。是否可以在不创建新圆的情况下在 PDF 上添加圆?
  • 编辑您的问题以澄清它,最好还添加您尝试过的几行代码..!
  • 您的问题与How to update a PDF without creating a new PDF? 重复您在问一些违反基本逻辑的问题:您想写入现有文件并同时读取该现有文件。但是,一旦您写入文件,就无法再读取它。适用于 Word 文档的内容也适用于 PDF。
  • 非常感谢布鲁诺的解释。

标签: c# pdf itextsharp


【解决方案1】:

您不能同时读取和写入文件。想想 Word 的工作原理:您无法打开 Word 文档并直接对其进行写入。 Word 总是创建一个临时文件,将更改写入其中,然后用它替换原始文件,然后丢弃临时文件。

你也可以这样做:

  • PdfReader读取原文件,
  • PdfStamper 创建一个临时文件,完成后,
  • 用临时文件替换原始文件。

或者:

  • 将原始文件读入byte[]
  • 用这个byte[]创建PdfReader,然后
  • 使用PdfStamper的原始文件路径。

第二个选项更危险,因为如果您在PdfStamper 中执行导致异常的操作,您将丢失原始文件。

至于使用PdfStamper 添加内容,请查看免费电子书The Best iText Questions on StackOverflow 中标题为“操作现有PDF”的部分。您会发现以下问题:

所有这些示例都通过像这样创建 PdfContentByte 实例来添加内容:

PdfContentByte canvas = stamper.getOverContent(pagenumber);

在页码为pagenumber的页面上画圈时需要用到这个canvas。执行此操作时使用正确的坐标很重要。这在这里解释:How to position text relative to page using iText?

更新:

Json 在 cmets 中发布了以下代码:

string oldFile = @"C:\Users\ae40394\Desktop\hello.pdf";
string newFile = @"C:\Users\ae40394\Desktop\NEW.pdf";
// creating a reader with the original PDF
PdfReader reader = new PdfReader(oldFile);
Rectangle rect = reader.GetPageSize(1);
FileStream fs = new FileStream(newFile,FileMode.Create);
using (PdfStamper stamper = new PdfStamper(reader, fs)) {
    // modify the pdf content
    PdfContentByte cb = stamper.GetOverContent(1);
    cb.SetColorStroke(iTextSharp.text.BaseColor.GREEN);
    cb.SetLineWidth(5f);
    cb.Circle(rect.GetLeft() + 30, rect.GetBottom() + 30 ,20f);
    cb.Stroke();
}    
reader.Close();
File.Replace(@"C:\Users\ae40394\Desktop\NEW.pdf", @"C:\Users\ae40394\Desktop\hello.pdf", @"C:\Users\ae40394\Desktop\hello.pdf.bac"); 

我稍微修改了代码,因为:

  • 不需要Document 对象,
  • stamper 关闭时 using 关闭,
  • stamper 关闭时,FileStream 也关闭
  • 圆的坐标是硬编码的。我使用页面大小来确保它们是相对于坐标系的原点制作的,但可以肯定的是,您可能还想检查是否有裁剪框。

【讨论】:

  • 感谢您的快速回复,我仍然需要一些解释,要在 pdfStamper 中添加一个圆圈,我需要一个“PdfContentByte”和一个“PdfWriter”吗?另外,我看不清楚如何用临时文件替换原始文件:/,再次感谢!
  • 不,您不需要PdfWriter。 @shajeer 提供的答案是完全错误的。 PdfStamper 有一个 getOverContent() 方法。有很多可用的例子。我会用一些例子来更新我的答案。
  • 添加到 cmets 的代码很难阅读。我会将您的代码复制/粘贴到我的答案中。乍一看,您的代码看起来不错。
  • 谢谢@BrunoLowagie!我不明白的是,我们仍然有这个解决方案的两个文件:/
  • 如果您将旧的替换为新的,则不会。我忘了那行了。
【解决方案2】:

您可以同时读取和写入文件。

这是一个例子:

private void button4_Click(object sender, EventArgs e) 
{ 
    using (PdfReader pdfReader = new PdfReader(new FileStream(pdfInput, FileMode.Open, FileAccess.Read, FileShare.Read))) 
    { 
        using (PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(pdfInput, FileMode.Open, FileAccess.Write, FileShare.None))) 
        { 
            PdfContentByte canvas = pdfStamper.GetUnderContent(1); 
            canvas.SetColorFill(BaseColor.YELLOW); 
            canvas.Rectangle(36, 786, 66, 16); 
            canvas.Fill(); 
        } 
    } 
    // PDF Datei im Anschluss anzeigen/öffnen 
    System.Diagnostics.Process.Start(pdfInput); 
} 

【讨论】:

  • 通过使用Stream 而不是文件名作为PdfReader 构造函数参数,您可以有效地使iText 在PdfReader 构造之前将流读入字节数组。因此,您的代码本质上是@Bruno 答案中第二个选项的实现:将原始文件读入byte[],使用此byte[] 创建PdfReader,并将原始文件的路径用于@ 987654328@.
  • 一个更正,不过:您使用FileMode.Open 作为PdfWriter 构造函数的FileStream 参数。这是一个坏主意,因为这会导致您写入现有文件,并且如果新文件比原始文件短,则旧文件的最后部分会保留下来,您实际上会得到损坏的 PDF。您应该改用FileMode.CreateFileMode.Truncate
  • 谢谢!我是初学者,对不起:D
【解决方案3】:
string oldFile = @"C:\...6166-21.pdf";
        string newFile = @"C:\...NEW.pdf";

        // open the reader
        PdfReader reader = new PdfReader(oldFile);
        Rectangle size = reader.GetPageSizeWithRotation(1);
        Document document = new Document(size);

        FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.Write);
        PdfWriter writer = PdfWriter.GetInstance(document, fs);
        document.Open();

        // the pdf content
        PdfContentByte cb = writer.DirectContent;

        cb.SetColorStroke(iTextSharp.text.BaseColor.GREEN);
        cb.Circle(150f, 150f, 50f);
        cb.Stroke();

        // create the new page and add it to the pdf
        PdfImportedPage page = writer.GetImportedPage(reader, 1);
        cb.AddTemplate(page, 0, 0);

        // close the streams and voilá the file should be changed :)
        document.Close();
        fs.Close();
        writer.Close();
        reader.Close();

【讨论】:

  • 这个答案不正确。假设原始文件包含注释、表单、书签……然后使用DocumentPdfWriter丢弃所有这些内容!如果您想在文档上标记新内容,你应该使用PdfStamper!另外:这不能回答问题。问题问我怎样才能避免创建新文件?您创建一个以 NEW.pdf 结尾的文件,这是 OP 试图避免的!
  • 感谢您的回复 shajeer,但该解决方案创建了一个名为“New”的新 PDF,我想做的是在原始文件的基础上进行绘制。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
  • 2012-07-03
  • 2018-12-27
  • 2015-01-01
  • 2011-08-29
相关资源
最近更新 更多