2

I want to write a function that will get as input string fileName and return an ImageDrawing object.
I don't want to load the Bitmap from the disk in this function. Instead, I want to have some kind of lazy evaluation. In order to find out the dimensions, I use the Bitmap class.

Currently I have this code:

    public static ImageDrawing LoadImage(string fileName)
    {
        System.Drawing.Bitmap b = new System.Drawing.Bitmap(fileName);
        System.Drawing.Size s = b.Size ;
        System.Windows.Media.ImageDrawing im = new System.Windows.Media.ImageDrawing();
        im.Rect = new System.Windows.Rect(0, 0, s.Width, s.Height);
        im.ImageSource = new System.Windows.Media.Imaging.BitmapImage(new Uri(fileName, UriKind.Absolute));
        return im;            
    }
  1. Is the call to System.Drawing.Bitmap constructor lazy?
  2. Is the call to .Size lazy?
  3. Is the BitmapImage constructor lazy?
  4. Is there any other way that I can implement it to be fully lazy?

Edit: There are many good answers that might be helpful to the community - to use Lazy class and to open it with a Task.
Nevertheless, I want to put this ImageDrawing inside a DrawingGroup and serialize afterwards, so Lazy as well as Task is not an option for me.

Andrey Rubshtein
  • 20,795
  • 11
  • 69
  • 104
  • 1
    Related: http://stackoverflow.com/questions/552467/how-do-i-reliably-get-an-image-dimensions-in-net-without-loading-the-image – George Johnston Jan 10 '12 at 15:58

2 Answers2

4

The constructor of the Bitmapclass is not lazy but you can use the Lazy<T> class which is made for exactly that purpose:

public static Lazy<ImageDrawing> LoadImage(string fileName)
{
    return new Lazy<ImageDrawing>(() => {
        System.Drawing.Bitmap b = new System.Drawing.Bitmap(fileName);
        System.Drawing.Size s = b.Size;
        System.Windows.Media.ImageDrawing im = new System.Windows.Media.ImageDrawing();
        im.Rect = new System.Windows.Rect(0, 0, s.Width, s.Height);
        im.ImageSource = new System.Windows.Media.Imaging.BitmapImage(new Uri(fileName,     UriKind.Absolute));
        return im;
    });
}

From the documentation (http://msdn.microsoft.com/en-us/library/dd997286.aspx):

Although you can write your own code to perform lazy initialization, we recommend that you use Lazy instead. Lazy and its related types also support thread-safety and provide a consistent exception propagation policy.

Markus Palme
  • 659
  • 4
  • 15
  • (+1) For the helpful answer for the community. But it is not good for me specifically, I have updated my question - please check it out – Andrey Rubshtein Jan 10 '12 at 16:45
  • When I try to serialize an instance of with this code.. ` var img = LoadImage("C:\\Windows\\Account.png"); Stream stream = File.Open("Serialized.osl", FileMode.Create); BinaryFormatter bformatter = new BinaryFormatter(); bformatter.Serialize(stream, img); stream.Close(); ` ... I get the error message that 'System.Windows.Media.ImageDrawing' is not serializable. That's the same message you would get without the `Lazy` wrapper... How are you trying to serialize this thing anyway? – Markus Palme Jan 10 '12 at 16:46
  • You have to pass in the Value property to the serializer: `System.Windows.Markup.XamlWriter.Save(img.Value);` – Markus Palme Jan 10 '12 at 16:53
  • But then it would not be lazy. img.Value will initialize. – Andrey Rubshtein Jan 10 '12 at 16:56
  • In the moment you serialize, it will always be initialized :) Maybe you can tell us what you are trying to achieve here is a broader context? – Markus Palme Jan 10 '12 at 17:06
  • It could have been serialized only with the relevant properties - height, width, fileName. Not opening the Bitmap from disk – Andrey Rubshtein Jan 10 '12 at 17:32
1

I suggest to use Timer within your class and download your image in a "lazy" manner. Also you can try to implement Task of MS TPL to do it as well inside of the Timer tick event.

NoWar
  • 36,338
  • 80
  • 323
  • 498
  • Thanks for the advice, it might be useful to somebody else - so (+1). For me it is not useful because I need to serialize the BitmapImage, and I don't want to serialize Tasks – Andrey Rubshtein Jan 10 '12 at 16:22
  • I see... Well.. Do it then without a Task. But you can try to re-view your class and implement all things you need. In fact the class which is going to do some job should be a different one. And keep your data/images in class which doesn't have any transformation methods. I mean try to split the data and methods to manipulate it into 2 diff. classes. – NoWar Jan 10 '12 at 16:27