c# - iTextSharp - Cannot access a closed Stream - c#

I have been struggling with this issue for days now and cant find a solution anywhere, The only thing I can think of is that iTextSharp doesn't work....
First I create a MemoryStream like so:
MemoryStream outFile = new MemoryStream();
I have this Stream here:
var streamFile = await graphClient.Me.Drive.Items["item-id"].Content.Request().GetAsync();
Which is a PDF file from Microsoft OneDrive
Then I take this Stream and assign it to iTextSharp's PdfReader like so:
PdfReader pdfReader = new PdfReader(streamFile);
Then I use PDFStamper to make edits to the PDF File like so:
PdfStamper pdfStamper = new PdfStamper(pdfReader, outFile);
Then I do my edits like so:
AcroFields fields = pdfStamper.AcroFields;
fields.SetField("Full_Names", "JIMMMMMMAYYYYY");
Then I re-upload the file to OneDrive (which is also expecting a Stream) like so:
await graphClient.Me.Drive.Items["item-id"].ItemWithPath("NewDocument-2.pdf").Content.Request().PutAsync(outFile);
But I get this error:
Cannot access a closed Stream.
on this line:
await graphClient.Me.Drive.Items["item-id"].ItemWithPath("NewDocument-2.pdf").Content.Request().PutAsync<DriveItem>(outFile);
When I just get my file from OneDrive and Upload it like so:
var streamFile = await graphClient.Me.Drive.Items["item-id"].Content.Request().GetAsync();
await graphClient.Me.Drive.Items["item-id"].ItemWithPath("NewDocument-2.pdf").Content.Request().PutAsync<DriveItem>(streamFile);
It works! I am able to get the file and re-upload it, so its not an issue with the PDF file at all, iTextSharp is broken I have tried multiple things and nothing works at all. What is iTextSharp doing wrong? Here is my full code:
using (MemoryStream outFile = new MemoryStream())
{
var streamFile = await graphClient.Me.Drive.Items["item-id"].Content.Request().GetAsync();
using (PdfReader pdfReader = new PdfReader(streamFile))
{
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, outFile))
{
AcroFields fields = pdfStamper.AcroFields;
fields.SetField("Full_Names", "JIMMMMMMAYYYYY");
}
}
await graphClient.Me.Drive.Items["item-id"].ItemWithPath("NewDocument-2.pdf").Content.Request().PutAsync<DriveItem>(outFile);
}
What the hell is going wrong?

The stamper closes the inner stream when it gets disposed. Add this line just below the line where you create the stamper:
pdfStamper.Writer.CloseStream = false;

Related

ITextSharp - Cannot Open .pdf because it is being used by another process?

