Load PDF from memory into telerik:RadPdfViewer - c#

I have a PDF file stored in a database as a byte array.
I'm reading the PDF byte array from my database back into my application.
Now, I'm trying to display the PDF with the RadPdfViewer but it is not working.
Here is my code:
byte[] pdfAsByteArray= File.ReadAllBytes(#"C:\Users\Username\Desktop\Testfile.pdf");
//Save "pdfAsByteArray" into database
//...
//Load pdf from database into byte[] variable "pdfAsByteArray"
using (var memoryStream = new MemoryStream(pdfAsByteArray))
{
this.PdfViewer.DocumentSource = new PdfDocumentSource(memoryStream);
}
when I execute the application I just get an empty PdfViewer.
Question: How do I set the DocumentSource the right way?
Question: How do I dispose the stream? (note that using doesn't works)
Note: I wan't to avoid things like writing a temp file to disk
Edit:
I figured it out but I am not completely satisfied with this solution:
Not working:
using (var memoryStream = new MemoryStream(pdfAsByteArray))
{
this.PdfViewer.DocumentSource = new PdfDocumentSource(memoryStream);
}
Working:
var memoryStream = new MemoryStream(pdfAsByteArray);
this.PdfViewer.DocumentSource = new PdfDocumentSource(memoryStream);
I don't know how teleriks RadPdfViewer component works but I wan't to dispose the Stream.

From the Telerik documentation (particularly with regards to the "Caution" stating that this loading is done asynchronously), I believe this should work while still providing you a way to close the stream (not as cleanly as if you were able to use a using block, but still better than leaving it open):
//class variable
private MemoryStream _stream;
_stream = new MemoryStream(pdfAsByteArray);
var docSource = new PdfDocumentSource(memoryStream);
docSource.Loaded += (sender, args) => { if (_stream != null) _stream.Dispose();};
this.PdfViewer.DocumentSource = docSource;
I did this free-hand and don't have access to the Telerik API so the exact details of the Loaded event are not available to me.
EDIT
Here's the relevant details from documentation I found (emphasis mine):
The PdfDocumentSource loads the document asynchronously. If you want
to obtain a reference to the DocumentSource after you have imported a
document, you should use the Loaded event of the PdfDocumentSource
object to obtain the loaded document. This is also a convenient method
that can be used to close the stream if you are loading a PDF from a
stream.

You need to implement PdfDocumentSource Loaded event. This is when the stream gets loaded and used up, and can be closed / disposed at that time.

Another method I've used is:
this.PdfViewer.PdfjsProcessingSettings.FileSettings.Data = Convert.ToBase64String(File.ReadAllBytes(#"C:\Users\Username\Desktop\Testfile.pdf"));

Related

How can i deleted a file that is using by IronOCR process in winform?

Sorry for my bad English.
I would like to extract text from a image then delete it. Can you show me how to stop Ocr process after i extracted text from file to delete it?
this is my code
Image image = Image.FromFile(#"C:\Users\Admin\Desktop\testtool.png");
var ocr = new AutoOcr();
result_text.Text = ocr.Read(image).ToString();
string textforClipboard = result_text.Text.Replace("\n", Environment.NewLine);
Clipboard.Clear();
Clipboard.SetText(textforClipboard);
//File.Delete(#"C:\Users\Admin\Desktop\testtool.png");
This is the error:
System.IO.IOException: 'The process cannot access the file 'C:\Users\Admin\Desktop\testtool.png' because it is being used by another process.'
An image is Disposable. Before you delete files that contains Images, you should Dispose all Images that are extract from the file.
Make it good practice: always consider using when you are dealing with an IDisposable. This way, you can be certain that whatever happens: the object is disposed when you don't need it anymore, even after exceptions.
using (Image image = Image.FromFile(#"C:\Users\Admin\Desktop\testtool.png"))
{
// do with the image what you need to do
// Is AutoOcr also IDisposable?
using (var autoOcr = new AutoOcr())
{
...
}
// object autoOcr is disposed
}
// object image is disposed. You can delete the file that contains this image
System.IO.File.Delete(...);

How to dynamically generate file for download in Razor Pages

I want to add a button that will download a dynamically generated CSV file.
I think I need to use FileStreamResult (or possibly FileContentResult) but I have been unable to find an example that shows how to do this.
I've seen examples that create a physical file, and then download that. But my ideal solution would write directly to the response stream, which would be far more efficient than creating a file or first building the string in memory.
Has anyone seen an example of dynamically generating a file for download in Razor Pages (not MVC)?
So here's what I came up with.
Markup:
<a class="btn btn-success" asp-page-handler="DownloadCsv">
Download CSV
</a>
Handler:
public IActionResult OnGetDownloadCsv()
{
using MemoryStream memoryStream = new MemoryStream();
using CsvWriter writer = new CsvWriter(memoryStream);
// Write to memoryStream using SoftCircuits.CsvParser
writer.Flush(); // This is important!
FileContentResult result = new FileContentResult(memoryStream.GetBuffer(), "text/csv")
{
FileDownloadName = "Filename.csv""
};
return result;
}
This code works but I wish it used memory more efficiently. As is, it writes the entire file contents to memory, and then copies that memory to the result. So a large file would exist twice in memory before anything is written to the response stream. I was curious about FileStreamResult but wasn't able to get that working.
If someone can improve on this, I'd gladly mark your answer as the accepted one.
UPDATE:
So I realized I can adapt the code above to use FileStreamResult by replacing the last block with this:
memoryStream.Seek(0, SeekOrigin.Begin);
FileStreamResult result = new FileStreamResult(memoryStream, "text/csv")
{
FileDownloadName = "Filename.csv"
};
return result;
This works almost the same except that, instead of calling memoryStream.GetBuffer() to copy all the bytes, it just passes the memory stream object. This is an improvement as I am not needlessly copying the bytes.
However, the downside is that I have to remove my two using statements or else I'll get an exception:
ObjectDisposedException: Cannot access a closed Stream.
Looks like it's a trade off between copying the bytes an extra time or not cleaning up my streams and CSV writer.
In the end, I'm able to prevent the CSV writer from closing the stream when it's disposed, and since MemoryStream does not have unmanaged resources there should be no harm in leaving it open.

Image opened from stream is different from opened from file

I have 2 pieces of sample codes, I try to do the same thing that update property items back to image and save it under a different file.
Code 1
Image image;
using (FileStream stream = new FileStream(this.fileName, FileMode.Open)) {
image = Image.FromStream(stream);
foreach (var property in this.propItems) {
image.SetPropertyItem(property);
}
}
image.Save(#"D:\Temp\1.jpg");
image.Dispose();
Code 2
using (Image image = new Bitmap(this.fileName)) {
foreach (var property in this.propItems) {
image.SetPropertyItem(property);
}
image.Save(#"D:\Temp\1.jpg");
}
The only difference is that how I opened the file. If I run the first piece of code I got exception message
System.Runtime.InteropServices.ExternalException was unhandled
HResult=-2147467259 Message=A generic error occurred in GDI+.
Source=System.Drawing ErrorCode=-2147467259
My 2nd piece of code just runs fine, I can get proper output. What is the difference here?
This is by design, the MSDN article for Image.FromStream() sternly warns about this. Once you close the stream, the image is no longer usable. And trying to save it like you do is very likely, but not guaranteed, to throw an exception when it tries to retrieve pixel data from a closed stream.
A key property of the Image class is that it is lazy, not unlike many .NET classes, it won't access the stream data until necessary. And it isn't necessary until the pixel data is actually used, that happens in the Save() call in your snippet. Kaboom when it can no longer read it.
You can fix your first snippet by moving the Save() call inside the using statement:
using (var stream = new FileStream(this.fileName, FileMode.Open))
using (var image = Image.FromStream(stream) {
foreach (var property in this.propItems) {
image.SetPropertyItem(property);
}
image.Save(#"D:\Temp\1.jpg");
}
No point in using a FileStream anymore. Do note that the file that you save the image to cannot be the same file that you read the image from. Some hint that you tried to work around that problem. Using a MemoryStream is a common technique to avoid the lock on the file.
Also note another bug in your code, you save the file with the .jpg extension but it is actually a PNG. You cannot omit the ImageFormat argument if you want a JPEG.

Read audio file to stream with MediaPlayer (WPF)

I use MediaPlayer to play audio files
var mediaPlayer = new MediaPlayer();
mediaPlayer.Open(new Uri(s));
mediaPlayer.Play();
Sometimes I need to delete files that MediaPlayer is still playing.
I guess I have somehow read file to stream to be get free access to it in order to delete it. I mean i sthere way to read file to stream or I have to create some temp. file to play and in this case I can delete the original one or there are other options?
How to implement it?
Thank you!
Actually, when you call MediaPlayer.Open it reads in the file via a stream automatically. The problem is that the stream is still open when you try to delete the file.
MediaPlayer has a .Close method on it. Calling this will close the stream that's reading in the file.
here's the documentation on the MediaPlayer class so you can see what other methods are available to use: http://msdn.microsoft.com/en-us/library/system.windows.media.mediaplayer.aspx
EDIT: If you don't mind that the player stops playback when you call Close then you can just Close & then delete your file. If you do need playback to continue then you'll need a different approach.
If you're using Silverlight then you can just load the stream directly into a MediaElement:
var bytes = File.ReadAllBytes(#"c:\yourfile.ext");
var mStream = new MemoryStream(bytes);
mediaElement1.SetSource(mStream);
Sadly, WPF does not have the same stream support. I attempted to get a Uri for the MemoryStream by writing the stream into the resource pack. Though, i couldn't get it to playback correctly in my testing. I'll include my source that i had just in case you want to fiddle with it and maybe get it to work:
var bytes = File.ReadAllBytes(#"C:\Bill\TestWaveFiles\14043.wav");
MemoryStream packStream = new MemoryStream()
Package pack = Package.Open(packStream, FileMode.Create, FileAccess.ReadWrite);
Uri packUri = new Uri("bla:");
PackageStore.AddPackage(packUri, pack);
Uri packPartUri = new Uri("/MemoryResource", UriKind.Relative);
PackagePart packPart = pack.CreatePart(packPartUri, "Media/MemoryResource");
packPart.GetStream().Write(bytes, 0, bytes.Length);
var inMemoryUri = PackUriHelper.Create(packUri, packPart.Uri);
mediaElement1.LoadedBehavior = MediaState.Manual;
mediaElement1.Source = inMemoryUri;
mediaElement1.Play();
Another option is to simply make a copy of the file before you open it. that way you can always delete the original. Though, you could also just "mark" the file to be deleted. When the user is done playing the the file then you could close & delete it.
One additional option is to use a 3rd party library called BoxedApp. It seemingly will allow you to have a "Virtual File" that contains a memory stream. You could then get a Uri that points to this virtual file and load it into the media player. Look at this answer by
user1108125 to see how to use this BoxedApp library (which i've never used). https://stackoverflow.com/a/8587166/1721136

Image.FromStream(PostedFile.InputStream) Fails. (Parameter is not valid.) (AsyncFileUpload))

I'm using an AsyncFileUpload (AJAX Toolkit) to upload images.
I have a Button which handle the image resizing.
This have worked fine for some time, but not anymore...
protected void BtnUploadImage_Click(object sender, EventArgs e)
{
var imageFileNameRegEx = new Regex(#"(.*?)\.(jpg|jpeg|png|gif)$",
RegexOptions.IgnoreCase);
if (!AsyncFileUpload1.HasFile ||
!imageFileNameRegEx.IsMatch(AsyncFileUpload1.FileName))
{
AsyncFileUpload1.FailedValidation = true;
ErrorLabel.Visible = true;
return;
}
ErrorLabel.Visible = false;
var file = AsyncFileUpload1.PostedFile.InputStream;
var img = Image.FromStream(file, false, false);
...
}
Another thing which I find weird: If I try a image which is smaller than 80kb it works..!
We have tried to restart the server, but no change.
Same code runs fine on my machine. (heard that before ?? :) )
I also tried to save the file on the server, then to get the file trough Image.FromFile(), but then I get "Cannot access a closed file."
How to resolve this ?
I would make sure the stream is positioned at the start:
var file = AsyncFileUpload1.FileContent;
file.Seek(0, SeekOrigin.Begin);
var img = Image.FromFile(file);
Second thing to check: the requestLengthDiskThreshold setting. Unless specified this setting has a default of ... yes, 80 KB.
Note: imo there should be no overall difference whether you use Image to read the file stream directly or if you use an intermediate MemoryStream (other than the fact that in the latter case you actually loads the entire file into memory twice). Either way the original file stream will be read from, thus stream position, CAS rights, file permissions, etc still applies.
Note2: and yes, by all means make sure those resources are disposed properly :)
This is correct, it will not work. The problem is that you are crossing a managed/unmanaged boundary, I recently encountered the same. Other problems are that the stream is not directly there and the Image.FromStream has no idea how to deal with it.
The solution is quite straightforward: read everything from PostedFile into a MemoryStream (just use new MemoryStream()) and use the MemoryStream with the Image.FromStream. This will solve your problem.
Make sure to make proper use of using when you work with Image, Graphics and Streams. All of them implement the IDisposable and in an ASP.NET environment, not using using blocks properly, can and will lead to increased memory usage and other nasty side effect on the long run (and ASP.NET apps do run very long!).
The solution should look something like this:
using(Stream memstr = new MemoryStream())
{
// copy to a memory stream
Stream uploadStream = AsyncFileUpload1.PostedFile.InputStream;
byte[] all = new byte[uploadStream.Length];
uploadStream.Read(all, 0, uploadStream.Length);
memstr.Write(all, 0, uploadStream.Length);
memstr.Seek(0, SeekOrigin.Begin);
using(Graphics g = Graphics.FromStream(memstr))
{
// do your img manipulation, or Save it.
}
}
Update: the crossing managed boundary issue only occurs in the reverse (using Response stream), it seems, not with Upload streams, but I'm not entirely sure.

Categories