C# Image via Memorystream error (but only second time through) - arrays

I need to be able to convert an Image to a byte Array and then back again. I've followed the google results and it seemed to be working..except it doesn't :)
I am pretty sure it has something to do with the Memory stream (I'm getting that GDI+ error) but I'm using the "using" and I thought I was cleanup up after myself.
private void button1_Click(object sender, EventArgs e)
{
System.Drawing.Image myImage = null;
SetImage(ref myImage); //This one works
SetImage(ref myImage); // This call breaks on
//the first myImage.Save line
}
private void SetImage(ref System.Drawing.Image myImage)
{
try
{
byte[] myImageAsBytes = null;
//First time through we don't have an image already so we load from a file
if (myImage == null)
{
myImage = System.Drawing.Image.FromFile("C:\\temp\\test.jpg");
}
//Convert our Image to a Byte Array.
using (System.IO.MemoryStream myMemoryStream = new System.IO.MemoryStream())
{
myImage.Save(myMemoryStream, myImage.RawFormat);
myImageAsBytes = myMemoryStream.ToArray();
}
//Just debugging
myImage.Dispose();
myImage = null;
GC.Collect();
//And convert it back to an image.
//using (System.IO.MemoryStream myMemoryStream = new System.IO.MemoryStream(myImageAsBytes))
//{
// myImage = System.Drawing.Image.FromStream(myMemoryStream);
//}
System.IO.MemoryStream myMemoryStream2 = new System.IO.MemoryStream(myImageAsBytes);
myImage = System.Drawing.Image.FromStream(myMemoryStream2);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

The documentation for Image.FromStream: https://msdn.microsoft.com/en-us/library/93z9ee4x(v=vs.110).aspx
Says:
You must keep the stream open for the lifetime of the Image.
When it comes to MemoryStreams there is actually no point in closing/disposing them. It's the only .NET class I can think of that is IDisposable that doesn't need disposing. It accidentally inherits IDisposable from System.IO.Stream, that's why.
So I would recommend that you just create your memory streams and let them be.
If you were to use Image.FromStream on a physical file, however, maybe you wont like to keep it open. What you could do in that case is to make a copy of the bitmap like this:
Bitmap safeBitmap;
using ( var stream = blah-blah-blah )
using ( var img = Image.FromStream(stream) )
safeBitmap = new Bitmap(img);

I know delphi but not C++. I think you have set myimage to null if myimage is an object, so tried to re-create. Or don't set it to null, just redraw on it or myimage.loadfromstream.
System.Drawing.Image myImage = null;
SetImage(ref myImage); //This one works
myimage :=create;
SetImage(ref myImage);

Its as simple as removing "ref" from everywhere
I suggest you read up what that key word is doing, you will then understand why its breaking it.
rather return the new image from the method.
i.e. change it from void to return the new image.
Update
below is a console version of your code basically unmodified at ALL
and it runs fine.... although i don't agree with the programming at ALL either.
Point is where are you getting an error if it seems to run with no errors
class Program
{
static void Main(string[] args)
{
Dosomething();
}
private static void Dosomething()
{
System.Drawing.Image myImage = null;
SetImage(ref myImage); //This one works
SetImage(ref myImage); // This call breaks on
}
private static void SetImage(ref System.Drawing.Image myImage)
{
try
{
byte[] myImageAsBytes = null;
//First time through we don't have an image already so we load from a file
if (myImage == null)
{
myImage = System.Drawing.Image.FromFile("C:\\temp\\test.jpg");
}
//Convert our Image to a Byte Array.
using (System.IO.MemoryStream myMemoryStream = new System.IO.MemoryStream())
{
myImage.Save(myMemoryStream, myImage.RawFormat);
myImageAsBytes = myMemoryStream.ToArray();
}
//Just debugging
myImage.Dispose();
myImage = null;
GC.Collect();
//And convert it back to an image.
//using (System.IO.MemoryStream myMemoryStream = new System.IO.MemoryStream(myImageAsBytes))
//{
// myImage = System.Drawing.Image.FromStream(myMemoryStream);
//}
System.IO.MemoryStream myMemoryStream2 = new System.IO.MemoryStream(myImageAsBytes);
myImage = System.Drawing.Image.FromStream(myMemoryStream2);
}
catch (Exception ex)
{
}
}
}

Related

Memory leak in loading an image C#

I wrote a code to load the image into a <image> control and since i need to edit and save the same image which is used in multiple places, i was in a position to modify the code to avoid Access violation error. Now i'm getting Out of memory exception.
private BitmapSource LoadImage(string path)
{
lock (_syncRoot) //lock the object so it doesn't get executed more than once at a time.
{
BitmapDecoder decoder = null;
try
{
//If the image is not found in the folder, then show the image not found.
if (!File.Exists(path) && (path != null))
{
using (var stream = new System.IO.MemoryStream())
{
if (!File.Exists(Path.GetTempPath() + "ImageNotFound.jpg"))
{
System.Drawing.Bitmap ss = Ashley.ProductData.MarketSeries.Presentation.Properties.Resources.ImageNotFound;
using (FileStream file = new FileStream(Path.GetTempPath() + "ImageNotFound.jpg", FileMode.Create, FileAccess.Write))
{
ss.Save(stream, ImageFormat.Jpeg);
stream.Position = 0;
stream.WriteTo(file);
}
}
}
path = Path.Combine(Path.GetTempPath(), "ImageNotFound.jpg");
NoImage = false;
}
else
{
if (!EnableForEdit)
NoImage = false;
else
NoImage = true;
}
if (!string.IsNullOrEmpty(path) && (!NoImage || File.Exists(path)))
{
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
{
decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
return decoder.Frames.FirstOrDefault();
}
}
else
return null;
}
catch (OutOfMemoryException ex)
{
MessageBox.Show("Insufficient memory to handle the process. Please try again later.", "Application alert");
return null;
}
catch (Exception ex)
{
// Error handling.
ShowMessages.AlertBox(ex.Message, MethodInfo.GetCurrentMethod().Name);
throw ex;
}
finally
{
decoder = null;
}
}
}
I need to know if there is any memory leak in the above code or is there any better way to load an image which match my requirements.
I had something similar to the same issue and solved by loading the image like this,
//Code:
Replace,
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
{
decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
return decoder.Frames.FirstOrDefault();
}
With,
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.UriSource = new Uri(path);
bi.EndInit();
bi.Freeze();
return bi;
if needed make the bi object null in your finally block.
That code shouldn't cause a leak. But you should consider if you want to freeze the image. x.ImageSource.Freeze();
In what scenarios does freezing wpf objects benefit performace greatly
Also if you think you have a memory leak you should get a profiler.
Red Ant's profiler has saved me dozens of times Red Ant's .Net Memory Profiler
Seriously it's worth it, they probably have a free trial or something, but it can find many sources of leaks, like timers, events not being closed properly etc. Very helpful. If you don't like them then go for another solution but if your looking for leaks Visual Studio won't help you, you need a 3rd party solution.

Download a file through the WebBrowser control

I have a WebBrowser control on a form, but for the most part it remains hidden from the user. It is there to handle a series of login and other tasks. I have to use this control because there is a ton of Javascript that handles the login. (i.e., I can't just switch to a WebClient object.)
After hopping around a bit, we end up wanting to download a PDF file. But instead of downloading, the file is displayed within the webBrowser control, which the user can not see.
How can I download the PDF instead of having it load in the browser control?
Add a SaveFileDialog control to your form, then add the following code on your WebBrowser's Navigating event:
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
if (e.Url.Segments[e.Url.Segments.Length - 1].EndsWith(".pdf"))
{
e.Cancel = true;
string filepath = null;
saveFileDialog1.FileName = e.Url.Segments[e.Url.Segments.Length - 1];
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
filepath = saveFileDialog1.FileName;
WebClient client = new WebClient();
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
client.DownloadFileAsync(e.Url, filepath);
}
}
}
//Callback function
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("File downloaded");
}
Source: http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/d338a2c8-96df-4cb0-b8be-c5fbdd7c9202
The solution I ended up using:
I did everything else as-needed to get the URL where it needed to go. Knowing that all of the login information, required settings, viewstates, etc. were stored in the cookies, I was finally able to grab the file using a hybrid of the web control to navigate then the WebClient object to actually snag the file bytes.
public byte[] GetPDF(string keyValue)
{
DoLogin();
// Ask the source to generate the PDF. The PDF doesn't
// exist on the server until you have visited this page
// at least ONCE. The PDF exists for five minutes after
// the visit, so you have to snag it pretty quick.
LoadUrl(string.Format(
"https://www.theMagicSource.com/getimage.do?&key={0}&imageoutputformat=PDF",
keyValue));
// Now that we're logged in (not shown here), and
// (hopefully) at the right location, snag the cookies.
// We can use them to download the PDF directly.
string cookies = GetCookies();
byte[] fileBytes = null;
try
{
// We are fully logged in, and by now, the PDF should
// be generated. GO GET IT!
WebClient wc = new WebClient();
wc.Headers.Add("Cookie: " + cookies);
string tmpFile = Path.GetTempFileName();
wc.DownloadFile(string.Format(
"https://www.theMagicSource.com/document?id={0}_final.PDF",
keyValue), tmpFile);
fileBytes = File.ReadAllBytes(tmpFile);
File.Delete(tmpFile);
}
catch (Exception ex)
{
// If we can't get the PDF here, then just ignore the error and return null.
throw new WebScrapePDFException(
"Could not find the specified file.", ex);
}
return fileBytes;
}
private void LoadUrl(string url)
{
InternalBrowser.Navigate(url);
// Let the browser control do what it needs to do to start
// processing the page.
Thread.Sleep(100);
// If EITHER we can't continue OR
// the web browser has not been idle for 10 consecutive seconds yet,
// then wait some more.
// ...
// ... Some stuff here to make sure the page is fully loaded and ready.
// ... Removed to reduce complexity, but you get the idea.
// ...
}
private string GetCookies()
{
if (InternalBrowser.InvokeRequired)
{
return (string)InternalBrowser.Invoke(new Func<string>(() => GetCookies()));
}
else
{
return InternalBrowser.Document.Cookie;
}
}
bool documentCompleted = false;
string getInnerText(string url)
{
documentCompleted = false;
web.Navigate(url);
while (!documentCompleted)
Application.DoEvents();
return web.Document.Body.InnerText;
}
private void web_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
documentCompleted = true;
}

