We use essential cookies for the website to function, as well as analytics cookies for analyzing and creating statistics of the website performance. To agree to the use of analytics cookies, click "Accept All". You can manage your preferences at any time by clicking "Cookie Settings" on the footer. More Information.

Only Essential Cookies
Accept All
GuidesMediaImage KitImage Development (ArkTS)Image Editing and ProcessingUsing PixelMap for PixelMap Operations

Using PixelMap for PixelMap Operations

To process a certain area in an image, you can perform PixelMap operations, which are usually used to beautify the image.

As shown in the figure below, the pixel data of a rectangle in an image is read, modified, and then written back to the corresponding area of the original image.

Figure 1 PixelMap operation

How to Develop

For details about the APIs for PixelMap operations, see Interface (PixelMap).

  1. Complete image decoding and obtain a PixelMap object.

  2. Obtain information from the PixelMap object.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. // Obtain the total number of bytes of this PixelMap object.
    2. const totalPixelBytes: number = this.pixelMap.getPixelBytesNumber();
    3. Logger.info('Total bytes: ', totalPixelBytes.toString());
    4. // Obtain the number of bytes per row of the image.
    5. const rowBytes: number = this.pixelMap.getBytesNumberPerRow();
    6. Logger.info('Row bytes: ', rowBytes.toString());
    7. // Obtain the pixel density of the current image. Pixel density refers to the number of pixels per inch of an image. The higher the pixel density, the finer the image.
    8. const density: number = this.pixelMap.getDensity();
    9. Logger.info('Density: ', density.toString());
  3. Read and modify the pixel data of the target area, and write the modified data back to the original image.

    NOTE

    You are advised to use readPixelsToBuffer with writeBufferToPixels, and readPixels with writePixels, to prevent issues with the PixelMap due to inconsistent pixel formats.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. // Scenario 1: Read and modify the entire image data.
    2. // Read the pixel data of the entire PixelMap and write it to the buffer in the PixelMap's pixel format.
    3. const buffer = new ArrayBuffer(totalPixelBytes);
    4. await this.pixelMap.readPixelsToBuffer(buffer).then(() => {
    5. Logger.info('Succeeded in reading image pixel data.');
    6. }).catch((error: BusinessError) => {
    7. Logger.error('Failed to read image pixel data. The error is: ' + String(error));
    8. });
    9. // ...
    10. // Read the image pixel data from the buffer in the PixelMap's pixel format and write it to the entire PixelMap.
    11. this.pixelMap!.writeBufferToPixels(buffer).then(() => {
    12. Logger.info('Succeeded in writing image pixel data.');
    13. this.updateImageInfo();
    14. }).catch((error: BusinessError) => {
    15. Logger.error('Failed to write image pixel data. The error is: ' + String(error));
    16. });
    Collapse
    Word wrap
    Dark theme
    Copy code
    1. // Scenario 2: Read and modify image data in a specified region.
    2. // Read the pixel data in the specified region of the PixelMap and write it to the PositionArea.pixels buffer in RGBA_8888 pixel format. The region is specified by PositionArea.region.
    3. const regionWidth: number = 200;
    4. const regionHeight: number = 100;
    5. const area: image.PositionArea = {
    6. pixels: new ArrayBuffer(regionWidth * regionHeight * 4), // Each pixel in BGRA_8888 format occupies 4 bytes.
    7. offset: 0,
    8. stride: regionWidth * 4, // Row stride of the specified region.
    9. region: {
    10. x: 0,
    11. y: 0,
    12. size: { width: regionWidth, height: regionHeight }
    13. }
    14. };
    15. await this.pixelMap.readPixels(area).then(() => {
    16. Logger.info('Succeeded in reading the image data in the area.');
    17. // ...
    18. }).catch((error: BusinessError) => {
    19. Logger.error('Failed to read the image data in the area. The error is: ' + String(error));
    20. });
    21. // Read the image pixel data from the PositionArea.pixels buffer and write it to the specified region of the PixelMap in BGRA_8888 pixel format. The region is specified by PositionArea.region.
    22. await this.pixelMap.writePixels(area).then(() => {
    23. this.updateImageInfo();
    24. Logger.info('Succeeded in writing pixelMap into the specified area.');
    25. }).catch((error: BusinessError) => {
    26. Logger.error('Failed to write pixelMap into the specified area. The error is: ' + String(error));
    27. });

Development Example

Cloning (Deep Copying) a PixelMap and Changing the Pixel Format

