How to save FileSteam as PDF file - c#

I am using a third party tool to get the scanned content from the scanner. On button click it executes the code and gives the content as a FileStream. Now I need to save this FileStream content as a pdf file in to a specified folder.
After saving I need to open the file in browser. How can I save the FileStream as a PDF file?

You can write the stream directly to the output buffer of the response.
So if you're at the point in your code where you have the filestream from the scanner. Simply read bytes from the scanner filestream and write them to the Response.OutputStream
Set the contentType to application/pdf
Make sure you return nothing else. The users browser will do whatever it is configured to do now, either save to disk or show in the browser. You can also save to disk on the server at this point as well in case you wanted a backup.
I'm assuming your file stream is already a pdf, otherwise you'll need to use something like itextsharp to create the pdf.
Edit
Here's some rough and ready code to do it. You'll want to tidy this up, like adding exception trapping to make sure the file stream gets cleaned up properly.
public void SaveToOutput(Stream dataStream)
{
dataStream.Seek(0, SeekOrigin.Begin);
FileStream fileout = File.Create("somepath/file.pdf");
const int chunk = 512;
byte[] buffer = new byte[512];
int bytesread = dataStream.Read(buffer,0,chunk);
while (bytesread == chunk)
{
HttpContext.Current.Response.OutputStream.Write(buffer, 0, chunk);
fileout.Write(buffer, 0, chunk);
bytesread = dataStream.Read(buffer, 0, chunk);
}
HttpContext.Current.Response.OutputStream.Write(buffer, 0, bytesread);
fileout.Write(buffer, 0, bytesread);
fileout.Close();
HttpContext.Current.Response.ContentType = "application/pdf";
}
Simon

You might want to take a look at the C# PDF Library on SourceForge: http://sourceforge.net/projects/pdflibrary/

If I'm understanding you correctly, the third party library is handing you a stream containing the data for the scanned document and you need to write it to a file? If that's the case you need to look up file I/O in C#. Here's a link and an example:
Stream sourceStream = scanner.GetOutput(); // whereever the source stream is
FileStream targetStream = File.OpenWrite(filename, FileMode.Create());
int bytesRead = 0;
byte[] buffer = new byte[2048];
while (true) {
bytesRead = sourceStream.Read(buffer, 0, buffer.length);
if (bytesRead == 0)
break;
targetStream.Write(buffer, 0, bytesRead);
}
sourceStream.Close();
targetStream.Close();

not sure, but maybe check this
http://sourceforge.net/projects/itextsharp/
iTextSharp + FileStream = Corrupt PDF file

Another prominent PDF library (which I have used in the past as well) is iTextSharp. You can take a look at this tutorial on how to convert your Stream to PDF then have the user download it.

Related

How to copy a Stream from the begining irrespective its current position