How to work with webClient.OpenReadCompleted event handler?

I'm using the following code and it works nice
private void somethingButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
WebClient webClient = new WebClient();
webClient.OpenReadCompleted += webClient_OpenReadCompleted;
webClient.OpenReadAsync(new Uri(myUri));
}
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if(e.Error != null)
{
messageTextBlock.Text = e.Error.Message;
return;
}
using (Stream s=e.Result)
{
XDocument document = XDocument.Load(s);
var q1 = from c in document.Descendants("result")
select new IndeedResult
{
Title =((string)c.Element("title")).Trim(),
ResultUri = ((string)c.Element("url")).Trim(),
Date = ((string)c.Element("date")).Trim(),
};
myDataGrid.ItemsSource = q1;
}
But I want to add another WebClient, webClient2 that will do exactly the same but has different uri and different structure so I will have webClient2_OpenReadCompleted...
The problem is that finally I need to merge (or do some logic before merge) var q1 from webClient_OpenReadCompleted and var q2 from webClient2_OpenReadCompleted and then
var mergedQs = q1.Union(q2).ToList();
myDataGrid.ItemsSource = mergedQs
Is there a simple way how to do it? I don't know how to do it using those event handlers.
Good question! Did it like this
void webClient_OpenReadCompleted( object sender, OpenReadCompletedEventArgs e )
{
Stream stream = (Stream)e.Result;
BinaryReader reader = new BinaryReader( stream );
byte[] buffer = reader.ReadBytes( (int)stream.Length );
Uri uri = (Uri)e.UserState;
streams.Add( uri.AbsoluteUri, new MemoryStream( buffer ) );
}
Note the usage of UserState in order to provide a unqiue key into my streams Dictionary. Works perfectly :-) This way you can work with as many files / images / binary data as you like!
See this to see just how powerful this can be....http://www.alansimes.com/warp3dsilverlighttestpage.html

