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

前言:ArkTS语言中照片添加水印常见用法总结和整理,目前常见的旋转铺满全屏水印,区域水印,底部带背景色的水印,以及图文混排的水印。

这篇文章对各种用法都进行了归纳整理。

HomePage示例图片显示

复制代码
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的方法实现,简单明了。

复制代码
// 水印绘制器抽象
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到每个样式的绘制器进行单独绘制)

复制代码
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工程:

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

效果图:


相关推荐
Lanren的编程日记1 天前
Flutter鸿蒙应用开发:网络请求优化实战,全方位提升请求稳定性与性能
网络·flutter·harmonyos
IntMainJhy1 天前
【futter for open harmony】Flutter 鸿蒙聊天应用实战:shared_preferences 本地键值存储适配指南[特殊字符]
flutter·华为·harmonyos
IntMainJhy1 天前
【Flutter for OpenHarmony 】第三方库鸿蒙电商实战|首页模块完整实现[特殊字符]
flutter·华为·harmonyos
以太浮标1 天前
华为eNSP模拟器综合实验之- 华为设备 LLDP(Link Layer Discovery Protocol)解析
运维·服务器·网络·网络协议·华为·信息与通信·信号处理
Lanren的编程日记1 天前
Flutter 鸿蒙应用离线模式实战:无网络也能流畅使用
网络·flutter·harmonyos
IntMainJhy1 天前
【Flutter for OpenHarmony 】第三方库 聊天应用:Provider 状态管理实战指南
flutter·华为·harmonyos
想你依然心痛1 天前
HarmonyOS 6金融应用实战:基于悬浮导航与沉浸光感的“光影财富“智能投顾系统
金融·harmonyos·鸿蒙·悬浮导航·沉浸光感
互联网散修1 天前
鸿蒙星闪实战:从零实现高速可靠的跨设备文件传输 - 星闪篇
华为·harmonyos
小红星闪啊闪1 天前
鸿蒙开发速通(一)
harmonyos