Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading Album art with TagLib sharp and then saving it to same/different file in C# causes memory error

Tags:

c#

mp3

taglib

My application lists all MP3's in a directory and when the user selects a file it loads the tag info, including album art. The art is loaded into a variable to be used when the user saves the data. The art is also loaded into a picture frame for the user to see.

// Global to all methods
System.Drawing.Image currentImage = null;

// In method onclick of the listbox showing all mp3's
TagLib.File f = new TagLib.Mpeg.AudioFile(file);
if (f.Tag.Pictures.Length > 0)
{
      TagLib.IPicture pic = f.Tag.Pictures[0];
      MemoryStream ms = new MemoryStream(pic.Data.Data);
      if (ms != null && ms.Length > 4096)
      {
           currentImage = System.Drawing.Image.FromStream(ms);
           // Load thumbnail into PictureBox
           AlbumArt.Image = currentImage.GetThumbnailImage(100,100, null, System.IntPtr.Zero);
      }
      ms.Close();
}

// Method to save album art
TagLib.Picture pic = new TagLib.Picture();
pic.Type = TagLib.PictureType.FrontCover;
pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg;
pic.Description = "Cover";
MemoryStream ms = new MemoryStream();
currentImage.Save(ms, ImageFormat.Jpeg); // <-- Error occurs on this line
ms.Position = 0;
pic.Data = TagLib.ByteVector.FromStream(ms);
f.Tag.Pictures = new TagLib.IPicture[1] { pic };
f.save();
ms.Close();

If I load the image and try to save it right away I get this "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." If I try to save currentImage as a ImageFormat.Bmp I get this "A generic error occurred in GDI+."

My save method works correctly if I load an image from a url like this:

WebRequest req = WebRequest.Create(urlToImg);
WebResponse response = req.GetResponse();
Stream stream = response.GetResponseStream();
currentImage = Image.FromStream(stream);
stream.Close();

So I'm guessing there is an issue with the way that I am loading the image into currentImage when the user selects an MP3 from the listbox.

I have found a lot of examples of loading and saving images to mp3's but no one seems to be having this issue when they try to save the are immediately after loading it.

like image 775
Ovin08 Avatar asked Oct 05 '22 23:10

Ovin08


3 Answers

Thanks for the help Jim but I couldn't really get it working using the 'using' blocks so I'm guessing the stream was still closing somewhere. I found another way to do what I was looking for by storing/saving a byte[] instead of an Image. And then just saving it using:

using (MemoryStream ms = new MemoryStream(currentImageBytes))
{
    pic.Data = TagLib.ByteVector.FromStream(ms);
    f.Tag.Pictures = new TagLib.IPicture[1] { pic };
    if (save)
        f.Save();
}
like image 139
Ovin08 Avatar answered Oct 17 '22 09:10

Ovin08


Your stream stuff should be in using blocks, which will dispose of your goods automagically and close them too. Not terribly important, but easier to manage.

Your generic GDI+ error is likely because you are trying to perform an operation or call a method on a file for which the stream is already closed.

Check it out...

like image 29
J.Wells Avatar answered Oct 17 '22 08:10

J.Wells


your method isn't really false, only a few things had to be changed:

// Method to save album art
TagLib.Picture pic = new TagLib.Picture();
pic.Type = TagLib.PictureType.FrontCover;
pic.MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg;
pic.Description = "Cover";
MemoryStream ms = new MemoryStream();
currentImage.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); // <-- Error doesn't occur anymore
ms.Position = 0;
pic.Data = TagLib.ByteVector.FromStream(ms);
f.Tag.Pictures = new TagLib.IPicture[1] { pic };
f.save();
ms.Close();
like image 1
cramopy Avatar answered Oct 17 '22 09:10

cramopy