I got a file stream which has content read from a disk.
Stream input = new FileStream("filename");
This stream is to be passed to a third party library which after reading the stream, keeps the Stream's position pointer at the end of the file (as ususal).
My requirement is not to load the file from the desk everytime, instead I want to maintain MemoryStream, which will be used everytime.
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, read);
}
}
I have tried the above code. It works for the first very time to copy the input stream to output stream, but subsequent calls to CopyStream will not work as the source's Position will be at the end of the stream after the first call.
Are there other alternatives which copy the content of the source stream to another stream irrespective of the source stream's current Position.
And this code needs to run in thread safe manner in a multi threaded environment.
You can use .NET 4.0 Stream.CopyTo to copy your steam to a MemoryStream. The MemoryStream has a Position property you can use to move its postition to the beginning.
var ms = new MemoryStream();
using (Stream file = File.OpenRead(#"filename"))
{
file.CopyTo(ms);
}
ms.Position = 0;
To make a thread safe solution, you can copy the content to a byte array, and make a new MemoryStream wrapping the byte array for each thread that need access:
byte[] fileBytes = ms.ToArray();
var ms2 = new MemoryStream(fileBytes);
You should check the input stream's CanSeek property. If that returns false, you can only read it once anyway. If CanSeek returns true, you can set the position to zero and copy away.
if (input.CanSeek)
{
input.Position = 0;
}
You may also want to store the old position and restore it after copying.
ETA: Passing the same instance of a Stream around is not the safest thing to do. E.g. you can't be sure the Stream wasn't disposed when you get it back. I'd suggest to copy the FileStream to a MemoryStream in the beginning, but only store the byte content of the latter by calling ToArray(). When you need to pass a Stream somewhere, just create a new one each time with new MemoryStream(byte[]).

FileStream to Bitmap - Parameter is not valid

I have read the posts on this subject but none of them explains it to me clearly enough to be able to fix the problem.
I am trying to upload a file from a local directory to the server.
Here is my code:
string fullPath = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory + #"Images\Readings", PhotoFileName);
Stream s = System.IO.File.OpenRead(fileUpload);
byte[] buffer = new byte[s.Length];
s.Read(buffer, 0, Convert.ToInt32(s.Length));
using (FileStream fs = new FileStream(fullPath, FileMode.Create))
{
fs.Write(buffer, 0, Convert.ToInt32(fs.Length));
Bitmap bmp = new Bitmap((Stream)fs);
bmp.Save(fs, ImageFormat.Jpeg);
}
I keep on getting an Argument Exception: "Parameter is not valid" on line:
Bitmap bmp = new Bitmap((Stream)fs);
Can anyone explain this to me please
There are at least two problems, probably three. First, your copying code is broken:
byte[] buffer = new byte[s.Length];
s.Read(buffer, 0, Convert.ToInt32(s.Length));
You've assumed that this will read all of the data in a single Read call, and ignored the return value for Read. Generally, you'd need to loop round, reading data and writing it (the amount you've just read) to the output stream, until you read the end. However, as of .NET 4, Stream.CopyTo makes this much simpler.
Next is how you're creating the bitmap:
using (FileStream fs = new FileStream(fullPath, FileMode.Create))
{
fs.Write(buffer, 0, Convert.ToInt32(fs.Length));
Bitmap bmp = new Bitmap((Stream)fs);
bmp.Save(fs, ImageFormat.Jpeg);
}
You're trying to read from the stream when you've just written to it - but without "rewinding"... so there's no more data left to read.
Finally, I would strongly advise against using Bitmap.Save to write to the same stream that you're loading the bitmap from. Bitmap will keep a stream open, and read from it when it needs to - if you're trying to write to it at the same time, that could be very confusing.
It's not clear why you're using Bitmap at all, to be honest - if you're just trying to save the file that was uploaded, without any changes, just use:
using (Stream input = File.OpenRead(fileUpload),
output = File.Create(fullPath))
{
input.CopyTo(output);
}
This is assuming that fileUpload really is an appropriate filename - it's not clear why you haven't just written the file to the place you want to write it to straight away, to be honest. Or use File.Copy to copy the file. The above code should work with any stream, so you can change it to save the stream straight from the request...

File upload with c# and streaming

Looking at the different ways to upload a file in .NET, e.g. HttpPostedFile, and using a HttpHandler, I'm trying to understand how the process works in a bit more details.
Specifically how it writes the information to a file.
Say I have the following:
HttpPostedFile file = context.Request.Files[0];
file.SaveAs("c:\temp\file.zip");
The actual file does not get created until the full stream seems to be processed.
Similarly:
using (Stream output = File.OpenWrite("c:\temp\file.zip"))
using (Stream input = file.InputStream)
{
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, bytesRead);
}
}
I would have thought that this would "progressively" write the file as it reads the stream. Looking at the filesystem, it does not seems to do this at all. If I breakpoint inside the while, it does though.
What I'm trying to do, is have it so you upload a file (using a javascript uploader), and poll alongside, whereby the polling ajax request tries to get the fileinfo(file size) of the uploaded file every second. However, it always returns 0 until the upload is complete.
Vimeo seems to be able to do this type of functionality (for IE)?? Is this a .NET limitation, or is there a way to progressively write the file from the stream?
Two points:
First, in Windows, the displayed size of a file is not updated constantly. The file might indeed be growing continually, but the size only increases once.
Second (more likely in this case), the stream might not be flushing to the disk. You could force it to by adding output.Flush() after the call to output.Write(). You might not want to do that, though, since it will probably have a negative impact on performance.
Perhaps you could poll the Length property of the output stream directly, instead of going through the file system.
EDIT:
To make the Length property of the stream accessible to other threads, you could have a field in your class and update it with each read/write:
private long _uploadedByteCount;
void SomeMethod()
{
using (Stream output = File.OpenWrite("c:\temp\file.zip"))
using (Stream input = file.InputStream)
{
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, bytesRead);
Interlocked.Add(ref _uploadedByteCount, bytesRead);
}
}
}
public long GetUploadedByteCount()
{
return _uploadedByteCount;
}

Create pdf document from System.IO.Stream object?

