鸿蒙给图片设置水印,保存到相册

思路:

使用OffScreenCanvas离屏画布拿到图片源数据,在离屏画布上使用OffscreenCanvasRenderingContext2D的 drawImage和 fillText分别绘制图像和文水印文字。水印图片的保存可以使用安全控件SaveButton结合fs.write来实现。

图片添加水印

一、添加水印流程和方法

1.解析图片得到pixelMap数据。

  async getImagePixelMap(resource: Resource): Promise<ImagePixelMap> {
    const data: Uint8Array = await getContext(this).resourceManager.getMediaContent(resource);
    const arrayBuffer: ArrayBuffer = data.buffer.slice(data.byteOffset, data.byteLength + data.byteOffset);
    const imageSource: image.ImageSource = image.createImageSource(arrayBuffer);
    return await imageSource2PixelMap(imageSource)
  }

2.使用ImageSource.getImageInfo()方法获取图片宽、高信息,使用ImageSource.createPixelMap()方法创建PixelMap对象。

export async function imageSource2PixelMap(imageSource: image.ImageSource): Promise<ImagePixelMap> {
  const imageInfo: image.ImageInfo = await imageSource.getImageInfo();
  const height = imageInfo.size.height;
  const width = imageInfo.size.width;
  const options: image.DecodingOptions = {
    editable: true,
    desiredSize: { height, width }
  };
  const pixelMap: PixelMap = await imageSource.createPixelMap(options);
  const result: ImagePixelMap = { pixelMap, width, height };
  return result;
}

export interface ImagePixelMap {
  pixelMap: image.PixelMap
  width: number
  height: number
}

3.封装添加水印的方法

export function addWatermark(
  imagePixelMap: ImagePixelMap,
  text: string = '自定义水印',
  text2: string = '自定义水印时间',
  drawWatermark?: (OffscreenContext: OffscreenCanvasRenderingContext2D) => void
): image.PixelMap {
  const height = px2vp(imagePixelMap.height);
  const width = px2vp(imagePixelMap.width);
  const offScreenCanvas = new OffscreenCanvas(width, height);
  const offScreenContext = offScreenCanvas.getContext('2d');
  offScreenContext.drawImage(imagePixelMap.pixelMap, 0, 0, width, height);
  if (drawWatermark) {
    drawWatermark(offScreenContext);
  } else {
    const imageScale = width / px2vp(display.getDefaultDisplaySync().width);
    offScreenContext.textAlign = 'right';
    offScreenContext.fillStyle = '#A2FFFFFF';
    offScreenContext.font = 16 * imageScale + 'vp';
    const padding = 5 * imageScale;
    offScreenContext.fillText(text, width - padding, height - padding - 18);
    offScreenContext.fillText(text2, width - padding, height - padding);
  }
  return offScreenContext.getPixelMap(0, 0, width, height);
}

4.封装下载图片的方法

export async function saveToFile(pixelMap: image.PixelMap, context: Context) {
  try {
    const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context)
    const filePath = await phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png')
    // AlertDialog.show({ message: JSON.stringify(filePath, null, 2) })

    const imagePacker = image.createImagePacker()
    const imageBuffer = await imagePacker.packing(pixelMap, {
      format: 'image/png',
      quality: 80
    })
    const mode = fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE;
    fd = (await fileIo.open(filePath, mode)).fd;
    await fileIo.truncate(fd);
    await fileIo.write(fd, imageBuffer);
  } catch (err) {
    hilog.error(0x0000, TAG, 'saveToFile error:', JSON.stringify(err) ?? '');
    // AlertDialog.show({ message: JSON.stringify(err, null, 2) })
  } finally {
    if (fd) {
      fileIo.close(fd);
    }
  }
}

二、调用方法实现添加水印

  @State addedWatermarkPixelMap: image.PixelMap | null = null;
  

async aboutToAppear() {
    const imagePixelMap = await this.getImagePixelMap($r('app.media.img1'))
    //显示图片
    this.addedWatermarkPixelMap = addWatermark(imagePixelMap)
  }

三、使用安全控件SaveButton保存图片到相册

 SaveButton({ text: SaveDescription.SAVE })
          .backgroundColor('#00ffffff')
          .fontColor(Color.Black)
          .onClick(async () => {
            try {
              if (this.addedWatermarkPixelMap === null) {
                return
              }
              await saveToFile(this.addedWatermarkPixelMap, getContext(this))
            } catch (err) {
              AlertDialog.show({ message: JSON.stringify('保存失败', null, 2) })
            }

          })

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值