What's a good way to store project related pictures? - c#

I'm trying to get an array of PictureBox to display a list of pictures (in png file format).
I tried to use the .NET ImageList control but it insists in re-sizing my pictures. It also does not support transparent background of those png files.
I also tried to use the Assembly to retrieve my files like this:
_imageStream = _assembly.GetManifestResourceStream("MyNamespace.MyImage.png");
but the code does not return me any resource files nor does it throw any run-time error.
My question is, is there any other ways to do this? Or better yet, can I somehow make the ImageList control to NOT alter my picture? Thanks.

You can try something like this although I am not sure that this is the best one or not:-
Assembly ambly = Assembly.LoadFile(pathToDll);
or
BitMap bitMap;
// where "ns" is the default namespace of the resource project
using (Stream resourceStream = ambly.GetManifestResourceSream("ns.image.jpg"))
{
bitMap = BitMap.FromStream(resourceStream);
}
An example:-
interface IThemeResourceProvider
{
Stream LoadBigLogo();
Stream LoadSmallLogo();
}
Then implement that interface in your resource library
public class ThemeResourceProvider : IThemeResourceProvider
{
public Stream LoadBigLogo()
{
Assembly ambly = Assembly.GetExecutingAssembly();
return ambly.GetManifestResourceStream("namespace.image.jpg");
}
(...)
}
Finally, instead of loading the resource directly in your main application, you instantiate the IThemeResourceProvider found in the resource library
Assembly assembly = Assembly.LoadFile(pathToDll);
var results = from type in assembly.GetTypes()
where typeof(IThemeResourceProvider).IsAssignableFrom(type)
select type;
Now you have an IEnumerable in that list. Typically, you'd only have one, but using this approach you could also host multiple sets of resources, and implement multiple IThemeResourceProviders in the same resource dll. You could e.g. identify each IThemeResourceProvider with a name, either as a property, or using a custom [Attribute] decoration on your various implementations. I'll leave the rest up to you to figure out.
But here's how to instantiate the IThemeResourceProviders in your list
foreach (var providerType in results)
{
var constructorInfo = providerType.GetConstructor(Type.EmptyTypes);
IThemeResourceProvider provider = constructorInfo.Invoke(null);
}
And finally, using one of these providers to get a bitmap:
BitMap bitMap;
using (Stream resourceStream = provider.LoadBigLogo())
{
bitMap = BitMap.FromStream(resourceStream);
}

This is the code that I got from someone and it's worked well for me!
private void SetImage(PictureBox pb) {
try {
Image img = pb.Image;
Size imgSize = GenerateImageDimensions( img.Width, img.Height, pb.Width, pb.Height );
Bitmap finalImg = new Bitmap( img, imgSize.Width, imgSize.Height );
Graphics gfx = Graphics.FromImage( img );
gfx.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
pb.Image = null;
pb.SizeMode = PictureBoxSizeMode.AutoSize;
pb.Image = finalImg;
} catch(Exception ex) {
}
}
public Size GenerateImageDimensions(int currW, int currH, int destW, int destH) {
//double to hold the final multiplier to use when scaling the image
double multiplier = 0;
//string for holding layout
string layout;
//determine if it's Portrait or Landscape
if(currH > currW) layout = "portrait";
else layout = "landscape";
switch(layout.ToLower()) {
case "portrait":
//calculate multiplier on heights
if(destH > destW) {
multiplier = (double) destW / (double) currW;
} else {
multiplier = (double) destH / (double) currH;
}
break;
case "landscape":
//calculate multiplier on widths
if(destH > destW) {
multiplier = (double) destW / (double) currW;
} else {
multiplier = (double) destH / (double) currH;
}
break;
}
//return the new image dimensions
return new Size( (int) (currW * multiplier), (int) (currH * multiplier) );
}
EDIT: Full disclosure all my images are jpg so I have no clue how this will hand transparent backgrounds.
EDIT TWO: Also you will need to adjust the pb.SizeMode to fit your needs. The way I did it was to set a max size for the PictureBox and it's worked well.

Related

C# - Updating pictureBox.Image during Runtime causes Error

