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;
}
Related
I am using itext7 pdfhtml (4.0.3) to convert Html to pdf in memory. Below method is taking html in memory and returning PdfDocument object of itext7. I need to convert that PdfDocument object to byte array or stream.
Please let me know how we can achieve that.
private iText.Kernel.Pdf.PdfDocument CreatePdf( string html)
{
byte[] bytes = Encoding.ASCII.GetBytes(html);
ConverterProperties properties = new ConverterProperties();
properties.SetBaseUri(path);
MemoryStream myMemoryStream = new MemoryStream(bytes);
PdfWriter writer = new(myMemoryStream);
iText.Kernel.Pdf.PdfDocument pdf = new iText.Kernel.Pdf.PdfDocument(writer);
pdf.SetDefaultPageSize(PageSize.A4);
pdf.SetTagged();
HtmlConverter.ConvertToDocument(html,pdf,properties);
return pdf;
}
to #mkl's point, you're kind of overdoing it. Here's a simple example:
var html = "<h1>hi mom</h1>";
byte[] result;
using (var memoryStream = new MemoryStream())
{
var pdf = new PdfDocument(new PdfWriter(memoryStream));
pdf.SetDefaultPageSize(PageSize.A4);
pdf.SetTagged();
HtmlConverter.ConvertToPdf(html, pdf, new ConverterProperties());
result = memoryStream.ToArray();
}
File.WriteAllBytes(#"/tmp/file.pdf", result);
the memoryStream will have your in memory representation of your conversion. I've added the WriteAllBytes bits just so you can see for yourself.
Another note, if you do not require setting any PdfDocument properties, you can use an even simpler version:
var html = "<h1>hi mom</h1>";
byte[] result;
using (var memoryStream = new MemoryStream())
{
HtmlConverter.ConvertToPdf(html, memoryStream);
result = memoryStream.ToArray();
}
File.WriteAllBytes(#"/tmp/file.pdf", result);
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 want to convert word byte array to pdf byte array.
I am using Xceed.Words.NET library
var stream = new MemoryStream(sourceFile.AttachedFile);
var doc = DocX.Load(stream);
var ms = new MemoryStream();
doc.SaveAs(ms);
var wByteArray = ms.GetBuffer();
Use this:
var stream = new MemoryStream(sourceFile.AttachedFile);
using (var document = DocX.Load(stream))
{
stream = new MemoryStream();
DocX.ConvertToPdf(document, stream);
}
var bytes = stream.ToArray();
As mentioned in the comment, you need a professional version of DocX library to convert a Word document to PDF.
If you're looking for free solution then perhaps you could try out GemBox.Document, its free version does support converting to PDF, but it has a document size limitation.
You can use it like this:
ComponentInfo.SetLicense("FREE-LIMITED-KEY");
var stream = new MemoryStream(sourceFile.AttachedFile);
var document = DocumentModel.Load(stream, LoadOptions.DocxDefault);
stream = new MemoryStream();
document.Save(stream, SaveOptions.PdfDefault);
var bytes = stream.ToArray();
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
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.