How to edit an image (HTML)
[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
- Building your first Windows Windows Runtime app using JavaScript
- Windows.Storage.Pickers
- Windows.Graphics.Imaging
Prerequisites
- We assume that you can create a basic Windows Runtime app using JavaScript. For more info, see Building your first Windows Windows Runtime app using JavaScript.
- You have a BitmapDecoder object. How to decode an image walks you through that process.
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.
function (decoder, fileStream) {
Note 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.
// Keep variables in-scope across multiple async
var memStream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
var encoder;
Windows.Graphics.Imaging.BitmapEncoder
.createForTranscodingAsync(memStream, decoder).then(function (_encoder) {
encoder = _encoder;
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.
// Scaling occurs before flip/rotation.
encoder.bitmapTransform.scaledWidth = 640;
encoder.bitmapTransform.scaledHeight = 480;
// Fant is a relatively high quality interpolation algorithm.
encoder.bitmapTransform.interpolationMode =
Windows.Graphics.Imaging.BitmapInterpolationMode.fant;
// Generate a new thumbnail from the updated pixel data.
// Note: Only JPEG, TIFF and JPEG-XR images support encoding thumbnails.
encoder.isThumbnailGenerated = true;
encoder.bitmapTransform.rotation =
Windows.Graphics.Imaging.BitmapRotation.clockwise90Degrees;
Note If you use CreateForTranscodingAsync to create the BitmapEncoder, the encoder tries to copy over all of the original data in a lossless manner. For example, 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, then you can skip this error handling.
return encoder.flushAsync();
}).then(null, function (error) {
switch (error.number) {
// If the encoder doesn't support writing a thumbnail, then try again
// but disable thumbnail generation.
case -2003292287: // WINCODEC_ERR_UNSUPPORTEDOPERATION
encoder.isThumbnailGenerated = false;
return encoder.flushAsync();
default:
throw error;
}
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.
}).then(function () {
// Overwrite the contents of the file with the updated image stream.
memStream.seek(0);
fileStream.seek(0);
fileStream.size = 0;
return Windows.Storage.Streams.RandomAccessStream.copyAsync(memStream, fileStream);
}).done(function () {
memStream.close();
fileStream.close();
});