WP7 Audio Streaming Help

So I've downloaded the samples from http://archive.msdn.microsoft.com/ManagedMediaHelpers.
I've got my code working using MP3MediaStreamSource. However, I don't fully understand the code would like some explanation.
public partial class MainPage : PhoneApplicationPage
{
private static string mediaFileLocation = "http://file-here.mp3";
private static HttpWebRequest request = null;
private static Mp3MediaStreamSource mss = null;
public MainPage()
{
InitializeComponent();
}
private void RequestCallback(IAsyncResult asyncResult)
{
HttpWebResponse response = request.EndGetResponse(asyncResult) as HttpWebResponse;
Stream s = response.GetResponseStream();
mss = new Mp3MediaStreamSource(s, response.ContentLength);
Deployment.Current.Dispatcher.BeginInvoke(
() =>
{
this.wp7AudioElement.Volume = 100;
this.wp7AudioElement.SetSource(mss);
});
}
private void Button_Click(object sender, RoutedEventArgs e)
{
request = WebRequest.CreateHttp(MainPage.mediaFileLocation);
// NOTICE
// Makes this demo code easier but I wouldn't do this on a live phone as it will cause the whole
// file to download into memory at once.
//
// Instead, use the asynchronous methods and read the stream in the backgound and dispatch its
// data as needed to the ReportGetSampleCompleted call on the UIThread.
request.AllowReadStreamBuffering = true;
IAsyncResult result = request.BeginGetResponse(new AsyncCallback(this.RequestCallback), null);
}
}
It's really just the last method I need explained, I don't understand the Notice as to why it's a bad idea and how to do it differently?
Basically, it is trying to tell you that you are downloading 1 file COMPLETELY before it plays. It is not a good idea, since if the file is 10 MB, it may take a while before it completely downloads.
A better idea would be to chunk the file using Encoders, and read it in on need basis.

