概要
使用ArkTS在HarmonyNext系统上,实现图片增加文字水印
整体架构流程
1、使用Stack组件作为根容器,并设置id为“root”
Stack() {
Image(this.bgImg)
.width('100%')
.draggable(false)
.objectFit(ImageFit.Contain)
.onAreaChange((oldArea: Area, newArea: Area) => {
if ((oldArea.width != newArea.width || oldArea.height != newArea.height) && newArea.width > 0 && newArea.height > 0) {
this.canvasWidth = newArea.width as number
this.canvasHeight = newArea.height as number
this.offContext2D = new OffscreenCanvasRenderingContext2D(this.canvasWidth, this.canvasHeight, this.settings)
this.offContext2D.fillStyle = '#1F000000'
this.offContext2D.font = '18vp sans-serif'
}
})
Canvas(this.context2D)
.width(this.canvasWidth)
.height(this.canvasHeight)
}
.width('100%')
.height('100%')
.align(Alignment.Center)
.id("root")
2、通过系统相册选择图片,并使用Image组件显示,作为背景图
openGallery() {
try {
let PhotoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
PhotoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
PhotoSelectOptions.maxSelectNumber = 1;
let photoPicker = new photoAccessHelper.PhotoViewPicker();
photoPicker.select(PhotoSelectOptions).then((photoSelectResult: photoAccessHelper.PhotoSelectResult) => {
if (photoSelectResult.photoUris.length > 0) {
this.bgImg = photoSelectResult.photoUris[0]
this.maskText = ''
}
console.info('PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + JSON.stringify(photoSelectResult));
}).catch((err: BusinessError) => {
console.error(`PhotoViewPicker.select failed with err: ${err.code}, ${err.message}`);
});
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error(`PhotoViewPicker failed with err: ${err.code}, ${err.message}`);
}
}
3、在Image组件上叠加Canvas组件,并通过Canvas绘制文字
watchMaskText() {
this.offContext2D.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
this.context2D.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
this.offContext2D.saveLayer()
this.offContext2D.rotate(-45 * Math.PI / 180)
let cols = Math.sqrt(this.canvasWidth * this.canvasWidth + this.canvasHeight * this.canvasHeight) / 100
for (let i = 0; i < cols; i++) {
let x = (-cols / 2 + i) * 200
for(let j = 0; j < 100; j++) {
this.offContext2D.fillText(this.maskText, x, (i * j) * 50)
}
}
this.offContext2D.rotate(45 * Math.PI / 180)
this.offContext2D.restoreLayer()
let image = this.offContext2D.transferToImageBitmap()
if (image) {
this.context2D.transferFromImageBitmap(image)
image.close()
}
}
4、对根容器截图,保存到媒体库
save() {
componentSnapshot.get("root", async (error: Error, pixmap: image.PixelMap) => {
if (error) {
console.log("error: " + JSON.stringify(error))
return;
}
try {
let packOpts: image.PackingOption = { format: "image/jpeg", quality: 100 }
let arrayBuffers: ArrayBuffer = await this.imageImagePacker.packing(pixmap, packOpts)
let result = await savePhoto(getContext(this), arrayBuffers)
promptAction.showToast({message: result ? '图片已保存到系统相册' : '图片保存失败'})
} catch (error) {
console.error("error is "+ JSON.stringify(error));
}
}, {scale : 2, waitUntilRenderFinished : true})
}
技术名词解释
- Stack:层叠布局
- Image:图片显示组件
- Canvas:画布组件
技术细节
保存图片到媒体库,有两种方式:
参考文档保存媒体库资源-Media Library Kit(媒体文件管理服务)-媒体 - 华为HarmonyOS开发者
方式1:申请受限权限,获取文件读写的权限(调用需要ohos.permission.READ_IMAGEVIDEO和ohos.permission.WRITE_IMAGEVIDEO的权限),这样就可以将媒体资源保存到媒体库。 参考文档 申请使用受限权限-申请应用权限-应用权限管控-程序访问控制-安全-系统 - 华为HarmonyOS开发者
方式2:通过安全控件,每次保存图片时需要用户手动授权 参考文档安全控件概述-使用安全控件-程序访问控制-安全-系统 - 华为HarmonyOS开发者
小结
Demo可参考WaterMask: 水印工具