目录

元服务如何给图片添加水印?

  1. 使用OffScreenCanvas离屏画布拿到图片源数据。
  2. 在离屏画布上使用OffscreenCanvasRenderingContext2D.drawImage方法将图片数据进行绘制。
  3. 使用OffscreenCanvasRenderingContext2D.fillText方法绘制文字水印。

参考样例:

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('选择图片')
          .onClick(() => {
            this.selectPicture();
          })
        Button('添加水印')
          .onClick(async () => {
            if (this.fileUri) {
              this.pixelMap = await this.addWatermark(this.fileUri, '添加水印')
            }
          })
      }
      .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; // 选择媒体文件的最大数目
    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}`);
    })
  }
}

参考链接

OffscreenCanvasRenderingContext2D