从BitmapMetadata获取所需数据后,如何处理位图/可用内存?

时间:2016-03-31 06:44:18

标签: c# image bitmap

我正在开发一个解决方案,它需要支持查询许多jpeg文件元数据才能获得Comment - 和DateTaken - 属性。但是我总是在大约20个文件后得到一个OutOfMemoryException。因此,在将Comment - 和DateTaken - 值分配给两个字符串后,我需要知道如何释放内存。目前我正在使用JpegBitmapDecoder并通过解码器的实例化将BitmapCacheOption设置为OnLoad。我想,这就是我得到异常的原因,但我不知道如何让它变得更好,因为我第一次使用Images / Bitmaps工作。

在一个单独的表单中,我有一个BackgroundWorker,在其中调用mainform的方法。在该方法中,调用两个方法,以从文件中获取Comment和DateTaken。为了在这两个方法中获取文件的元数据,调用另一个方法,在该方法中,我在行中获得异常,我实例化了JpegBitmapDecoder

以下是方法:

formPleaseWait

private void bgwLoadPhotos_DoWork(object sender, DoWorkEventArgs e)
 //BackgroundWorker in formPleaseWait
    {
        int filesCount;
        FileInfo[] files;

        FolderBrowserDialog browseFolder = (FolderBrowserDialog)e.Argument;

        files = selectedFolder.GetFiles("*.jpg");
        filesCount = files.Count();

        foreach (FileInfo file in selectedFolder.GetFiles("*.jpg"))
        {
            try
            {
                Photo photo = formMain.CreatePhotoObject(file);
        //the method in the mainform is called

                loadedPhotos.Add(photo);
                loadProgress++;

                if (loadProgress == filesCount)
                {
                    loadProgress = 100;
                }
            }
            catch (OutOfMemoryException)
            {
                MessageBox.Show(
                     MessageBoxButtons.OK, MessageBoxIcon.Information);

                loadProgress = 100;
                break;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }

formMain

    public Photo CreatePhotoObject(FileInfo file)
    {   

        int year = 0;
        string comment = GetPhotoComment(file);
        string dateString = GetPhotoDate(file);
        //the two methods to get comment and date are called
        string filename = file.Name;
        string path = selectedFolder + @"\" + filename;            
        string photoname = Path.GetFileNameWithoutExtension(file.FullName);
        DateTime date = new DateTime();

        if(dateString != null)
        {
            date = DateTime.Parse(dateString).Date;
            dateString = date.ToShortDateString();
            year = date.Year;
        }

        return new Photo(year, comment, filename, photoname, dateString);
    }

    private string GetPhotoComment(FileInfo file)
    {
        BitmapMetadata metadata = GetMetadata(file);

        return metadata.Comment;
    }

    private string GetPhotoDate(FileInfo file)
    {
        BitmapMetadata metadata = GetMetadata(file);

        return metadata.DateTaken;
    }

    private BitmapMetadata GetMetadata(FileInfo file)
    {
        BitmapFrame frame;
        BitmapMetadata metadata;
        JpegBitmapDecoder decoder;

        string filepath = file.FullName;

        using (Stream fileStreamIn = File.Open(filepath, FileMode.Open,  
               FileAccess.Read, FileShare.Read))
        {
            decoder = new JpegBitmapDecoder(fileStreamIn, 
                             BitmapCreateOptions.PreservePixelFormat,
                             BitmapCacheOption.OnLoad);
            //Here I get the exception
        }

        frame = decoder.Frames[0];

        return metadata = (BitmapMetadata)frame.Metadata;
    }

2 个答案:

答案 0 :(得分:1)

我找到了解决方案。

我创建了一个包含所需方法的类:

 public class PhotoFactory
{
    [...]

    public Photo CreatePhotoObject(FileInfo file)
    {
        string comment;
        string dateString;
        DateTime date;

        int year = 0;
        string filename = file.FullName;
        string path = selectedFolder + @"\" + filename;
        string photoname = file.Name;

        GetCommentDate(file.FullName, out comment, out dateString);

        if (dateString != null)
        {
            date = DateTime.Parse(dateString).Date;
            dateString = date.ToShortDateString();
            year = date.Year;
        }

        return new Photo(year, comment, filename, photoname, dateString);
    }

    private void GetCommentDate(string filepath, out string comment, out 
                                string dateString)
    {
        using (FileStream fileIn = new FileStream(filepath, FileMode.Open, 
               FileAccess.Read, FileShare.Read))
        {
            BitmapSource source = BitmapFrame.Create(fileIn);
            BitmapMetadata metadata = (BitmapMetadata)source.Metadata;

            comment = metadata.Comment;
            dateString = metadata.DateTaken;
        }
    }
}

当我加载100个文件时,我没有得到OutOfMemoryException。

如果有人有改进建议或其他注释,我将很高兴听到他们。

答案 1 :(得分:0)

首先,不要两次加载元数据。您的GetPhotoCommentGetPhotoDate方法应该采用BitmapMetadata而不是FileInfo

然后,您应该尝试使用BitmapCacheOption.None。有关不同的可用值,请参阅the documentation

最后,您向我们展示的formMain中的所有方法都应该放在他们自己的类中。它们没有理由在表单类中,它们与用户界面无关。我会通过以下方式解决这个问题:

  1. 使用PhotoFactory作为参数的构造函数创建一个类selectedFolder
  2. formMain中创建该类的实例,并将其传递给formPleaseWait
  3. 使用该实例代替formMain