在itextsharp中从模板创建pdf并输出为内容处置。

时间:2012-02-27 16:54:18

标签: itextsharp

我想打开一个现有的pdf,添加一些文本然后使用itext sharp作为内容处理输出。我有以下代码。它落下的地方是我想输出内存流但需要filestream来打开原始文件。

这就是我所拥有的。显然,定义PdfWriter两次是行不通的。

   public static void Create(string path)
    {
        var Response = HttpContext.Current.Response;
        Response.Clear();
        Response.ContentType = "application/pdf";
        System.IO.MemoryStream m = new System.IO.MemoryStream();
        Document document = new Document();
        PdfWriter wri = PdfWriter.GetInstance(document, new FileStream(path, FileMode.Create));
        PdfWriter.GetInstance(document, m);
        document.Open();
        document.Add(new Paragraph(DateTime.Now.ToString()));
        document.NewPage();
        document.Add(new Paragraph("Hello World"));
        document.Close();
        Response.OutputStream.Write(m.GetBuffer(), 0, m.GetBuffer().Length);
        Response.OutputStream.Flush();
        Response.OutputStream.Close();
        Response.End();
    } 

2 个答案:

答案 0 :(得分:16)

你有几个问题我会试着指导你。

首先,Document对象仅用于处理新PDF,而不是修改现有PDF。基本上Document对象是一堆包装类,它们抽象出PDF规范的底层部分,并允许您处理段落和可重排内容等更高级别的内容。这些抽象将您对“段落”的看法转变为原始命令,这些命令一次写一行,而行之间没有关系。使用现有文档时,没有安全的方法来说明如何重排文本,因此不使用这些抽象。

相反,您想要使用PdfStamper对象。使用此对象时,您有两种选择可以处理可能重叠的内容,或者将新文本写在现有内容之上,或者将文本写在其下面。实例化GetOverContent()对象的两个方法GetUnderContent()PdfStamper将返回一个PdfContentByte对象,然后您可以使用该对象编写文本。

有两种主要方式可以手动或通过ColumnText对象来编写文本。如果您已完成HTML,则可以将ColumnText对象视为使用大的固定位置单行,单列<TABLE>ColumnText的优点是您可以使用更高级别的抽象,例如Paragraph

以下是一个完整的C#2010 WinForms应用程序,该应用程序针对iTextSharp 5.1.2.0展示了上述内容。如有任何问题,请参阅代码注释。将它转换为ASP.Net应该很容易。

using System;
using System.IO;
using System.Windows.Forms;
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e) {
            string existingFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "file1.pdf");
            string newFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "file2.pdf");
            using (FileStream fs = new FileStream(existingFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
                using (Document doc = new Document(PageSize.LETTER)) {
                    using (PdfWriter writer = PdfWriter.GetInstance(doc, fs)) {
                        doc.Open();

                        doc.Add(new Paragraph("This is a test"));

                        doc.Close();
                    }
                }
            }

            //Bind a PdfReader to our first document
            PdfReader reader = new PdfReader(existingFile);
            //Create a new stream for our output file (this could be a MemoryStream, too)
            using (FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
                //Use a PdfStamper to bind our source file with our output file
                using (PdfStamper stamper = new PdfStamper(reader, fs)) {

                    //In case of conflict we want our new text to be written "on top" of any existing content
                    //Get the "Over" state for page 1
                    PdfContentByte cb = stamper.GetOverContent(1);

                    //Begin text command
                    cb.BeginText();
                    //Set the font information
                    cb.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1250, false), 16f);
                    //Position the cursor for drawing
                    cb.MoveText(50, 50);
                    //Write some text
                    cb.ShowText("This was added manually");
                    //End text command
                    cb.EndText();

                    //Create a new ColumnText object to write to
                    ColumnText ct = new ColumnText(cb);
                    //Create a single column who's lower left corner is at 100x100 and upper right is at 500x200
                    ct.SetSimpleColumn(100,100,500,200);
                    //Add a higher level object
                    ct.AddElement(new Paragraph("This was added using ColumnText"));
                    //Flush the text buffer
                    ct.Go();

                }
            }

            this.Close();
        }
    }
}

至于你关于FileStream vs MemoryStream的第二个问题,如果你看几乎所有的方法签名(据我所知,实际上是所有)方法iTextSharp你会发现它们都是一个Stream对象而不只是一个FileStream对象。每当你看到这个,甚至在iTextSharp之外,这意味着你可以传入包含Stream对象的MemoryStream的任何子类,其他一切都保持不变。

以下代码是上述代码的略微修改版本。我删除了大部分评论以缩短评论。主要变化是我们使用的是MemoryStream而不是FileStream。此外,当我们在需要在访问原始二进制数据之前关闭PdfStamper对象时完成PDF。 (using声明稍后会自动为我们执行此操作,但它也会关闭流,因此我们需要在此处手动执行此操作。)

另一件事,永远不要使用GetBuffer()的{​​{1}}方法。这听起来像你想要的(我也错误地使用了它),但你想要使用MemoryStreamToArray()包括未初始化的字节,通常会生成损坏的PDF。此外,我没有写入HTTP Response流,而是先将字节保存到数组中。从调试角度来看,这允许我完成所有iTextSharp和GetBuffer()代码,并确保它是正确的,然后对原始字节数组执行任何操作。在我的情况下,我没有方便的网络服务器,所以我将它们写入磁盘,但你可以轻松地调用System.IO

Response.BinaryWrite(bytes)

答案 1 :(得分:3)

问题标题的第二部分说:

  

“输出内容处理”

如果这是你真正想要的,你可以这样做:

Response.AddHeader("Content-Disposition", "attachment; filename=DESIRED-FILENAME.pdf");

由于MemoryStream可用,因此无需使用Response.OutputStream。您的示例代码正在调用NewPage()尝试将文本添加到PDF的现有页面,因此这是您提出要求的一种方式:< / p>

Response.ContentType = "application/pdf";    
Response.AddHeader("Content-Disposition", "attachment; filename=itextTest.pdf");
PdfReader reader = new PdfReader(readerPath);
// store the extra text on the last (new) page
ColumnText ct = new ColumnText(null);
ct.AddElement(new Paragraph("Text on a new page"));
int numberOfPages = reader.NumberOfPages;
int newPage = numberOfPages + 1;
// get all pages from PDF "template" so we can copy them below
reader.SelectPages(string.Format("1-{0}", numberOfPages));
float marginOffset = 36f;
/*
* we use the selected pages above with a PdfStamper to copy the original.
* and no we don't need a MemoryStream...
*/
using (PdfStamper stamper = new PdfStamper(reader, Response.OutputStream)) {
// use the same page size as the __last__ template page    
  Rectangle rectangle = reader.GetPageSize(numberOfPages);
// add a new __blank__ page      
  stamper.InsertPage(newPage, rectangle);
// allows us to write content to the (new/added) page
  ct.Canvas = stamper.GetOverContent(newPage);
// add text at an __absolute__ position      
  ct.SetSimpleColumn(
    marginOffset, marginOffset, 
    rectangle.Right - marginOffset, rectangle.Top - marginOffset
  );
  ct.Go();
}

我认为您已经发现Document / PdfWriter组合在这种情况下不起作用:)这是创建 PDF的标准方法文档。