使用 ITextSharp 在 PDF 上绘图,而不创建新的 PDF

Drawing on PDF using ITextSharp, without creating a new PDF

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

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

J.

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();

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

你也可以这样做:

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

或:

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

第二个选项更危险,因为如果您在 PdfStamper.

中执行导致异常的操作,您将丢失原始文件

关于使用 PdfStamper 添加内容,请查看免费电子书 The Best iText Questions on Whosebug 中标题为 "Manipulating existing PDFs" 的部分。您会发现以下问题:

所有这些示例都通过创建 PdfContentByte 实例来添加内容,如下所示:

PdfContentByte canvas = stamper.getOverContent(pagenumber);

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

更新:

Json在评论中贴出以下代码:

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 object,
  • 关闭using时关闭stamper,
  • stamper 关闭时,FileStream
  • 也会关闭
  • 圆的坐标是硬编码的。我使用页面大小来确保它们是相对于坐标系的原点制作的,尽管可以肯定的是,您可能还想检查是否有裁剪框。

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

这是一个例子:

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); 
}