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工程。

效果图:

相关推荐
索西引擎几秒前
【React】Immer.js 在现代 Redux 生态中的角色:不可变性保障的工程化实现与开发体验优化
前端·javascript·react.js
大卫陈12 分钟前
微信小程序虚拟支付实战:从「支付能力被限制」到沙箱调通的全过程
前端·后端
武子康12 分钟前
vLLM 0.25.1:服务没有报错,为什么仍会生成垃圾 Token(5 级正确性门禁 + 自动回滚条件)
前端·人工智能·后端
jyp2012110716 分钟前
Vue3 Diff 算法
前端·vue.js
胡萝卜术20 分钟前
抽象的三级跳:从原生 DOM 到 React 组件树,我们到底在解决什么问题?
前端·javascript·面试
黄敬峰23 分钟前
从零理解React:事件、组件与响应式——一个WebGPU Demo的前端笔记
前端·面试
weedsfly37 分钟前
从类继承到自定义 Hook:模板方法模式的前端演进
前端·javascript·面试
Quz38 分钟前
QML 线性布局:Row/RowLayout 与 Column/ColumnLayout
前端·qt
你为她披上外套时我正站在窗外42 分钟前
用 Rust + WebAssembly 写了个字幕工具,文件全程不离开浏览器
前端
帅帅哥的兜兜42 分钟前
AI模型初了解
前端