I am having a issue where I write to a pdf file and then close it and later on open it up again and try to read it.
I get "Cannot Open .pdf because it is being used by another process?"
var path = // get path
Directory.CrateDirctory(path);
using(var writer = new PdfWriter(path, //writer properties)){
var reader = new PdfReader(//template);
var pdfDoc = new PdfDcoument(reader, writer);
writer.SetCloseStream(false)
// some code to fill in the pdf
reader.Close();
pdfDoc.Close();
}
//later in code
using(var stream = new MemoryStream(File.ReadAllBytes(//the file that I crated above)))
{
// do some stuff here
}
I get the error right on the using statement above. I thought all the streams for creating the pdf are closed at this point but it seems like it is not.
The issue is with the line writer.SetCloseStream(false);. That is telling it to not close the stream when the writer is closed. Since the stream is left open you will get an IOException when you create another stream for reading. Remove this line or set to true to resolve the issue.
If you need to keep the stream open for whatever reason, like issues with flushing the write buffer too soon when PdfWriter is closed. Then you can get access to the write stream and close it later when you are ready to read it. Something like this:
Stream outputStream;
using (var writer = new PdfWriter(path)){
writer.SetCloseStream(false);
// do whatever you need here
outputStream = writer.GetOutputStream();
}
// do whatever else you need here
// close the stream before creating a read stream
if(null != outputStream) {
outputStream.Close();
}
using (var stream = new MemoryStream(File.ReadAllBytes(path)))
{
// do some stuff here
}

C# - Microsoft Graph API with iTextSharp - Cannot access a closed Stream

I am using Microsoft API Graph API to get a PDF file from my OneDrive which I have successfully got via this line:
var streamFile = await graphClient.Me.Drive.Items["{item-id}"].Content.Request().GetAsync();
Now I want to take a the stream of this file and edit it with iTextSharp
using (MemoryStream outFile = new MemoryStream())
{
//Dont know what to replace this with
PdfReader pdfReader = new PdfReader("Uploads/Document.pdf");
PdfStamper pdfStamper = new PdfStamper(pdfReader, outFile);
AcroFields fields = pdfStamper.AcroFields;
fields.SetField("Full_Names", "aaa");
pdfStamper.Close();
pdfReader.Close();
}
And then upload it back to OneDrive, which I am able to do via this:
//Don't know what to replace this with
var uploadPath = System.Web.HttpContext.Current.Server.MapPath("~/Uploads/NewDocument.pdf");
byte[] data = System.IO.File.ReadAllBytes(uploadPath);
Stream stream = new MemoryStream(data);
await graphClient.Me.Drive.Items["{item-id}"].ItemWithPath("NewDocument.pdf").Content.Request().PutAsync<DriveItem>(stream);
So my question is how do I take my file that I got and use iTextSharp to do its thing? So I can upload this new edited file?
UPDATE
I tried this:
var streamFile = await graphClient.Me.Drive.Items["{item-id}"].Content.Request().GetAsync();
using (MemoryStream outFile = new MemoryStream())
{
PdfReader pdfReader = new PdfReader(streamFile);
PdfStamper pdfStamper = new PdfStamper(pdfReader, outFile);
AcroFields fields = pdfStamper.AcroFields;
fields.SetField("Full_Names", "JIMMMMMMAYYYYY");
await graphClient.Me.Drive.Items["{item-id}"].ItemWithPath("NewDocument-2.pdf").Content.Request().PutAsync<DriveItem>(outFile);
pdfStamper.Close();
pdfReader.Close();
}
But got this error:
Cannot access a closed Stream.
I can see the file is being uploaded to my OneDrive, but when I goto open it I get this error:
Failed to load PDF document.
What am I doing wrong here?
UPDATE
When I remove these last two lines:
pdfStamper.Close();
pdfReader.Close();
I don't get Cannot access a closed Stream error anymore, my file uploads but I get an error when I open it:
Failed to load PDF document.
UPDATE
When I try this
var streamFile = await graphClient.Me.Drive.Items["{item-id}"].Content.Request().GetAsync();
await graphClient.Me.Drive.Items["{item-id}"].ItemWithPath("NewDocument-2.pdf").Content.Request().PutAsync<DriveItem>(streamFile);
It uploads the file I grabbed, so that part is working, but I can't edit it with iTextSharp.
See if this helps you along:
Do I need to reset a stream(C#) back to the start?
Once you read a stream, you need to reset it back to the beginning to do something else with it.

Loading an iTextSharp Document into MemoryStream

I'm developing an ASP.NET application where I have to send an PDF based on a Table created dinamically on the page as attachment on a email. So I have a function that creates the PDF as iTextSharp Document and returns it. If i try just to save this document, it works fine but I'm having a bad time trying to make it as Stream. I tried several things already, but I always get stuck at some point.
I tried to serialize it, but appears that Document is not serializable. Then I tried to work with PdfCopy, but I couldn't find out how to use this to my problem in specific.
The code right now is like this:
//Table,string,string,Stream
//This document returns fine
Document document = Utils.GeneratePDF(table, lastBook, lastDate, Response.OutputStream);
using (MemoryStream ms = new MemoryStream())
{
PdfCopy copy = new PdfCopy(document, ms);
//Need something here to copy from one to another! OR to make document as Stream
ms.Position = 0;
//Email, Subject, Stream
Utils.SendMail(email, lastBook + " - " + lastDate, ms);
}
Try to avoid passing the native iTextSharp objects around. Either pass streams, files or bytes. I don't have an IDE in front of me right now but you should be able to do something like this:
byte[] Bytes;
using(MemoryStream ms = new MemoryStream()){
Utils.GeneratePDF(table, lastBook, lastDate, ms);
Bytes = ms.ToArray();
}
Then you can either change your Utils.SendMail() to accept a byte array or just wrap it in another stream.
EDIT
You might also be able to just do something like this in your code:
using(MemoryStream ms = new MemoryStream()){
Utils.GeneratePDF(table, lastBook, lastDate, ms);
ms.Position = 0;
Utils.SendMail(email, lastBook + " - " + lastDate, ms);
}
I did this in the past by doing something like the following:
using (Document doc = new Document())
{
MemoryStream msPDFData = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(doc, msPDFData);
doc.Open();
doc.Add(new Paragraph("I'm a pdf!");
}
If you need access to the raw data you can also do
byte[] pdfData = msPDFData.ToArray();

ITextSharp edit an existing pdf

I want to add a text to an existing PDF file using iTextSharp, I found different ways but in all of them the writer and reader are separate pdf files.
I want a way so I can open a pdf then write different things in different positions.
right now I have this code, but it makes a new file.
using (FileStream stream1 = File.Open(path, FileMode.OpenOrCreate))
{
BaseFont bf = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
PdfReader reader = new PdfReader("C:\\26178DATA\\pdf\\holding.pdf");
var pageSize = reader.GetPageSize(1);
PdfStamper stamper = new PdfStamper(reader, stream1);
iTextSharp.text.Font tmpFont = new iTextSharp.text.Font(bf, fontSize);
PdfContentByte canvas = stamper.GetOverContent(1);
Phrase ph = new Phrase(words[1], tmpFont);
ph.Font = tmpFont;
canvas.SetFontAndSize(bf, fontSize);
ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT, ph, iTextSharp.text.Utilities.MillimetersToPoints(x * 10), pageSize.GetTop(iTextSharp.text.Utilities.MillimetersToPoints(y * 10)), 0);
stamper.Close();
}
You want to add a text to an existing PDF file using iTextSharp, found different ways but in all of them the writer and reader are separate pdf files.
As the normal way in which iText(Sharp) manipulates a PDF using a PdfStamper, can involve major reorganization of existing PDF elements, iText does not edit a file in place. The other way, using append mode, would allow for editing in place; but such an option is not implemented. A big draw-back of in-place editing is that in case of some program failure, the file in question might remain in an intermediary, unusable state.
That being said, you can save the new file to the path of the original file by first reading the file into memory completely and then starting to create the output with the same path. In case of your sample code that would imply at least moving the PdfReader constructor use before the creation of the output stream:
PdfReader reader = new PdfReader(path);
using (FileStream stream1 = File.Open(path, FileMode.OpenOrCreate))
{
BaseFont bf = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
...
Alternatively you could create the result file in memory, i.e. in a MemoryStream instead of a FileStream, and, when finished, write the contents of the memory stream to your source file path.

What's the best way to adding a user's signature to a PDF document online?

I need to add a user's signature (like your signature on a credit card, for example) to a PDF document online. How can I do it? What is the best practice for this kind of tasks?
You can use iTextSharp to do it. Something like this will work for you:
PdfReader pdfReader = null;
PdfStamper pdfStamper = null;
// Open the PDF file to be signed
pdfReader = new PdfReader(this.signFile.FullName);
// Output stream to write the stamped PDF to
using (FileStream outStream = new FileStream(targetFilename, FileMode.Create))
{
try
{
// Stamper to stamp the PDF with a signature
pdfStamper = new PdfStamper(pdfReader, outStream);
// Load signature image
iTextSharp.text.Image sigImg = iTextSharp.text.Image.GetInstance(SIGNATURE_IMAGE_PATH);
// Scale image to fit
sigImg.ScaleToFit(MAX_WIDTH, MAX_HEIGHT);
// Set signature position on page
sigImg.SetAbsolutePosition(POS_X, POS_X);
// Add signatures to desired page
PdfContentByte over = pdfStamper.GetOverContent(PAGE_NUM_TO_SIGN);
over.AddImage(sigImg);
}
finally
{
// Clean up
if (pdfStamper != null)
pdfStamper.Close();
if (pdfReader != null)
pdfReader.Close();
}
}
You need to implement some action with JavaScript. You can use some JQuery pluging for that. Here is an example;
http://motyar.blogspot.com/2010/01/draw-with-jquery.html
For the pdf part, you can use some pdf converter tool Like ITextSharp

Categories

Resources