Page 2 of 4
Decoders and Encoders
The BitmapFrame without and encoder or decoder class isn't really of any more use than a BitmapSource.
Put simply a decoder class will convert an image in a particular format into an array of decoded BitmapFrames, thumbnails and metadata. Obviously an encoder does the reverse job and takes some BitmapFrames, complete with thumbnails and metadata and codes them into a specific image format.
The best way to make this all seem simple is to follow through a simple example that takes us from a coded image format to raw pixels and back again.
First let's open a JPEG file stored in the local directory (the bin\debug directory if you are running a debug session under Visual Studio or C# Express). All we have to do is use the appropriate Decoder, JpegBitmapDecoder and specify the parameters in its constructor:
JpegBitmapDecoder MyJpegDec =
Notice that although a Decoder doesn't inherit from BitmapSource it has a BitmapSource derived object as one of its properties and so can be used in a similar way.
In this case the Frames property consists of a single item - JPEGs only ever have a single frame - and this can be displayed using:
BitmapFrame MyBMF = MyJpegDec.Frames;
image1.Source = MyBMF;
or of course more directly as:
image1.Source = MyJpegDec.Frames;
You can also access and use any thumbnail stored along with the main image. For example:
image1.Source = MyJpegDec.Frames
The BitmapFrame returned from a decoder is frozen. If you need to modify it then you need to create a copy using its clone method. Notice, however, that in most cases this isn't necessary as you can access all of its properties and even pixel data (using CopyPixels) without creating an unfrozen copy. In particular if you want to manipulate the pixel data directly then converting the BitmapFrame to a WriteableBitmap is the best solution:
WriteableBitmap MyWBM =
After this you can work with the pixel data in the usual way.
Coding the pixel data the other way is just as easy. First we need an encoder of the correct type. To convert to PNG we need a PngBitmapEncoder object:
PngBitmapEncoder MyPngEnc =
In this case the constructor isn't used to specify the details of the conversion. All you really have to do is to supply some raw bitmap data by adding BitmapFrames to the Frames collection:
Notice that you have to use a BitmapFrame but you can always convert a BitmapSource derived object into a BitmapFrame- just use the appropriate static constructor - so that you can use the encoder.
The encoding isn't performed until the coded bits are actually required and this usually means when the encoder's the Save method is used. This saves the coded bits to a stream. For example:
FileStream fs = new FileStream(
Notice that you can use a memory stream if you want to gain access to the coded bits directly as an array.
The problems of compression
The procedure given above, i.e. decode an image file and then encode it to a different format, looks as if it is a good way to perform file conversion or update. It is, but you need to keep in mind that when working with formats that use lossy compression you can only do it a small number of times.
With lossy compression such as JPEG image quality is lost each time you encode an image. So when you open a JPEG image the decoded result isn't quite as good as the original and when you encode it again some quality is lost to add to that lost in the first encoding. If you keep repeating the decode/encode cycle the image will eventually deteriorate to the point where it is unacceptable.
If you want to control the compression and other details of the conversion used by the encoder then this is just a simple matter of setting appropriate properties. For example the JPEG encoder has a QualityLevel property that you can set to control the amount of compression applied. Obviously these properties are specific to the type of decoder and you can look them up in the documentation - they are generally easy to use.