i am trying to change the pictureBox.Image during Runtime. I have several Model classes with a picture stored, whenever i click on a MenuStripItem i call the method "ChangePictureBoxImages". Till then there is no error (the pB is invisible!) but once i call the method to make the pB visible i get an Error. The Error code: "An unhandled exception of type 'System.ArgumentException' occurred in System.Drawing.dll".
Research said i should dispose the picturebox and set it to "null", however this does NOT help.
My Code:
using (Image current = BitmapManipulator.EvaluateMesurement(CSV_Name1, max_Rows, max_Col, var.TopImage, var.BitmapToManipulate, pB_ColourScale_Evaluation.Image, var.BitmapToManipulate, var.Filepath, var.FoldID))
{
var.LastEvaluationImage = current;
BitmapManipulator.CombineImagesAndSaveThem_Evaluation(var.TopImage, var.BitmapToManipulate, pB_ColourScale_Evaluation.Image, var.Filepath, var.FoldID); //saves the Files as jpg
if (var.CurrentlyShownToUser) //checks if the MenuStripItem is the active one
{
if (var.LastEvaluationImage == null) { MessageBox.Show("the image is null");} //only for debugging purpose -> does never call
ChangePictureBoxImages();
}
}
and the ChangePictureBoxImages():
public void ChangePictureBoxImages()
{
foreach (Fold fold in FoldExisting)
{
if (fold.FoldID == LastSelectedMenuStripItem_Name) //the clicked item is the last Selected MenuStripItem
{
if (fold.LastEvaluationImage != null)
{
Debug.WriteLine(pB_Evaluation_Bottom.Image.ToString() + " " + fold.LastEvaluationImage.ToString());
pB_Evaluation_Bottom.Image = fold.LastEvaluationImage;
}
pB_Evaluation_Top.Image = fold.TopImage;
}
}
}
There is no error till then, the error appears once i call "pB_Evaluation_Bottom.visible = true". (or if i called the visible method first first the error appears upon changing the Image!) The error also appears upon clicking 2 times on the MenuStripItem. I load the picture from the Class Fold as following:
This will set an image in the fold class, this image will then be manipulated and stored in LastEvaluationImage
private void setTheImages(string PictureToManipulate, string PathToTopImage)
{
try
{
this.BitmapToManipulate_intern = (Image)Image.FromFile(#PictureToManipulate, true);
this.TopImage_intern = (Image)Image.FromFile(#PathToTopImage, true);
}
catch (ArgumentNullException ex)
{
Debug.WriteLine("The BitMap for the manipulation process and the top image is not created.");
}
}
and the LastEvaluationImage where the last picture is stored -> this will be called to be the new pb.Image
private Image LastEvaluationImage_intern;
public Image LastEvaluationImage
{
get
{
return this.LastEvaluationImage_intern;
}
set
{
if (LastEvaluationImage_intern != null) { LastEvaluationImage_intern.Dispose(); LastEvaluationImage_intern = null; }
this.LastEvaluationImage_intern = value;
this.LastEvaluationTime_intern = DateTime.Now;
}
}
I know this is a little complex, but i hope someone can help me.
THANKS IN ADVANCE!
UPDATE: The Error must be in the following Code:
The BitmapManipulator.EvaluateMeasurement Code :
public Image EvaluateMesurement(double[][] MeasuredValues, int max_Rows, int max_Col, Image pB_Evaluation_Top, Image pB_Evaluation_Bottom, Image pB_EvaluationColourScale, Image ManipulatedBitmap, string PathMeasurementFiles, string Foldname)
{
using (Bitmap bitmap = new Bitmap(ManipulatedBitmap))
{
// the data array sizes:
int number_nio = 0;
int number_total = 0;
List<FileInfo> LastFiles;
int got_number_for_trends = Properties.Settings.Default.TrendNumber;
SolidBrush myBrush = new SolidBrush(red);
using (Graphics g = Graphics.FromImage(bitmap))
{
Random rnd = new Random(8);
int[,] data = new int[max_Col, max_Rows];
// scale the tile size:
float sx = 1f * bitmap.Width / data.GetLength(0);
float sy = 1f * bitmap.Height / data.GetLength(1);
LastFiles = FM.GetLastFiles_Trend(ref got_number_for_trends, PathMeasurementFiles);
double[][] CSV_Statistiken = FM.LastFilesToCSV(got_number_for_trends, true, LastFiles, PathMeasurementFiles);
for (int x = 0; x < max_Col; x++)
{
for (int y = max_Rows - 1; y >= 0; y--)
{
number_total++;
RectangleF r = new RectangleF(x * sx, y * sy, sx, sy);
if (MeasuredValues[y][x] < Properties.Settings.Default.Threshhold)
{
number_nio++;
if (CSV_Statistiken[y][x] == Properties.Settings.Default.TrendNumber)
{
myBrush.Color = Color.FromArgb(150, black);
g.FillRectangle(myBrush, r);
}
else
{
myBrush.Color = Color.FromArgb(150, red);
g.FillRectangle(myBrush, r);
}
}
else
{
myBrush.Color = Color.FromArgb(150, green);
g.FillRectangle(myBrush, r);
}
}
}
}
return bitmap;
}
}
This returned bitmap will be stored in fold.LastEvaluationImage as following:
using (Image current = BitmapManipulator.EvaluateMesurement(CSV_Name1, max_Rows, max_Col, var.TopImage, var.BitmapToManipulate, pB_ColourScale_Evaluation.Image, var.BitmapToManipulate, var.Filepath, var.FoldID))
{
var.LastEvaluationImage = current;
}
You're returning a disposed bitmap. It shouldn't be surprising you can't draw something that no longer exists :)
The using (bitmap) is the last thing you want in this case. The bitmap must survive longer than the scope of the using. And the using (current) in the caller has the same problem - you're again disposing the image way too early. You can only dispose it when it's clear that it isn't going to be used ever again - e.g. when you replace it with a new image.
To elaborate, using does nothing but call Dispose when you leave its scope. In the case of Bitmap (which is just a "thin" wrapper around a GDI bitmap), this releases the memory where the actual image data is stored. There isn't anything interesting left, so there's nothing to draw (and you'd basically be calling DrawBitmap(NULL) as far as GDI is concerned).

Make sure that an image larger than 5 mb is reduced below that size c#

I'm using ImageProcessor to reduce the resolution or quality of an image, but I'm don't know how to make sure that the image resultant size it's below 5 megabytes. I tried setting the image dimensions to 3840-2160 but I want to use a better option.
Here it's my code:
private static byte[] redimensionImage(ref byte[] photoBytes)
{
var byteCuantity = ConvertBytesToMegabytes(photoBytes.Count());
ISupportedImageFormat format = new JpegFormat();
using (MemoryStream inStream = new MemoryStream(photoBytes))
{
using (MemoryStream outStream = new MemoryStream())
{
// Initialize the ImageFactory using the overload to preserve EXIF metadata.
using (ImageFactory imageFactory = new ImageFactory(preserveExifData: true))
{
// Load, resize, set the format and quality and save an image.
using (var imageProcessor = imageFactory.Load(inStream))
{
var originalHeight = imageProcessor.Image.Size.Height;
var originalWidth = imageProcessor.Image.Size.Width;
//calculate aspect ratio
var aspect = originalWidth / (float)originalHeight;
int newWidth, newHeight;
var dimenssionTooSmall = false;
if (originalWidth <= originalHeight && originalWidth < 100)
{
//calculate new dimensions based on aspect ratio
newHeight = (int)(100 / aspect);
var resizeLayer = new ResizeLayer(new Size(100, newHeight), ResizeMode.Min);
imageProcessor.Resize(resizeLayer);
dimenssionTooSmall = true;
}
else if (originalHeight < originalWidth && originalHeight < 100)
{
//calculate new dimensions based on aspect ratio
newWidth = (int)(100 / aspect);
var resizeLayer = new ResizeLayer(new Size(newWidth, 100), ResizeMode.Min);
imageProcessor.Resize(resizeLayer);
dimenssionTooSmall = true;
}
if (byteCuantity > 1 || dimenssionTooSmall)
{
//format.Quality = 6;
imageProcessor.Resize(new ResizeLayer(new Size(3840, 2160), ResizeMode.Min));
imageProcessor.Format(format);
imageProcessor.Save(outStream);
return outStream.ToArray();
}
else
{
return inStream.ToArray();
}
}
}
}
}
}
Thanks and regards.
Unfortunately there's no way you can really do this without reprocessing unless you're saving as bitmap.
When you save an image there are many compression processes that take place to store the image in each individual format (except bitmap which doesn't compress the image). Without actually going through the process itself you can't predict the file size.
You could potentially create your own lookup tables to act as a guideline by resizing a large sample of images in different formats and collecting the output sizes to give you a rough estimate for future processing.

Error saving resized image

I have the following code
int oswidth = 0;
int osheight = 0;
if (comboBox3.SelectedIndex == 0)
{
oswidth = Convert.ToInt32(textBox5.Text.ToString());
osheight = Convert.ToInt32(textBox6.Text.ToString());
}
else if (comboBox3.SelectedIndex == 1)
{
oswidth = 38 * Convert.ToInt32(textBox5.Text.ToString());
osheight = 38 * Convert.ToInt32(textBox6.Text.ToString());
}
Bitmap oldimg = new Bitmap(pictureBox3.Image);
Bitmap objBitmap = new Bitmap(oldimg, new Size(oswidth, osheight));
objBitmap.Save(pictureBox3.ImageLocation.ToString(), ImageFormat.Jpeg);
The problem is when the selected index is 0 it works fine
but when the selected index is 1 i get a error "Parameter is not valid."
i tried different images but same error. is it the multiply by 32 thing
The Parameter is not valid error message when trying to create a Bitmap usually means that you are trying to allocate too much memory to it. The bitmap requires bit-depth*width*height/8 bytes of contiguous memory, and there just isn't enough available to satisfy that.
In this case, it looks like it's because you're multiplying its dimensions by 38 (and therefore multiplying the size in memory by 38^2).
You could utilize the following method:
private static void ResizeImage(string file, double vscale, double hscale, string output)
{
using(var source = Image.FromFile(file))
{
var width = (int)(source.Width * vscale);
var height = (int)(source.Height * hscale);
using(var image = new Bitmap(width, height, PixelFormat.Format24bppRgb))
using(var graphic = Graphics.FromImage(image))
{
graphic.SmoothingMode = SmoothingMode.AntiAlias;
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.DrawImage(source, new Rectangle(0, 0, width, height));
image.Save(output);
}
}
}
You can tailor this however you'd like, but it should meet your needs.
Important: The reason vscale and hscale are separate is to not follow scaling. You can easily combine them so you can scale accordingly. The other thing to remember, is your using a value of 32. Try using a value of .32 which will treat it more like a percent, which will scale. Also it won't increase the memory drastically causing your error.

Creating thumbnail images with C#

#functions{
public void GetThumbnailView(string originalImagePath, int height, int width)
{
//Consider Image is stored at path like "ProductImage\\Product1.jpg"
//Now we have created one another folder ProductThumbnail to store thumbnail image of product.
//So let name of image be same, just change the FolderName while storing image.
string thumbnailImagePath = originalImagePath;
originalImagePath = originalImagePath.Replace("thumb_", "");
//If thumbnail Image is not available, generate it.
if (!System.IO.File.Exists(Server.MapPath(thumbnailImagePath)))
{
System.Drawing.Image imThumbnailImage;
System.Drawing.Image OriginalImage = System.Drawing.Image.FromFile(Server.MapPath(originalImagePath));
double originalWidth = OriginalImage.Width;
double originalHeight = OriginalImage.Height;
double ratioX = (double)width / (double)originalWidth;
double ratioY = (double)height / (double)originalHeight;
double ratio = ratioX < ratioY ? ratioX : ratioY; // use whichever multiplier is smaller
// now we can get the new height and width
int newHeight = Convert.ToInt32(originalHeight * ratio);
int newWidth = Convert.ToInt32(originalWidth * ratio);
imThumbnailImage = OriginalImage.GetThumbnailImage(newWidth, newHeight,
new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero);
imThumbnailImage.Save(Server.MapPath(thumbnailImagePath), System.Drawing.Imaging.ImageFormat.Jpeg);
imThumbnailImage.Dispose();
OriginalImage.Dispose();
}
}
public bool ThumbnailCallback() { return false; }
}
in another stackowerflow question i found this code and really liked it but while using it there was a problem occured while creating the thumbnail images as shown below:
Server Error in '/' Application.
Out of memory. Description: An unhandled exception occurred during
the execution of the current web request. Please review the stack
trace for more information about the error and where it originated in
the code.
Exception Details: System.OutOfMemoryException: Out of memory.
Source Error:
Line 199: {
Line 200: System.Drawing.Image imThumbnailImage;
Line 201: System.Drawing.Image OriginalImage =
System.Drawing.Image.FromFile(Server.MapPath(originalImagePath.ToString()));
Line 202:
Line 203: double originalWidth = OriginalImage.Width;
Source File: c:\Inetpub\wwwroot\Lokal\Views\Stok\SatisRaporu.cshtml
Line: 201
my curiosity about this issue got me into the exception details and seen this :
//
// Summary:
// Creates an System.Drawing.Image from the specified file.
//
// Parameters:
// filename:
// A string that contains the name of the file from which to create the System.Drawing.Image.
//
// Returns:
// The System.Drawing.Image this method creates.
//
// Exceptions:
// System.OutOfMemoryException:
// The file does not have a valid image format.-or- GDI+ does not support the
// pixel format of the file.
//
// System.IO.FileNotFoundException:
// The specified file does not exist.
//
// System.ArgumentException:
// filename is a System.Uri.
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public static Image FromFile(string filename);
but all my pictures in that folder has ".jpg" extention so it seems wierd to me.
if im not gonna be able to create thumbnails from ".jpg" what else i can do?
I actually want to learn about if anyone else tried this on ".jpg" files and got a problem with it? and If no problem occured what i might be doing wrong?
A little note: I do this in a view using razor syntax. I know a little about c# language and improving my knowledge about it everyday.
Edit :
How i call the function:
GetThumbnailView("../pics/thumb_" + (("0000000" + stocks.stockcode).Substring(("0000000" + stocks.stockcode).Length - 7, 7)) + ".jpg", 200, 200);
A website I work on generates its thumbnails using the WPF APIs instead of GDI+. You need to add two references to your project to enable this: WindowsBase, PresentationFramework and PresentationCore. Here’s a basic example of how the code might be used:
try
{
using (var input = File.Open(inputFilename, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var thumb = File.Open(thumbFilename, FileMode.Create, FileAccess.Write, FileShare.None))
{
Thumbnail(input, thumb, 200, 100);
}
}
catch (MyException)
{
File.Delete(thumbFilename);
}
This fits the thumbnail into a 200x100 rectangle, while preserving aspect ratio.
(The real website doesn’t do it quite like the above. What we actually do is attempt to generate the smallest thumbnail in the file upload POST handler. We use a memory stream to hold the resulting thumbnail. If the thumbnail could be generated correctly, we save the upload and the small thumbnail, otherwise we return an error response to the client. Other thumbnail sizes are generated on the fly and cached.)
Here’s the code - note that I may have messed up a bit while transforming this into something reusable, but the core bits should all be there. Note that it saves all thumbnails as JPEG, but allows multiple input formats, including JPEG and PNG. This might or might not be OK for you.
private static void Thumbnail(Stream source, Stream destination, int maxWidth, int maxHeight)
{
int width = 0, height = 0;
BitmapFrame frame = null;
try
{
frame = BitmapDecoder.Create(source, BitmapCreateOptions.None, BitmapCacheOption.None).Frames[0];
width = frame.PixelWidth;
height = frame.PixelHeight;
}
catch
{
throw new MyException("The image file is not in any of the supported image formats.");
}
if (width > AbsoluteLargestUploadWidth || height > AbsoluteLargestUploadHeight)
throw new MyException("This image is too large");
try
{
int targetWidth, targetHeight;
ResizeWithAspect(width, height, maxWidth, maxHeight, out targetWidth, out targetHeight);
BitmapFrame targetFrame;
if (frame.PixelWidth == targetWidth && frame.PixelHeight == targetHeight)
targetFrame = frame;
else
{
var group = new DrawingGroup();
RenderOptions.SetBitmapScalingMode(group, BitmapScalingMode.HighQuality);
group.Children.Add(new ImageDrawing(frame, new Rect(0, 0, targetWidth, targetHeight)));
var targetVisual = new DrawingVisual();
var targetContext = targetVisual.RenderOpen();
targetContext.DrawDrawing(group);
var target = new RenderTargetBitmap(targetWidth, targetHeight, 96, 96, PixelFormats.Default);
targetContext.Close();
target.Render(targetVisual);
targetFrame = BitmapFrame.Create(target);
}
var enc = new JpegBitmapEncoder();
enc.Frames.Add(targetFrame);
enc.QualityLevel = 80;
enc.Save(destination);
}
catch
{
throw new MyException("The image file appears to be corrupt.");
}
}
/// <summary>Generic helper to compute width/height that fit into specified maxima while preserving aspect ratio.</summary>
public static void ResizeWithAspect(int origWidth, int origHeight, int maxWidth, int maxHeight, out int sizedWidth, out int sizedHeight)
{
if (origWidth < maxWidth && origHeight < maxHeight)
{
sizedWidth = origWidth;
sizedHeight = origHeight;
return;
}
sizedWidth = maxWidth;
sizedHeight = (int) ((double) origHeight / origWidth * sizedWidth + 0.5);
if (sizedHeight > maxHeight)
{
sizedHeight = maxHeight;
sizedWidth = (int) ((double) origWidth / origHeight * sizedHeight + 0.5);
}
}
The file extension doesn't really matter, it is the actual bytes of the image that matter. Most likely one of the jpgs is corrupt. You should catch the OutOfMemory exception on a per file basis and handle that appropriately.
Since you are trying to generate thumbnails, I suggest you have a default image to use if the thumbnail can't be generated. For example, most web browsers use a small box with a red X in it when the image is corrupt or missing.
See also:
SO#6506089
SO#1108607
SO#1644108
SO#9237457
And for those curious about why OutOfMemoryException is thrown, see the answer to this question:
Is there a reason Image.FromFile throws an OutOfMemoryException for an invalid image format?

How to thumbnail faster in c#

I'm trying to thumb an image as fast as possible regardless of the usage of resources to be used in my ImageList and listview and this is currently how i'm doing it but it seems to be slow:
public Image toThumbs(string file, int width, int height)
{
image = null;
aspectRatio = 1;
fullSizeImg = null;
try
{
fullSizeImg = Image.FromFile(file);
float w = fullSizeImg.Width;
float h = fullSizeImg.Height;
aspectRatio = w / h;
int xp = width;
int yp = height;
if (fullSizeImg.Width > width && fullSizeImg.Height > height)
{
if ((float)xp / yp > aspectRatio)
{
xp = (int)(yp * aspectRatio);
}
else
{
yp = (int)(xp / aspectRatio);
}
}
else if (fullSizeImg.Width != 0 && fullSizeImg.Height != 0)
{
xp = fullSizeImg.Width;
yp = fullSizeImg.Height;
}
image = new Bitmap(width, height);
graphics = Graphics.FromImage(image);
graphics.FillRectangle(Brushes.White, ((width - xp) / 2), (height - yp), xp, yp);
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.DrawImage(fullSizeImg, new Rectangle(((width - xp) / 2), (height - yp), xp, yp));
graphics.Dispose();
fullSizeImg.Dispose();
}
catch (Exception)
{
image = null;
}
return image;
}
I'm not sure if the computation is the one that is slowing down the thumbnailing or maybe the classes itself that are being used are slow, if that is the case then what other alternatives can be use maybe a different computation or i need to import other classes or is there a third party libraries that can be used or i need to do a dll import or something? Please help me.
Edit: Just found a solution here
http://www.vbforums.com/showthread.php?t=342386
it extracts a thumbnail from a file
without reading the whole file. I was able to reduce the time about 40% when i used this.
Your calculations happen in fractions of a second. The call to DrawImage is most likely the slowest part of this (as that one is doing the scaling).
If you're needing this thumbnail image exactly once then I don't see much room for improvement here. If you're calling that method on the same image more than once, you should cache the thumbnails.
I use this mechanism which seems to be very fast.
BitmapFrame bi = BitmapFrame.Create(new Uri(value.ToString()), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand);
// If this is a photo there should be a thumbnail image, this is VERY fast
if (bi.Thumbnail != null)
{
return bi.Thumbnail;
}
else
{
// No thumbnail so make our own (Not so fast)
BitmapImage bi2 = new BitmapImage();
bi2.BeginInit();
bi2.DecodePixelWidth = 100;
bi2.CacheOption = BitmapCacheOption.OnLoad;
bi2.UriSource = new Uri(value.ToString());
bi2.EndInit();
return bi2;
}
Hope this helps.
Out of curiosity, have you tried the GetThumbnailImage method on System.Drawing.Bitmap? It might at least be worth comparing to your current implementation.
This may seem like to much of an obvious answer but have you tried just using Image.GetThumbnailImage()?
You don't get as much control over the quality of the result but if speed is your main concern?
Your thumbnail extraction that gets you the big speed up relies on the image having a thumbnail already embedded in it.
To speed up the original you might find that changing:-
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
to
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
Might help.

Categories

Resources