无法访问已关闭的文件itextsharp

时间:2017-03-21 07:04:53

标签: c# pdf itext

我正在尝试获取所有图片pdf并在该图片上方写下一些文字。我正在使用以下代码,但收到错误"无法访问已关闭的文件"

private static void InsertTextToPdf(string sourceFileName, string newFileName)
        {
            var img = new ReadPDFContent.ImagePDF.MyImageRenderListener();
            using (Stream pdfStream = new FileStream(sourceFileName, FileMode.Open))

                using (Stream newpdfStream = new FileStream(newFileName, FileMode.Create, FileAccess.ReadWrite))
                {

                    PdfReader pdfReader = new PdfReader(pdfStream);
                    PdfStamper pdfStamper = new PdfStamper(pdfReader, newpdfStream);

                    PdfContentByte pdfContentByte = pdfStamper.GetOverContent(1);
                    BaseFont baseFont = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1250, BaseFont.NOT_EMBEDDED);
                    pdfContentByte.SetColorFill(BaseColor.BLUE);
                    pdfContentByte.SetFontAndSize(baseFont, 8);
                    pdfContentByte.BeginText();
                    pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_CENTER, " ", 400, 600, 0);

                    Dictionary<string, System.Drawing.Image> images;
                    images = new Dictionary<string, System.Drawing.Image>();
                    using (var reader = new PdfReader(sourceFileName))
                    {
                        var parser = new iTextSharp.text.pdf.parser.PdfReaderContentParser(reader);
                        ImageRenderListener listener = null;
                        for (var i = 1; i <= reader.NumberOfPages; i++)
                        {
                            parser.ProcessContent(i, (listener = new ImageRenderListener()));
                            var index = 1;
                            if (listener.Images.Count > 0)
                            {

                                try
                                {

                                    var image = iTextSharp.text.Image.GetInstance(pdfStream);
                                        float xval = image.AbsoluteX;
                                        float yval = image.AbsoluteY;
                                        image.SetAbsolutePosition(xval, yval);
                                        pdfContentByte.ShowText("rahul");

                                }
                                catch (Exception e)
                                {
                                    Console.WriteLine(e.Message);
                                }

                            }
                        }
                    }
                    pdfContentByte.EndText();
                    pdfStamper.Close();
                }
            }

错误发生在以下行:

iTextSharp.text.Image.GetInstance(pdfStream);

并且在调试我发现实际文件读取时,在pdfreader读取流后seeek被设置为false。

1 个答案:

答案 0 :(得分:3)

为何关闭?

这很简单:只要从PdfReader构造Stream,该流就会在读到结束后关闭。因此,在

之后
PdfReader pdfReader = new PdfReader(pdfStream);

pdfStream已关闭。

是的,这与源代码注释相矛盾,该注释声称“流被读取到最后但未关闭”:

/**
 * Reads and parses a PDF document.
 * @param isp the <CODE>InputStream</CODE> containing the document. The stream is read to the
 * end but is not closed
 * @throws IOException on error
 */
public PdfReader(Stream isp) : this(isp, null) {
}

/**
 * Reads and parses a PDF document.
 * @param is the <CODE>InputStream</CODE> containing the document. The stream is read to the
 * end but is not closed
 * @param ownerPassword the password to read the document
 * @throws IOException on error
 */
public PdfReader(Stream isp, byte[] ownerPassword) : this(
    new RandomAccessSourceFactory().CreateSource(isp),
    false,
    ownerPassword,
    null,
    null,
    false) {
}

但是看一下使用过的RandomAccessSourceFactory方法CreateSource重载:

/**
 * Creates a {@link RandomAccessSource} based on an {@link InputStream}.  The full content of the InputStream is read into memory and used
 * as the source for the {@link RandomAccessSource}
 * @param is the stream to read from
 * @return the newly created {@link RandomAccessSource}
 */
public IRandomAccessSource CreateSource(Stream inp) {
    try {
        return CreateSource(StreamUtil.InputStreamToArray(inp));
    }
    finally {
        try {inp.Close();}catch{}
    }       
} 

即。强制执行Close

尝试重新使用

话虽如此,如果文件没有关闭,你只会有一个不同的例外。

PdfReader pdfReader = new PdfReader(pdfStream);

将流读到最后,所以这里

var image = iTextSharp.text.Image.GetInstance(pdfStream);

没有什么可以从流中读取。

即使您确实将流重置为Image.GetInstance之前的开头,您还会遇到另一个例外:流内容是PDF或位图图像。如果是PDF,Image.GetInstance将失败;如果是位图,new PdfReader将失败(假设您没有使用其中一个构造文件,这些文件都被接受为位图,并通过网格格式化为PDF)

任务

关于在文件中的图像上方写入一些文本的任务,您可以通过创建自定义渲染侦听器(而不是使用忽略图像坐标的现有渲染器)来完成此操作,例如:像这样:

public class ImageEntitlingRenderListener : IRenderListener
{
    BaseFont baseFont = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1250, BaseFont.NOT_EMBEDDED);
    PdfStamper pdfStamper = null;
    int page = 0;

    public ImageEntitlingRenderListener(PdfStamper pdfStamper, int page)
    {
        this.pdfStamper = pdfStamper;
        this.page = page;
    }

    public void RenderImage(ImageRenderInfo renderInfo)
    {
        Matrix ctm = renderInfo.GetImageCTM();
        float xCenter = ctm[Matrix.I31] + 0.5F * ctm[Matrix.I11];
        float yTop = ctm[Matrix.I32] + ctm[Matrix.I22];
        PdfContentByte pdfContentByte = pdfStamper.GetOverContent(page);
        pdfContentByte.SetColorFill(BaseColor.BLUE);
        pdfContentByte.SetFontAndSize(baseFont, 8);
        pdfContentByte.BeginText();
        pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "rahul", xCenter, yTop, 0);
        pdfContentByte.EndText();
    }

    public void BeginTextBlock() { }
    public void EndTextBlock() { }
    public void RenderText(TextRenderInfo renderInfo) { }
}

你可以像这样使用它:

private static void InsertTextToPdf(string sourceFileName, string newFileName)
{
    using (Stream pdfStream = new FileStream(sourceFileName, FileMode.Open))
    using (Stream newpdfStream = new FileStream(newFileName, FileMode.Create, FileAccess.ReadWrite))
    {
        PdfReader pdfReader = new PdfReader(pdfStream);
        PdfStamper pdfStamper = new PdfStamper(pdfReader, newpdfStream);

        var parser = new PdfReaderContentParser(pdfReader);
        for (var i = 1; i <= pdfReader.NumberOfPages; i++)
        {
            parser.ProcessContent(i, (new ImageEntitlingRenderListener(pdfStamper, i)));
        }
        pdfStamper.Close();
        pdfReader.Close();
    }
}

请注意,代码中有一些简化的假设。特别是它假定图像在PDF中直立绘制。您可能希望改进代码以获得更通用的用途。