NOTE
  • This method only copies the basic content of a PixelMap. It does not support copying the color gamut or HDR metadata. If you do not need to change the pixel format of the new PixelMap, use clone or cloneSync.
  • This method does not support converting the new PixelMap to the following pixel formats: RGBA_1010102, YCBCR_P010, YCRCB_P010, and ASTC_4x4.
  1. Complete image decoding and obtain a PixelMap object.

  2. Perform a deep copy of the PixelMap by referring to the following code.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. /**
    2. * Clone (deep copy) a PixelMap and change the pixel format.
    3. *
    4. * @param pixelMap - Original PixelMap.
    5. * @param desiredPixelFormat - Pixel format of the new PixelMap. The pixel format of the original PixelMap is used if not specified.
    6. * @returns Promise of the new PixelMap.
    7. */
    8. async function clonePixelMap(pixelMap: PixelMap, desiredPixelFormat?: image.PixelMapFormat): Promise<PixelMap> {
    9. // Obtain the image information of the original PixelMap.
    10. const imageInfo = pixelMap.getImageInfoSync();
    11. // Read the pixel data of the original PixelMap and write it to the buffer in the original PixelMap's pixel format.
    12. const buffer = new ArrayBuffer(pixelMap.getPixelBytesNumber());
    13. await pixelMap.readPixelsToBuffer(buffer);
    14. // Generate initialization options based on the image information of the original PixelMap.
    15. const options: image.InitializationOptions = {
    16. // Pixel format of the data source: must match the pixel format of the original PixelMap; otherwise, the new PixelMap image will be abnormal.
    17. srcPixelFormat: imageInfo.pixelFormat,
    18. // Pixel format of the new PixelMap.
    19. pixelFormat: desiredPixelFormat || imageInfo.pixelFormat,
    20. // Alpha type of the new PixelMap.
    21. alphaType: imageInfo.alphaType,
    22. // Size of the new PixelMap: must match the size of the original PixelMap. Passing a different size for scaling is not supported.
    23. size: imageInfo.size
    24. };
    25. // Create a new PixelMap based on the pixel data and initialization options.
    26. return await image.createPixelMap(buffer, options);
    27. }

Vertically Stitching Two PixelMaps of the Same Width into a Long Image

NOTE

This method supports only PixelMaps in the following pixel formats: RGBA_8888, BGRA_8888, and RGBA_F16.

  1. Complete image decoding and obtain two PixelMap objects with the same width and pixel format.

  2. Stitch the two PixelMaps by referring to the following code.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. /**
    2. * Vertically concatenate two PixelMaps of the same width into a long image.
    3. *
    4. * @param pixelMap1 - The first PixelMap.
    5. * @param pixelMap2 - The second PixelMap. Its width must be the same as the first, but its height can differ.
    6. * @returns A Promise of the new PixelMap after concatenation.
    7. */
    8. async function concatPixelMap(pixelMap1: PixelMap, pixelMap2: PixelMap): Promise<PixelMap> {
    9. // Read the pixel data of pixelMap1 into area1.pixels.
    10. const imageInfo1 = pixelMap1.getImageInfoSync();
    11. const area1: image.PositionArea = {
    12. pixels: new ArrayBuffer(pixelMap1.getPixelBytesNumber()),
    13. offset: 0,
    14. stride: pixelMap1.getBytesNumberPerRow(),
    15. region: {
    16. size: imageInfo1.size,
    17. x: 0,
    18. y: 0
    19. }
    20. };
    21. await pixelMap1.readPixels(area1);
    22. // Read the pixel data of pixelMap2 into area2.pixels.
    23. const imageInfo2 = pixelMap2.getImageInfoSync();
    24. const area2: image.PositionArea = {
    25. pixels: new ArrayBuffer(pixelMap2.getPixelBytesNumber()),
    26. offset: 0,
    27. stride: pixelMap2.getBytesNumberPerRow(),
    28. region: {
    29. size: imageInfo2.size,
    30. x: 0,
    31. y: 0
    32. }
    33. };
    34. await pixelMap2.readPixels(area2);
    35. // Create a new blank PixelMap whose width equals that of pixelMap1 and pixelMap2, and whose height is the sum of pixelMap1 and pixelMap2.
    36. const options: image.InitializationOptions = {
    37. srcPixelFormat: imageInfo1.pixelFormat,
    38. pixelFormat: imageInfo1.pixelFormat,
    39. size: {
    40. width: imageInfo1.size.width,
    41. height: imageInfo1.size.height + imageInfo2.size.height
    42. }
    43. };
    44. const newPixelMap = image.createPixelMapSync(options);
    45. // Write the previously obtained pixel data of pixelMap1 and pixelMap2 to the new PixelMap in order.
    46. await newPixelMap.writePixels(area1);
    47. area2.region.y = imageInfo1.size.height; // The write position of pixelMap2 pixels should start from the row after the last row of pixelMap1 pixels.
    48. await newPixelMap.writePixels(area2);
    49. return newPixelMap;
    50. }

Sample Code