This article descibes the puzzling behavior of BitmapEncoder.Save

In our effort to release editions of our software that have no reference to the System.Drawing assembly, we are porting GDI+ code to WPF. While doing this, we encounter some puzzling behavior from System.Windows.Media.Imaging.BitmapEncoder.Save.

We call BitmapEncoder.Save and pass it our own implementation of System.IO.Stream as follows:

using System.Windows.Media.Imaging;

BitmapFrame frame = BitmapFrame.Create(bitmapSource); BitmapEncoder encoder = new BmpBitmapEncoder(); encoder.Frames.Add(frame); encoder.Save( myStream );

The object myStream is a derived stream which implements some overloads available in System.IO.Stream. We would expect that the Save method calls the Stream.Write method only and does not call Stream.Read. Our initial implementation of Stream.CanSeek and Stream.CanRead returns false and Stream.Read throws NotSupportedException as specified in the MSDN documentation.

To our surprise, it turned out that the framework calls the Read method even though CanRead returns false!

After some experimentation, we discovered that when CanSeek returns true, the framework does not call Read. But, even more surprisingly it never calls Seek.

To summarize:

CanSeek false true
CanRead false false
CanWrite true true
Save calls Seek No No
Save calls Read Yes No

In other words, making the stream seek able, causes the framework to suddenly not call Read anymore, even though Seek is never called. This totally puzzles us.

Any insightful comments are welcome!