Get stream from java.sql.Blob in Hibernate

I'm trying to use hibernate #Entity with java.sql.Blob to store some binary data. Storing doesn't throw any exceptions (however, I'm not sure if it really stores the bytes), but reading does. Here is my test:
#Test
public void shouldStoreBlob() {
InputStream readFile = getClass().getResourceAsStream("myfile");
Blob blob = dao.createBlob(readFile, readFile.available());
Ent ent = new Ent();
ent.setBlob(blob);
em.persist(ent);
long id = ent.getId();
Ent fromDb = em.find(Ent.class, id);
//Exception is thrown from getBinaryStream()
byte[] fromDbBytes = IOUtils.toByteArray(fromDb.getBlob().getBinaryStream());
}
So it throws an exception:
java.sql.SQLException: could not reset reader
at org.hibernate.engine.jdbc.BlobProxy.getStream(BlobProxy.java:86)
at org.hibernate.engine.jdbc.BlobProxy.invoke(BlobProxy.java:108)
at $Proxy81.getBinaryStream(Unknown Source)
...
Why? Shouldn't it read bytes form DB here? And what can I do for it to work?
Try to refresh entity:
em.refresh(fromDb);
Stream will be reopened. I suspect that find(...) is closing the blob stream.
It is not at all clear how you are using JPA here, but certainly you do not need to deal with Blob data type directly if you are using JPA.
You just need to declare a field in the entity in question of #Lob somewhat like this:
#Lob
#Basic(fetch = LAZY)
#Column(name = "image")
private byte[] image;
Then, when you retrieve your entity, the bytes will be read back again in the field and you will be able to put them in a stream and do whatever you want with them.
Of course you will need a getter and setter methods in your entity to do the byte conversion. In the example above it would be somewhat like:
private Image getImage() {
Image result = null;
if (this.image != null && this.image.length > 0) {
result = new ImageIcon(this.image).getImage();
}
return result;
}
And the setter somewhat like this
private void setImage(Image source) {
BufferedImage buffered = new BufferedImage(source.getWidth(null), source.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics2D g = buffered.createGraphics();
g.drawImage(source, 0, 0, null);
g.dispose();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
ImageIO.write(buffered, "JPEG", stream);
this.image = stream.toByteArray();
}
catch (IOException e) {
assert (false); // should never happen
}
}
}
You need to set a breakpoint on method org.hibernate.engine.jdbc.BlobProxy#getStream on line stream.reset() and examine a reason of IOException:
private InputStream getStream() throws SQLException {
try {
if (needsReset) {
stream.reset(); // <---- Set breakpoint here
}
}
catch ( IOException ioe) {
throw new SQLException("could not reset reader");
}
needsReset = true;
return stream;
}
In my case the reason of IOException was in usage of org.apache.commons.io.input.AutoCloseInputStream as a source for Blob:
InputStream content = new AutoCloseInputStream(stream);
...
Ent ent = new Ent();
...
Blob blob = Hibernate.getLobCreator(getSession()).createBlob(content, file.getFileSize())
ent.setBlob(blob);
em.persist(ent);
While flushing a Session hibernate closes Inpustream content (or rather org.postgresql.jdbc2.AbstractJdbc2Statement#setBlob closes Inpustream in my case). And when AutoCloseInputStream is closed - it rases an IOException in method reset()
update
In your case you use a FileInputStream - this stream also throws an exception on reset method.
There is a problem in test case. You create blob and read it from database inside one transaction. When you create Ent, Postgres jdbc driver closes InputStream while flushing a session. When you load Ent (em.find(Ent.class, id)) - you get the same BlobProxy object, that stores already closed InputStream.
Try this:
TransactionTemplate tt;
#Test
public void shouldStoreBlob() {
final long id = tt.execute(new TransactionCallback<long>()
{
#Override
public long doInTransaction(TransactionStatus status)
{
try
{
InputStream readFile = getClass().getResourceAsStream("myfile");
Blob blob = dao.createBlob(readFile, readFile.available());
Ent ent = new Ent();
ent.setBlob(blob);
em.persist(ent);
return ent.getId();
}
catch (Exception e)
{
return 0;
}
}
});
byte[] fromStorage = tt.execute(new TransactionCallback<byte[]>()
{
#Override
public byte[] doInTransaction(TransactionStatus status)
{
Ent fromDb = em.find(Ent.class, id);
try
{
return IOUtils.toByteArray(fromDb.getBlob().getBinaryStream());
}
catch (IOException e)
{
return new byte[] {};
}
}
});
}
My current and only solution is closing the write session and opening new Hibernate session to get back the streamed data. It works. However I do not know what is the difference. I called inputStream.close(), but that was not enough.
Another way:
I tried to call free() method of blob after session.save(attachment) call too, but it throws another exception:
Exception in thread "main" java.lang.AbstractMethodError: org.hibernate.lob.SerializableBlob.free()V
at my.hibernatetest.HibernateTestBLOB.storeStreamInDatabase(HibernateTestBLOB.java:142)
at my.hibernatetest.HibernateTestBLOB.main(HibernateTestBLOB.java:60)
I am using PostgreSQL 8.4 + postgresql-8.4-702.jdbc4.jar, Hibernate 3.3.1.GA
Is the method IOUtils.toByteArray closing the input stream?

Resources