在itextsharp中从模板创建pdf并输出为内容处置。 [英] creating a pdf from a template in itextsharp and outputting as content disposition.

查看:79
本文介绍了在itextsharp中从模板创建pdf并输出为内容处置。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I would like to open an existing pdf, add some text and then output as content disposition using itext sharp. I have the following code. Where it falls down it is that i want to output as memory stream but need to filestream to open the original file.

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

Here's what i have. Obviously defining PdfWriter twice won't work.

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


推荐答案

你有一对夫妇我将试图引导您解决的问题。

You've got a couple of problems that I'll try to walk you through.

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

First, the Document object is only for working with new PDFs, not modifying existing ones. Basically the Document object is a bunch of wrapper classes that abstract away the underlying parts of the PDF spec and allow you to work with higher level things like paragraphs and reflowable content. These abstractions turn what you think of "paragraphs" into raw commands that write the paragraph one line at a time with no relationship between lines. When working with an existing document there's no safe way to say how to reflow text so these abstractions aren't used.

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

Instead you want to use the PdfStamper object. When working with this object you have two choices for how to work with potentially overlapping content, either your new text gets written on top of existing content or your text gets written below it. The two methods GetOverContent() or GetUnderContent() of an instantiated PdfStamper object will return a PdfContentByte object that you can then write text with.

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

There's two main ways to write text, either manually or through a ColumnText object. If you've done HTML you can think of the ColumnText object as using a big fixed-position single row, single column <TABLE>. The advantage of the ColumnText is that you can use the higher level abstractions such as Paragraph.

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

Below is a full working C# 2010 WinForms app targeting iTextSharp 5.1.2.0 that show off the above. See the code comments for any questions. It should be pretty easy to convert this to 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 ,如果你看几乎所有的方法签名(实际上是 all 据我所知)iTextSharp中的方法你会看到他们都采用 Stream 对象,而不仅仅是 FileStream 对象。每当你看到这个,甚至在iTextSharp之外,这意味着你可以传入 Stream 的任何子类,其中包括 MemoryStream 对象,其他一切都保持不变。

As to your second problem about the FileStream vs MemoryStream, if you look at the method signature for almost every (actually all as far as I know) method within iTextSharp you'll see that they all take a Stream object and not just a FileStream object. Any time you see this, even outside of iTextSharp, this means that you can pass in any subclass of Stream which includes the MemoryStream object, everything else stays the same.

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

The code below is a slightly modified version of the one above. I've removed most of the comments to make it shorter. The main change is that we're using a MemoryStream instead of a FileStream. Also, when we're done with the PDF when need to close the PdfStamper object before accessing the raw binary data. (The using statment will do this for us automatically later but it also closes the stream so we need to manually do it here.)

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

One other thing, never, ever use the GetBuffer() method of the MemoryStream. It sounds like what you want (and I have mistakenly used it, too) but instead you want to use ToArray(). GetBuffer() includes uninitialized bytes which usually produces corrupt PDFs. Also, instead of writing to the HTTP Response stream I'm saving the bytes to array first. From a debugging perspective this allows me to finish all of my iTextSharp and System.IO code and make sure that it is correct, then do whatever I want with the raw byte array. In my case I don't have a web server handy so I'm writing them to disk but you could just as easily call Response.BinaryWrite(bytes)

string existingFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "file1.pdf");
string newFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "file2.pdf");
PdfReader reader = new PdfReader(existingFile);
byte[] bytes;
using(MemoryStream ms = new MemoryStream()){
    using (PdfStamper stamper = new PdfStamper(reader, ms)) {
        PdfContentByte cb = stamper.GetOverContent(1);
        ColumnText ct = new ColumnText(cb);
        ct.SetSimpleColumn(100,100,500,200);
        ct.AddElement(new Paragraph("This was added using ColumnText"));
        ct.Go();

        //Flush the PdfStamper's buffer
        stamper.Close();
        //Get the raw bytes of the PDF
        bytes = ms.ToArray();
    }
}

//Do whatever you want with the bytes
//Below I'm writing them to disk but you could also write them to the output buffer, too
using (FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
    fs.Write(bytes, 0, bytes.Length);
}

这篇关于在itextsharp中从模板创建pdf并输出为内容处置。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