tags:

views:

66

answers:

4

I am working on a class that maintains a dictionary of images. This dictionary should be saved to and loaded from a file.

I implemented the below solution, but the problem is that according to MSDN documentation for Image.FromStream();
http://msdn.microsoft.com/en-us/library/93z9ee4x(v=VS.80).aspx

"The stream is reset to zero if this method is called successively with the same stream."

Any ideas how to fix this? The speed of loading the dictionary is critical.

class ImageDictionary
{
    private Dictionary<string, Image> dict = new Dictionary<string, Image>();

    public void AddImage(string resourceName, string filename)
    {
       //...
    }

    public Image GetImage(string resourceName) 
    {
       //...
    }


    public void Save(string filename)
    {
        var stream = new FileStream(filename, FileMode.Create);
        var writer = new BinaryWriter(stream);
        writer.Write((Int32) dict.Count);
        foreach (string key in dict.Keys)
        {
            writer.Write(key);

            Image img;
            dict.TryGetValue(key, out img);
            img.Save(stream,System.Drawing.Imaging.ImageFormat.Png);
        }
        writer.Close();
        stream.Close();
    }

    public void Load(string filename)
    {
        var stream = new FileStream(filename, FileMode.Open);
        var reader = new BinaryReader(stream);
        Int32 count = reader.ReadInt32();
        dict.Clear();

        for (int i = 0; i < count; i++)
        {
            string key = reader.ReadString();
            Image img = Image.FromStream(stream);
            dict.Add(key, img);

        }

        reader.Close();
        stream.Close();

    }



}
+6  A: 

The Image.FromStream method expects a valid image stream. You are concatenating multiple images into a single file and if you want to reconstruct them you will also need to save their size in addition to their number. An easier solution would be to simply binary serialize the image dictionary:

public void Save(string filename)
{
    var serializer = new BinaryFormatter();
    using (var stream = File.Create(filename))
    {
        serializer.Serialize(stream, dict);
    }
}

public void Load(string filename)
{
    var serializer = new BinaryFormatter();
    using (var stream = File.Open(filename, FileMode.Open))
    {
        dict = (Dictionary<string, Image>)serializer.Deserialize(stream);
    }
}
Darin Dimitrov
Thank you for this elegant solution :-)
Mike Warner
+1  A: 

You can try to use BinaryFormatter to serialize/deserialize your dictionary dict to/from file.

DixonD
A: 

An off-the-wall idea that might work (I have definitely not tested this):

  • Create a Substream class that derives from Stream and also wraps an underlying Stream. Its constructor would take a Stream and an offset into that stream that the Substream treats as zero. Substream is basically a constrained view or window into another stream (in this case, your file stream).
  • Initially, create a Substream over your FileStream with an offset of zero.
  • When you call Image.FromStream, the position of your Substream will advance to some new position (call this p).
  • Create a new Substream over your FileStream with an offset of p.
  • Loop until finished.

The idea is that even if Image.FromStream resets the underlying stream, it will reset the Substream to some offset into the FileStream, which is what you really want.

Chris Schmich
A: 

why not create custom header for that file which includes (number of images,starting address of the actual images and make between each image a line separator)

Saddam Abu Ghaida