Create thumbnails of images and store them in cache
I have a WPF application that has a list box of images. Right now I am using BitmapImage
and BitmapCacheOption.OnLoad
to load the images.
The problem is that when there are a lot of images, the RAM usage sky rockets due to the size o开发者_Python百科f the images.
How can I create thumbnail images of the originals to display in the list box?
It probably has to be cached since the image files in the directory may be deleted or modified while the application is running.
The problem is that when there are a lot of images, the RAM usage sky rockets due to the size of the images.
C# example from: http://msdn.microsoft.com/en-us/library/ms748873.aspx
// Create source
BitmapImage myBitmapImage = new BitmapImage();
// BitmapImage.UriSource must be in a BeginInit/EndInit block
myBitmapImage.BeginInit();
myBitmapImage.UriSource = new Uri(@"C:\Water Lilies.jpg");
// To save significant application memory, set the DecodePixelWidth or
// DecodePixelHeight of the BitmapImage value of the image source to the desired
// height or width of the rendered image. If you don't do this, the application will
// cache the image as though it were rendered as its normal size rather then just
// the size that is displayed.
// Note: In order to preserve aspect ratio, set DecodePixelWidth
// or DecodePixelHeight but not both.
myBitmapImage.DecodePixelWidth = 200;
myBitmapImage.EndInit();
//
//when you are ready to render the BitmapImage, do:
imageThumb.Source = myBitmapImage;
Note the DecodePixelWidth and DecodePixelHeight properties to cache the image at the desired reduced pixel size. Use both to stretch the image to fit the thumbnail size.
You can create decent thumb bitmaps using InterpolationMode.HighQualityBicubic
Bitmap bitmap = ...
Bitmap thumbBitmap = new System.Drawing.Bitmap(thumbWidth, thumbHeight);
using (Graphics g = Graphics.FromImage(thumbBitmap))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(bitmap, 0, 0, thumbWidth, thumbHeight);
}
If you are creating the thumbs in a background thread just save them into a memory stream which you can then lazily use to create the BitmapImage
when requested:
_ms = new MemoryStream();
thumbBitmap.Save(_ms, ImageFormat.Png);
_ms.Position = 0;
ImageLoaded = true;
//thumb image property of this class, use in binding
public BitmapImage ThumbImage
{
get
{
if (_thumbImage == null && ImageLoaded)
{
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = _ms;
bi.EndInit();
_thumbImage = bi;
}
return _thumbImage;
}
}
Here is a method I wrote not too long ago that may help you.
byte[] IImageResizer.CreateThumbnailBytes(byte[] originalImage)
{
Image thumbnail = null;
Image tempImage = Image.FromStream(new MemoryStream(originalImage));
int desiredWidth = 160;
int newPixelWidth = tempImage.Width;
int newPixelHeight = tempImage.Height;
if (newPixelWidth > desiredWidth)
{
float resizePercent = ((float)desiredWidth / (float)tempImage.Width);
newPixelWidth = (int)(tempImage.Width * resizePercent) + 1;
newPixelHeight = (int)(tempImage.Height * resizePercent) + 1;
}
Bitmap bitmap = new Bitmap(newPixelWidth, newPixelHeight);
using (Graphics graphics = Graphics.FromImage((Image)bitmap))
{
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.DrawImage(tempImage, 0, 0, newPixelWidth, newPixelHeight);
}
thumbnail = (Image)bitmap;
MemoryStream ms = new MemoryStream();
thumbnail.Save(ms, ImageFormat.Jpeg);
return ms.ToArray();
}
I pass in the original images binary, and resize the image to be around roughly 160px.
Hope it helps!
After checking MSDN I don't see any straightforward way to do this, but perhaps you could just sample the image every so many pixels and write the data to a new image, and then clean up the full size one.
精彩评论