How to edit an image (XAML)

[ This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation ]

This topic shows you how to use a BitmapEncoder to edit an existing image. You can use BitmapEncoder to apply transforms such as scaling and cropping, set metadata and properties, and edit pixels while preserving any unedited data. We show you how to initialize a BitmapEncoder with the original image data, apply one or more editing operations to it, and then save it so it updates the original file.

You can also use BitmapEncoder to create a new image from scratch, which we explain in How to encode a new image.

What you need to know

Technologies

Prerequisites

Instructions

Step 1: Get a decoder object from the original image

Write the beginning of a function that receives a BitmapEncoder object that was initialized from the image file that you want to edit, and the IRandomAccessStream opened from the file. This example overwrites the original image, so you must use a stream that was opened using ReadWrite privileges.

async void EditImage(
    Windows.Graphics.Imaging.BitmapDecoder decoder,
    Windows.Storage.Streams.IRandomAccessStream fileStream
    )
{

For instructions on how to obtain the decoder and stream objects, see How to decode an image. When you call OpenAsync, make sure to change the FileAccessMode parameter to ReadWrite.

Step 2: Initialize the encoder object for editing

Create an InMemoryRandomAccessStream as the encoding destination and create a transcoding BitmapEncoder using the CreateForTranscodingAsync method.

Use the InMemoryRandomAccessStream as a temporary location to store the encoded file. Otherwise, the decoder and encoder would be simultaneously reading and writing to the same stream, which wouldn't work.

var memStream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
    var encoder = await Windows.Graphics.Imaging.BitmapEncoder.CreateForTranscodingAsync(memStream, decoder);

Note  CreateForTranscodingAsync supports copying data only to an image with the same format as the original. It doesn't allow you to convert from one format to another.

 

You now have a BitmapEncoder that has been initialized with the data from the source BitmapDecoder.

Step 3: Transform the image

Now that you have the encoder, you can perform a variety of actions including setting metadata and pixel data. This example scales and rotates the image using the BitmapTransform method. For more info about setting metadata, see How to write image metadata. For more info about setting pixel data, see How to encode a new image.

    var memStream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
    var encoder = await Windows.Graphics.Imaging.BitmapEncoder.CreateForTranscodingAsync(memStream, decoder);

    // Scaling occurs before flip/rotation.
    encoder.BitmapTransform.ScaledWidth = 640;
    encoder.BitmapTransform.ScaledHeight = 480;
    encoder.BitmapTransform.Rotation = Windows.Graphics.Imaging.BitmapRotation.Clockwise90Degrees;

    // Fant is a relatively high quality interpolation algorithm.
    encoder.BitmapTransform.InterpolationMode = Windows.Graphics.Imaging.BitmapInterpolationMode.Fant;

    // Attempt to generate a new thumbnail from the updated pixel data.
    // Note: Only JPEG, TIFF and JPEG-XR images support encoding thumbnails.
    encoder.IsThumbnailGenerated = true;

Note  If you use CreateForTranscodingAsync to create the BitmapEncoder, the encoder tries to copy over all of the original data in a lossless manner. Like, if you transcode a JPEG and edit some imaging properties, but don’t apply any transforms or edit the pixel data, the image is copied losslessly. But, if you perform image processing by getting pixel data from the decoder and then setting it on the encoder, it is necessarily a lossy process as the pixel data must be re-encoded.

 

Step 4: Flush the encoder and handle errors

When you are finished using the encoder, flush it to complete the encoding operation. You also need to handle the case where the image format doesn’t support encoding thumbnails. If you know that you will always be editing an image format that supports thumbnails, like JPEG in this example, then you can skip this error handling.

   try
    {
        await encoder.FlushAsync();
    }
    catch (Exception err)
    {
        switch (err.HResult)
        {
            case unchecked ((int) 0x88982F81): //WINCODEC_ERR_UNSUPPORTEDOPERATION
                // If the encoder does not support writing a thumbnail, then try again
                // but disable thumbnail generation.
                encoder.IsThumbnailGenerated = false;
                break;
            default:
                throw err;
        }
    }

    if (encoder.IsThumbnailGenerated == false)
    {
        await encoder.FlushAsync();
    }

Step 5: Save the encoded image to the file and clean up

Finally, copy the contents from the in-memory stream to the original file’s stream and close all of the streams.

    // Overwrite the contents of the file with the updated image stream.
    memStream.Seek(0);
    fileStream.Seek(0);
    fileStream.Size = 0;
    await RandomAccessStream.CopyAsync(memStream, fileStream);

    fileStream.Dispose();
    memStream.Dispose();
}

Note  Instead of calling the Dispose method, consider the usingkeyword which provides a convenient syntax to guarantee the correct usage of IDisposable objects such as implementations of IRandomAccessStream.

 

Simple Imaging sample

Windows.Graphics.Imaging

CreateForTranscodingAsync

BitmapTransform

How to decode an image

How to encode an image

How to write image metadata