##HarmonyOS Next实战##HarmonyOS SDK应用服务##教育##
在软件开发中,水印是一种在应用页面、图片或文档中嵌入的标记,它通常采用文字或图案的形式展现。水印通常有以下用途:
- 标识来源:可用于标识应用、各种文件的来源或作者,确保产权的归属。
- 版权保护:可携带版权保护信息,有效防止他人篡改、盗用、非法复制。
- 艺术效果:可作为一种艺术效果,为图片或应用增添独特的风格。
实现思路:
- 创建Canvas画布,在画布上绘制水印。
- 使用浮层overlay属性,将画布与UI页面组件融合显示。
知识点: Canvas提供画布组件,用于自定义绘制图形。使用CanvasRenderingContext2D对象在Canvas组件上进行绘制,其中fillText()方法用于绘制文本,drawImage()方法用于图像绘制。
Canvas.onReady Canvas组件初始化完成时或者Canvas组件发生大小变化时的事件回调。 当该事件被触发时画布被清空,该事件之后Canvas组件宽高确定且可获取,可使用Canvas相关API进行绘制。当Canvas组件仅发生位置变化时,只触发onAreaChange事件,不触发onReady事件。onAreaChange事件在onReady事件后触发。
Canvas.hitTestBehavior 设置组件的触摸测试类型。默认值: HitTestMode.Default
实现绘制水印draw()方法。绘制的起点默认为坐标轴的原点(画布的左上角),通过坐标轴的平移及旋转,实现在画布的不同位置、不同角度绘制水印。如果水印有一定旋转角度,想保证第一个水印能完整显示,需要对绘制的起点做平移,平移距离通过旋转角度及水印宽高计算。 最终通过CanvasRenderingContext2D.fillText()方法进行水印文字的绘制。
fillText(text: string, x: number, y: number, maxWidth?: number): void
绘制填充类文本。 text:需要绘制的文本内容。 x:需要绘制的文本的左下角x坐标。默认单位:vp。 y:需要绘制的文本的左下角y坐标。默认单位:vp。 maxWidth:指定文本允许的最大宽度。默认单位:vp。默认值:不限制宽度。
创建水印:BuildWatermark
@Builder
export function BuildWatermark() {
Watermark()
.width('100%')
.height('100%')
}
@Component
struct Watermark {
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
@Prop watermarkWidth: number = 120;
@Prop watermarkHeight: number = 120;
@Prop watermarkText: string = '这是文字水印';
@Prop rotationAngle: number = -30;
@Prop fillColor: string | number | CanvasGradient | CanvasPattern = '#10000000';
@Prop font: string = '16vp';
build() {
Canvas(this.context)
.width('100%')
.height('100%')
.hitTestBehavior(HitTestMode.Transparent)
.onReady(() => this.draw())
}
draw() {
this.context.fillStyle = this.fillColor;
this.context.font = this.font;
const colCount = Math.ceil(this.context.width / this.watermarkWidth);
const rowCount = Math.ceil(this.context.height / this.watermarkHeight);
for (let col = 0; col <= colCount; col++) {
let row = 0;
for (; row <= rowCount; row++) {
const angle = this.rotationAngle * Math.PI / 180;
this.context.rotate(angle);
const positionX = this.rotationAngle > 0 ? this.watermarkHeight * Math.tan(angle) : 0;
const positionY = this.rotationAngle > 0 ? 0 : this.watermarkWidth * Math.tan(-angle);
this.context.fillText(this.watermarkText, positionX, positionY);
this.context.rotate(-angle);
this.context.translate(0, this.watermarkHeight);
}
this.context.translate(0, -this.watermarkHeight * row);
this.context.translate(this.watermarkWidth, 0);
}
}
}
使用水印:
import { BuildWatermark } from './BuildWatermark';
@Entry
@Component
struct WatermarkDemoPage {
@State message: string = 'WatermarkDemo';
build() {
Column() {
Text(this.message)
.fontWeight(FontWeight.Bold)
}
.height('100%')
.width('100%')
.overlay(BuildWatermark())
}
}