I have generated a pdf using PDFSharp.
I call the save method, and save it to disk, and the file is perfect.
I then need to get the file into a MemorySteam, in preparion of sending it to my website to download. However, the file ends up invalid. corrupt.
So, to see where it's going wrong, I have put the file into a MemoryStream, and then I try write that steam to a file, to confirm all is OK. It isn't.
Here I sav the file to disk, to check it (debugging), and then put it into a stream:
document.Save("c:\\temp\\ggg.pdf");
MemoryStream ms = new MemoryStream();
document.Save(ms, false);
byte[] buffer = new byte[ms.Length];
ms.Seek(0, SeekOrigin.Begin);
ms.Flush();
ms.Read(buffer, 0, (int)ms.Length);
return ms;
I then return 'ms' to my calling function, and attempt to write the stream to a file:
var doc = GeneratePdf(1);
using (FileStream file = new FileStream("c:\\temp\\222.pdf", FileMode.Create, System.IO.FileAccess.Write))
{
byte[] bytes = new byte[doc.Length];
doc.Read(bytes, 0, (int)doc.Length);
file.Write(bytes, 0, bytes.Length);
doc.Close();
}
But 222.pdf is not a valid pdf. ggg.pdf was fine. So I am doing something wrong when I write to stream, and write to disk. Why is the file getting corrupted?
I cannot reproduce your issue (PdfSharp 1.32.3057.0). It seems to me that you are messing too much with manual stream copying.
Try the following code, which correctly creates a pdf, streams it into a MemoryStream and than saves it into a file:
var pdf = new PdfSharp.Pdf.PdfDocument();
var page = pdf.AddPage();
var gfx = XGraphics.FromPdfPage(page);
var font = new XFont("Verdana", 20, XFontStyle.BoldItalic);
gfx.DrawString("Hello, World!", font, XBrushes.Black, new XRect(0, 0, page.Width, page.Height), XStringFormats.Center);
var ms = new MemoryStream();
pdf.Save(ms, false);
ms.Position = 0;
using (var file = File.OpenWrite("test.pdf"))
ms.CopyTo(file); // no need for manual stream copy or buffers
Related
I am serializing an object to a stream to store as file and then retrieving and trying to deserialize the object, but get an error parsing. Below is code:
var content = JsonConvert.SerializeObject(data);
var output = new MemoryStream();
var writer = new StreamWriter(output, Encoding.UTF8);
writer.Write(content);
writer.Flush();
//write to some file...
//when reading the file
Stream filestream;
//filestream opens some file stream
byte[] buffer = new byte[4096]
using(MemoryStream ms = new MemoryStream()){
int read;
while((read = filestream.Read(buffer, 0, buffer.Length)) > 0){
ms.Write(buffer, 0, read);
}
var data = Encoding.UTF8.GetString(ms.ToArray());
//encounters error here. I can see that first few chars of the string are question marks.
JsonConvert.DeserializeObject<T>(data);
A couple ideas. Are you getting an exception?
Try encapsulating your write & reads into functions and wrap the memoryStream and streamWriter in using statements as well
using var writer = new StreamWriter(...
Additionally you don't need to set the length of the buffer to 4096, that's probably messing up your encoding. Read your memorystream to an array like so
var buffer = ms.ToArray();
How can I write MemoryStream to byte[]
It looks like you're having an issue copying the memory between the 2 memory streams though. Ideally you would write and read to a file or some other source rather than between 2 memory stream objects but you can copy the contents directly using a copyto
https://learn.microsoft.com/en-us/dotnet/api/system.io.stream.copyto?view=net-6.0
Edit: Adding pseudocode
Assuming your content has been read into
Stream filestream;
using var MemoryStream ms = new MemoryStream();
filestream.CopyTo(ms);
var data = Encoding.UTF8.GetString(ms.ToArray());
return JsonConvert.DeserializeObject<T>(data);
I am using DotNetZip to add a file from a MemoryStream to a zip file and then to save that zip as a MemoryStream so that I can email it as an attachment. The code below does not err but the MemoryStream must not be done right because it is unreadable. When I save the zip to my hard drive everything works perfect, just not when I try to save it to a stream.
using (ZipFile zip = new ZipFile())
{
var memStream = new MemoryStream();
var streamWriter = new StreamWriter(memStream);
streamWriter.WriteLine(stringContent);
streamWriter.Flush();
memStream.Seek(0, SeekOrigin.Begin);
ZipEntry e = zip.AddEntry("test.txt", memStream);
e.Password = "123456!";
e.Encryption = EncryptionAlgorithm.WinZipAes256;
var ms = new MemoryStream();
ms.Seek(0, SeekOrigin.Begin);
zip.Save(ms);
//ms is what I want to use to send as an attachment in an email
}
Ok, I figured out my problem, pretty stupid actually. Thanks for everyone's help!
ZipEntry e = zip.AddEntry("test.txt", memStream);
e.Password = "123456!";
e.Encryption = EncryptionAlgorithm.WinZipAes256;
//zip.Save("C:\\Test\\Test.zip");
//Stream outStream;
var ms = new MemoryStream();
zip.Save(ms);
//--Needed to add the following 2 lines to make it work----
ms.Seek(0, SeekOrigin.Begin);
ms.Flush();
I've copied your code, and then saved your final memory steam to disk as data.txt. It was completely unreadable to me, but then I realized that it wasn't a text file, it was a zip file, so i saved it as data.zip and it worked as expected
the method I used to save ms to disk is the following(immediately after your zip.Save(ms); line)
ms.Position = 0;
byte[] data = ms.ToArray();
File.WriteAllBytes("data.zip", data);
So, I believe that your memory stream is what It is supposed to be, which is compressed text. It won't be readable until you decompress it.
I have a HttpModule that intercepts requests for PDF documents and I would like to add a date to the PDF and stream back to the client.
My code so far is
context.Response.ClearContent();
using (MemoryStream ms = new MemoryStream())
{
PdfReader reader = new PdfReader(document.Url + "&a=1");
PdfStamper stamper = new PdfStamper(reader, ms);
// *** Modify PDF here
stamper.Close();
context.Response.ContentType = "application/pdf";
context.Response.OutputStream.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length);
context.Response.OutputStream.Flush();
context.Response.OutputStream.Close();
context.Response.Flush();
context.Response.End();
}
HttpContext.Current.ApplicationInstance.CompleteRequest();
The code above works fine, but as soon as I try to modify the PDF I get a PDF Reader error 'The file is damaged and cannot be repaired', for example
TextField textField = new TextField(stamper.Writer, new Rectangle(0, 1000, 90, 600), name);
textField.Font = FontFactory.GetFont(FontFactory.HELVETICA, DEFAULT_FONT_SIZE, Font.NORMAL).BaseFont;
textField.FontSize = DEFAULT_FONT_SIZE;
textField.Rotation = 90;
PdfFormField field = textField.GetTextField();
stamper.AddAnnotation(field, page);
Does anyone know how I can solve this issue?
You continue sending stuff after the pdf, add
context.Response.End();
after:
context.Response.Flush();
Now you will send only the pdf, instead of the whole page. This sometimes fixes this issue.
You are also reading the buffer twice:
context.Response.OutputStream.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length);
try to add
byte[] bytes = ms.ToArray();
and then
context.Response.OutputStream.BinaryWrite(bytes);
I'm trying to save a bitmap to my isolated storage as a png file. I found a library on Codeplex called ImageTools which people have been recommending but when i try it and attempt to open the file it says that its corrupt. Any know what i am doing wrong?
private static void SaveImageToIsolatedStorageAsPng(BitmapImage bitmap, string fileName)
{
//convert to memory stream
MemoryStream memoryStream = new MemoryStream();
WriteableBitmap writableBitmap = new WriteableBitmap(bitmap);
writableBitmap.SaveJpeg(memoryStream, bitmap.PixelWidth, bitmap.PixelHeight, 0, 100);
//encode memory stream as PNG
ExtendedImage image = new ExtendedImage();
image.SetSource(memoryStream);
PngEncoder encoder = new PngEncoder();
//Save to IsolatedStorage
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
using (var writeStream = new IsolatedStorageFileStream(fileName, FileMode.Create, store))
{
encoder.Encode(image, writeStream);
}
}
You're attempting to convert the JPEG memory stream into PNG. That will make it corrupt - you should save the Bitmap directly to PNG.
I haven't tried this particular task with the imagetools library, but if you see John Papa's blog, it looks like you need to call the ToImage extension method on your WriteableBitmap which is provided as part of ImageTools. Then you can use the encoder to take this image and write out to your open stream.
var img = bitmap.ToImage();
var encoder = new PngEncoder();
using (var stream = new IsolatedStorageFileStream(fileName, FileMode.Create, store))
{
encoder.Encode(img, stream);
stream.Close();
}
I want to save a PdfSharp.Pdf.PdfDocument by its Save method to a Stream, but it doesn't attach the PDF header settings to it. So when I read back the Stream and return it to the user, he see that the PDF file is invalid. Is there a solution to attach the PDF header settings when PDFsharp saves to memory?
If you think there is an issue with PdfDocument.Save, then please report this on the PDFsharp forum (but please be more specific with your error description).
Your "solution" looks like a hack to me.
"pdfRenderer.Save" calls "PdfDocument.Save" internally.
Whatever the problem is - your "solution" still calls the same Save routine.
Edit:
To get a byte[] containing a PDF file, you only have to call:
MemoryStream stream = new MemoryStream();
document.Save(stream, false);
byte[] bytes = stream.ToArray();
Early versions of PDFsharp do not reset the stream position.
So you have to call
ms.Seek(0, SeekOrigin.Begin);
to reset the stream position before reading from the stream; this is no longer required for current versions.
Using ToArray can often be used instead of reading from the stream.
Edit 2: instead of stream.ToArray() it may be more efficient to use stream.GetBuffer(), but this buffer is usually larger than the PDF file and you only have to use stream.Length bytes from that buffer. Very useful for method that take a byte[] along with a length parameter.
So the solution:
MigraDoc.DocumentObjectModel.Document doc = new MigraDoc.DocumentObjectModel.Document();
MigraDoc.Rendering.DocumentRenderer renderer = new DocumentRenderer(doc);
MigraDoc.Rendering.PdfDocumentRenderer pdfRenderer = new MigraDoc.Rendering.PdfDocumentRenderer();
pdfRenderer.PdfDocument = pDoc;
pdfRenderer.DocumentRenderer = renderer;
using (MemoryStream ms = new MemoryStream())
{
pdfRenderer.Save(ms, false);
byte[] buffer = new byte[ms.Length];
ms.Seek(0, SeekOrigin.Begin);
ms.Flush();
ms.Read(buffer, 0, (int)ms.Length);
}
There is this MigraDoc stuff which comes with PdfSharp, but i hardly found any proper doc/faq for it. After hours of googling i've found a snippet which was something like this. Now it works.
I found simpler solution:
byte[] fileContents = null;
using(MemoryStream stream = new MemoryStream())
{
pdfDoc.Save(stream, true);
fileContents = stream.ToArray();
}
Source:
http://usefulaspandcsharp.wordpress.com/2010/03/09/save-a-pdf-to-a-byte-array-using-pdf-sharpmigradoc/
For MigraDoc (ver 1.30) I could save it with
PdfDocumentRenderer renderer = new PdfDocumentRenderer(true, PdfSharp.Pdf.PdfFontEmbedding.Always);
renderer.Document = report.m_Document;
renderer.RenderDocument();
using (MemoryStream stream = new MemoryStream())
{
renderer.PdfDocument.Save(stream, false);
... your code in here
}
Thanks Misnyo Solution. But for me it works like this:
Document document = new Document();
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer();
//Add to document here.......
//render the document with pdf renderer
pdfRenderer.Document = document;
pdfRenderer.RenderDocument();
//Save renderer result into stream
using(MemoryStream ms = new MemoryStream())
{
pdfRenderer.PdfDocument.Save(ms, false);
byte[] buffer = new byte[ms.Length];
ms.Seek(0, SeekOrigin.Begin);
ms.Flush();
ms.Read(buffer, 0, (int)ms.Length);
ms.Position = 0;
}