How to edit an image (HTML)
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) {
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;
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;
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();
});
Related topics