目录

How do I add a watermark to an image of an atomic service?

  1. Use the OffScreenCanvas object to obtain the image source data.
  2. Call the OffscreenCanvasRenderingContext2D.drawImage method to draw the image data on the off-screen canvas.
  3. Call the OffscreenCanvasRenderingContext2D.fillText method to draw the watermark text.

Refer to the sample code below:

import { image } from '@kit.ImageKit';
import { fileIo } from '@kit.CoreFileKit';
import { display } from '@kit.ArkUI';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct Demo {
  @State pixelMap: image.PixelMap | null = null;
  @State fileUri: string = '';
  build() {
    Column() {
      Row() {
        Button('Select image')
          .onClick(() => {
            this.selectPicture();
          })
        Button('Add watermark')
          .onClick(async () => {
            if (this.fileUri) {
              this.pixelMap = await this.addWatermark(this.fileUri, 'Add Watermark')
            }
          })
      }
      .margin({ bottom: 10 })
      Image(this.pixelMap)
        .width('100%')
        .margin({ bottom: 20 })
        .objectFit(ImageFit.Contain)
    }
    .width('100%')
    .height('100%')
  }
  async addWatermark(fileUri: string, watermarkText: string) {
    let file = fileIo.openSync(fileUri, fileIo.OpenMode.READ_ONLY);
    const imageSource: image.ImageSource = image.createImageSource(file.fd);
    let imageInfo = await imageSource.getImageInfo();
    let imageWidth = imageInfo.size.width;
    let imageHeight = imageInfo.size.height;
    let opts: image.DecodingOptions = {
      editable: true,
      desiredSize: {
        height: imageWidth,
        width: imageHeight
      }
    };
    let pixelMap = await imageSource.createPixelMap(opts);
    let offScreenCanvas = new OffscreenCanvas(imageWidth, imageHeight);
    let OffScreenContext = offScreenCanvas.getContext('2d');
    OffScreenContext.drawImage(pixelMap, 0, 0, offScreenCanvas.width, offScreenCanvas.height);
    OffScreenContext.textAlign = 'center';
    OffScreenContext.textBaseline = 'bottom';
    OffScreenContext.fillStyle = Color.Black;
    let imageScale = offScreenCanvas.width / display.getDefaultDisplaySync().width;
    OffScreenContext.font = 32 * imageScale + 'vp'
    OffScreenContext.fillText(watermarkText, offScreenCanvas.width / 2, offScreenCanvas.height / 2);
    return OffScreenContext.getPixelMap(0, 0, offScreenCanvas.width, offScreenCanvas.height);
  }
  selectPicture() {
    const photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
    photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
    photoSelectOptions.maxSelectNumber = 1; // Set the maximum number of images that can be selected.
    let uris: Array<string> = [];
    const photoViewPicker = new photoAccessHelper.PhotoViewPicker();
    photoViewPicker.select(photoSelectOptions).then((photoSelectResult: photoAccessHelper.PhotoSelectResult) => {
      uris = photoSelectResult.photoUris;
      console.info('photoViewPicker.select to file succeed and uris are:' + uris);
      if (uris.length <= 0) {
        return
      }
      this.fileUri = uris[0];
      let file = fileIo.openSync(this.fileUri, fileIo.OpenMode.READ_ONLY);
      const imageSource: image.ImageSource = image.createImageSource(file.fd);
      imageSource.getImageInfo((err, value) => {
        if (err) {
          return;
        }
        let opts: image.DecodingOptions = {
          editable: true,
          desiredSize: {
            height: value.size.height,
            width: value.size.width
          }
        };
        imageSource.createPixelMap(opts, async (_err, pixelMap) => {
          this.pixelMap = pixelMap;
        })
      })
    }).catch((err: BusinessError) => {
      console.error(`Invoke photoViewPicker.select failed, code is ${err.code}, message is ${err.message}`);
    })
  }
}

Reference

OffscreenCanvasRenderingContext2D