I have Stream object that contains data that i want to show in PDF document.
How do i create and Save PDF document from that Stream object? (The Stream object is created using MigraDoc tool)
I think you may be confused. MigraDoc creates Pdf documents. So if you have a stream from MigraDoc (which comes from it's PdfDocument object) I would guess that saving the stream to disk as "document.pdf" would be the best option.
See Jon Skeets answer to this here:
How do I save a stream to a file in C#?
Remember a stream is simply binary data. So when you want to read and write that data you use System.IO to read or write the stream into some location be it disk, memory or a network transmission.
I would take a look at the MigraDoc samples for more info:
http://www.pdfsharp.net/wiki/MigraDocSamples.ashx
if you are writing this to an HTTP output then I would do as follows:
byte[] buffer = new byte[8192];
pdfStream.Seek(0, SeekOrigin.Begin);
Response.ClearContent();
Response.ClearHeaders();
Response.BufferOutput = true;
Response.ContentType = "application/pdf";
int bytesRead = pdfStream.Read(buffer, 0, 8192);
while(bytesRead > 0)
{
byte[] buffer2 = new byte[bytesRead];
System.Buffer.BlockCopy(buffer, 0, buffer2, 0, bytesRead);
Response.BinaryWrite(buffer2);
Response.Flush();
bytesRead = pdfStream.Read(buffer, 0, 8192);
}
Response.End();

Delete dynamically generated PDF file immediately after it has been displayed to user

I'm creating a PDF file on the fly using ITextSharp and ASP.NET 1.1. My process is as follows -
Create file on server
Redirect browser to newly created PDF
file so it is displayed to user
What I'd like to do is delete the PDF from the server as soon it is displayed in the users browser. The PDF file is large so it is not an option to hold it in memory, an initial write to the server is required. I'm currently using a solution that periodically polls for files then deletes them, but I'd prefer a solution that deletes the file immediately after it has been downloaded to the client machine. Is there a way to do this?
Instead of redirecting the browser to the created file you could serve the file yourself using you own HttpHandler. Then you could delete the file immediately after you served it or you could even create the file in memory.
Write the PDF file directly to the Client:
public class MyHandler : IHttpHandler {
public void ProcessRequest(System.Web.HttpContext context) {
context.Response.ContentType = "application/pdf";
// ...
PdfWriter.getInstance(document, context.Response.OutputStream);
// ...
or read an already generated file 'filename', serve the file, delete it:
context.Response.Buffer = false;
context.Response.BufferOutput = false;
context.Response.ContentType = "application/pdf";
Stream outstream = context.Response.OutputStream;
FileStream instream =
new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
byte[] buffer = new byte[BUFFER_SIZE];
int len;
while ((len = instream.Read(buffer, 0, BUFFER_SIZE)) > 0) {
outstream.Write(buffer, 0, len);
}
outstream.Flush();
instream.Close();
// served the file -> now delete it
File.Delete(filename);
I didn't try this code. This is just how I think it would work ...
Inspired by f3lix's answer (thanks f3lix!) I've come up with the folowing VB.net code -
HttpContext.Current.Response.ClearContent()
HttpContext.Current.Response.ClearHeaders()
HttpContext.Current.Response.ContentType = "application/pdf"
HttpContext.Current.Response.TransmitFile(PDFFileName)
HttpContext.Current.Response.Flush()
HttpContext.Current.Response.Close()
File.Delete(PDFFileName)
This appears to work - is the 'WriteFile' method I've used any less efficent that the stream methods used by f3lix? Is there a method available that's more efficient than either of our solutions?
EDIT (19/03/2009) Based on comments below I've changed 'WriteFile' method to 'TransmitFile' as it appears it sends the file down to client in chunks rather than writing the entire file to the webserver's memory before sending. Further info can be found here.
Or you could just return it to the browser without writing to disk at all:
byte[] pdf;
using (MemoryStream ms = new MemoryStream()) {
Document doc = new Document();
PdfWriter.GetInstance(doc, ms);
doc.AddTitle("Document Title");
doc.Open();
doc.Add(new Paragraph("My paragraph."));
doc.Close();
pdf = ms.GetBuffer();
}
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "attachment;filename=MyDocument.pdf");
Response.OutputStream.Write(pdf, 0, pdf.Length);
The solution:
Response.TransmitFile(PDFFileName)
Response.Flush()
Response.Close()
File.Delete(PDFFileName)
Simply doesn't work for me (file never makes it to client). Reading in a byte array and calling Response.BinaryWrite isn't an option either since the file may be large. Is the only hack for this to start an asynchronous process that waits for the file to be released and then delete it?

Categories