【解决方案】HarmonyOS图片添加水印

 实现思路:从相册中算选择图片,将图片展示到UI界面,利用核心方法drawImage将要添加的水印画到图片上,然后将图片保存。

1、从相册中选取图片,添加水印,并返回添加水印后的图片保存路径

async pickerAcvtor(waterStr: string[]) {
    // 实例化选择参数对象
    const options = new picker.PhotoSelectOptions()
    options.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE
    options.maxSelectNumber = 1

    // 实例化选择器对象
    const pickerView = new picker.PhotoViewPicker()
    let res = await pickerView.select(options)


    // 判断用户取消了选择图片,则组织下面代码的继续运行
    if (res.photoUris.length === 0) {
      promptAction.showToast({ message: "用户取消图片选择" })
      return
    }
    //  准备好图片的完整路径
    let ext = 'jpg'
    let fileName = Date.now().toString()
    let cacheDir = getContext().cacheDir
    let fullPath = cacheDir + '/' + fileName + '.' + ext
    //  利用fileIo拷贝图片
    let file = fileIo.openSync(res.photoUris[0], fileIo.OpenMode.READ_ONLY)
    fileIo.copyFileSync(file.fd, fullPath)
    this.imgPath = fullPath

    addWaterMarkManager.addWaterImage(this.imgPath, waterStr, this.fillColor)
      .then((pixelMap?: image.PixelMap) => {
        if (pixelMap) {
          this.pixelMap = pixelMap;
        }
      })
    return this.imgPath
  }

2、addWaterImage方法类型的封装

class AddWaterMarkManager {
  private pixelMap?: image.PixelMap = undefined;
  private TAG: string = 'imageEdit';
  // 设置水印文字显示比例
  private scale = 12.0 / 375;

  /**
   * 获取加水印图片pixelMap
   *
   * @param imageSource ImageSource 图片描述
   * @param waterStr 水印数组
   * @param imageWidth 显示控件宽度默认50
   * @returns
   */
  public async addWaterImage(imgPath: string, waterStr: string[], fillColor: string): Promise<image.PixelMap> {
    //waterstr最后的数据渲染到页面最上边
    let newStr = this.waterStrSort(waterStr)
    let imgResource = image.createImageSource(imgPath)
    // 获取图片信息
    const imageInfo = imgResource.getImageInfoSync();
    const pixelMap = await imgResource.createPixelMap({
      editable: true
    });

    let returnPixelMap = this.getPixelMap(imageInfo, pixelMap, newStr, fillColor)
    return returnPixelMap
    // return imgPath
  }

  /**
   * 获取加水印图片pixelMap
   *
   * @param imageSource ImageSource 图片描述
   * @param waterStr 水印数组
   * @param imageWidth 显示控件宽度默认50
   * @returns
   */
  public async addWaterpixelMap(pixelMap: PixelMap, waterStr: string[], fillColor: string): Promise<image.PixelMap> {
    //waterstr最后的数据渲染到页面最上边
    let newStr = this.waterStrSort(waterStr)

    // 获取图片信息
    const imageInfo = pixelMap.getImageInfoSync();

    let returnPixelMap = this.getPixelMap(imageInfo, pixelMap, newStr, fillColor)
    return returnPixelMap
  }

  private waterStrSort(strlist: string[]) {
    let newList: string[] = []
    for (let index = 0; index < strlist.length; index++) {
      newList.push(strlist[strlist.length - index-1])
    }
    return newList
  }

  private getPixelMap(imageInfo: image.ImageInfo, pixelMap: image.PixelMap, newStr: string[], fillColor: string) {
    // 这个回调的pixelMap就是当前图片的pixelMap
    let offScreenCanvas = new OffscreenCanvas(imageInfo.size.width, imageInfo.size.height)
    let OffScreenContext = offScreenCanvas.getContext("2d")
    OffScreenContext.drawImage(pixelMap, 0, 0, offScreenCanvas.width, offScreenCanvas.height)
    pixelMap.release();

    // 判断水印内容是否为空
    if (newStr != undefined && newStr.length > 0) {
      let resultString = newStr.join("\n");
      // 设置字体大小
      OffScreenContext.fillStyle = fillColor
      OffScreenContext.font = this.scale * imageInfo.size.width + "vp";
      OffScreenContext.textAlign = 'right';
      OffScreenContext.textBaseline = 'bottom';
      OffScreenContext.fillText(resultString, offScreenCanvas.width - 150, offScreenCanvas.height - 100)
    }
    // 获取新的PixelMap
    return OffScreenContext.getPixelMap(0, 0, offScreenCanvas.width, offScreenCanvas.height)
  }

  /**
   * 获取加水印图片pixelMap
   *
   * @param fd 文件id
   * @param waterStr 水印数组
   * @param imageWidth 显示控件宽度默认50
   * @returns
   */
  private async getFdWaterPixelMap(fd: number, waterStr: string[], fillColor: string) {
    const imageSourceApi = image.createImageSource(fd);
    if (!imageSourceApi) {
      console.log(this.TAG, 'imageSourceAPI created failed!');
    }
    // 获取图片信息
    const imageInfo = imageSourceApi.getImageInfoSync();
    const pixelMap = await imageSourceApi.createPixelMap({
      editable: true
    });

    let returnPixelMap = this.getPixelMap(imageInfo, pixelMap, waterStr, fillColor)
    return returnPixelMap
  }
}

const addWaterMarkManager = new AddWaterMarkManager()

export { addWaterMarkManager }

3、UI界面渲染

  build() {
    Scroll() {
      Column({ space: 20 }) {
        this.titleBuilder()

        Image(this.pixelMap)
          .objectFit(ImageFit.Contain)
          .width('100%')
          .layoutWeight(1)
          .borderRadius($r('app.float.tab_bar_item_font_size'))
        Blank().layoutWeight(1)

      }
      .width('100%')
      .align(Alignment.Bottom)
      .backgroundColor(Color.Black)
      .padding({
        top: this.topBar,
        right: 10,
        left: 10,
        bottom: 20
      })
    }
    .height('150%')
    .width('100%')
  }

  @Builder
  titleBuilder() {
    Row() {
      Image($r('app.media.ic_left_row'))
        .width($r('app.float.common_font20vp'))
        .aspectRatio(1)
        .fillColor(Color.White)
        .onClick(() => {
          router.back();
        });

      Text('选取图片').fontColor(Color.White)
        .fontSize($r('app.float.common_font14'))
        .onClick(async () => {
          let waterImgPath = await this.pickerAcvtor(this.strings)
          AlertDialog.show({ message: `返回图片路径:${waterImgPath}` });
        });

      Text('完成').fontColor(Color.White)
        .fontSize($r('app.float.common_font14'))
        .onClick(() => {
          AlertDialog.show({ message: `返回图片路径:${this.imgPath}` });
        });
    }
    .width('100%')
    .justifyContent(FlexAlign.SpaceAround)
    .padding({ right: $r('app.float.tab_bar_item_icon_size'), left: $r('app.float.tab_bar_item_icon_size') })
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值