HarmonyOS:照片添加多样式的水印信息

前言:ArkTS语言中照片添加水印常见用法总结和整理,目前常见的旋转铺满全屏水印,区域水印,底部带背景色的水印,以及图文混排的水印。 这篇文章对各种用法都进行了归纳整理。

HomePage示例图片显示

scss 复制代码
Button('Single: Diagonal Watermark')
          .onClick(() => this.handleWaterMarkAddition(LXWaterMarkStyle.Default))
          .height(30)
        Button('Single: Top-Left Watermark')
          .onClick(() => this.handleWaterMarkAddition(LXWaterMarkStyle.LeftTop))
          .height(30)
        Button('Single: Bottom-Right Watermark')
          .onClick(() => this.handleWaterMarkAddition(LXWaterMarkStyle.RightBottom))
          .height(30)
        Button('Multiple: Diagonal Watermark')
          .onClick(() => this.handleWaterMarkAddition(LXWaterMarkStyle.MoreDefault, true))
          .height(30)

各种样式水印添加方法如上所示。

核心的代码封装类:

复制代码
LXWaterMarkMgr.ets

水印信息封装类:

复制代码
LXWaterMarkInfo

水印信息配置类:

复制代码
LXWaterMarkFillOption

水印样式配置枚举:

复制代码
LXWaterMarkStyle

照片信息类:

复制代码
LXImagePixelMap

水印绘制器抽象:

复制代码
LXWaterMarkDrawer

好处是,所有的水印都继承于LXWaterMarkDrawer的方法实现,简单明了。

ini 复制代码
// 水印绘制器抽象
abstract class LXWaterMarkDrawer {
  abstract draw(
    offScreenCanvas: OffscreenCanvasRenderingContext2D,
    imagePixelMap: LXImagePixelMap,
    waterMarkInfoList: LXWaterMarkInfo[],
    option: LXWaterMarkFillOption,
    scale: number,
    canvasSize?:SizeOptions
  ): Promise<void>;
}
// 默认水印绘制器
class DefaultWaterMarkDrawer extends LXWaterMarkDrawer {
  async draw(
    iOffScreenContext: OffscreenCanvasRenderingContext2D,
    imagePixelMap: LXImagePixelMap,
    waterMarkInfoList: LXWaterMarkInfo[],
    option: LXWaterMarkFillOption,
    scale: number,
    canvasSize?:SizeOptions
  ): Promise<void> {
    const waterInfo = waterMarkInfoList.length>0?waterMarkInfoList[0]:'';
    const waterMarkInfo = (waterInfo&&waterInfo.content.length>0)?waterInfo.content:'水印信息';
    const waterMarkW = 120;
    const waterMarkH = 120;
    const rotationAngle = -30;

    iOffScreenContext.font = `${16 * scale}vp`;
    const iWidth = canvasSize?canvasSize.width: DisplayUtil.getWidth();
    const iHeight = canvasSize?canvasSize.height: DisplayUtil.getHeight();

    const colCount = Math.ceil(iWidth as number / waterMarkW);
    const rowCount = Math.ceil(iHeight as number / waterMarkH);

    for (let col = 0; col < colCount; col++) {
      for (let row = 0; row <= rowCount; row++) {
        iOffScreenContext.save();
        iOffScreenContext.translate(col * waterMarkW, row * waterMarkH);
        iOffScreenContext.rotate((rotationAngle * Math.PI) / 180);
        iOffScreenContext.fillText(waterMarkInfo, 0, 0);
        iOffScreenContext.restore();
      }
    }
  }
}

核心的水印信息绘制代码如下:

1.创建画布

2.绘制原始图片

3.设置画布的属性

4.绘制水印(通过水印绘制器工厂get到每个样式的绘制器进行单独绘制)

ini 复制代码
export async function addWaterMarkWithContext(
  context: UIContext,
  imagePixelMap: LXImagePixelMap,
  waterMarkInfoList?: LXWaterMarkInfo[],
  waterMarkFillOption?: LXWaterMarkFillOption,
  customDrawer?: (ctx: OffscreenCanvasRenderingContext2D) => void
): Promise<image.PixelMap> {
  if (!context) {
    LogUtil.error('Context is undefined, returning original image');
    ToastUtil.showToast('Context为空,返回原图');
    return imagePixelMap.pixelMap;
  }
  // 创建离屏画布
  const iHeight = context.px2vp(imagePixelMap.height);
  const iWidth = context.px2vp(imagePixelMap.width);
  const offScreenCanvas = new OffscreenCanvas(iWidth, iHeight);
  const offScreenContext = offScreenCanvas.getContext('2d');

  if (!offScreenContext) {
    throw new Error('Failed to create offscreen context');
  }
  // 绘制原始图片
  offScreenContext.drawImage(imagePixelMap.pixelMap, 0, 0, iWidth, iHeight);

  // 自定义或自动水印
  if (customDrawer) {
    customDrawer(offScreenContext);
  } else if (waterMarkFillOption && waterMarkInfoList?.length) {
    const scale = await calculateImageScale(context, iWidth);
    const drawer = WaterMarkDrawerFactory.getDrawer(waterMarkFillOption.waterMartStyle);
    // 设置全局画布属性
    offScreenContext.textAlign = waterMarkFillOption.textAlign || 'left';
    offScreenContext.fillStyle = waterMarkFillOption.textFillStyle || '#A2FFFFFF';
    offScreenContext.globalAlpha = waterMarkFillOption.textGlobalAlpha || 1.0;
    //绘制水印
    await drawer.draw(offScreenContext, imagePixelMap, waterMarkInfoList, waterMarkFillOption, scale,{width:iWidth,height:iHeight});
  }

  return offScreenContext.getPixelMap(0, 0, iWidth, iHeight);
}
详细demo工程:

gitcode.com/luxingxing1... 如有使用请注明来源,不要直接上传的官方Demo工程。

效果图:

相关推荐
前端冒菜师2 小时前
记一次AI全栈开发的过程
前端·ai编程
Giant1002 小时前
深度玩转 Cursor Rules:让 AI 生成的代码 100% 符合团队规范
前端·面试
代码煮茶2 小时前
Vue3 组件通信实战 | 8 种组件通信方式全解析
前端·vue.js
kyriewen2 小时前
自定义事件:让代码之间也能“悄悄对话”
前端·javascript·面试
子兮曰2 小时前
别把它当成一次普通“源码泄露”:Claude Code 事件给 AI Agent 团队提了什么醒
前端·npm·claude
心之语歌2 小时前
Vue2 data + Vue3 ref/reactive 核心知识点总结
开发语言·前端·javascript
诸葛亮的芭蕉扇2 小时前
tooltip-position-solution
前端·vue.js·elementui
LXXgalaxy3 小时前
`摸鱼决策轮盘`【vue3+ts前端实战小项目】
前端
这是个栗子3 小时前
关于 TypeScript 的介绍
前端·javascript·typescript