马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
场景描述
添加水印是一个比较常见的功能,下面枚举一些遇到的业务需求:
- 场景一:在页面配景上添加全局水印
- 场景二:生存图片添加水印
- 场景三:照相添加水印
- 场景四:window级别的全局水印
方案描述
场景一:
在页面配景上添加全局水印
效果图:
方案
页面全局水印的实现思路是利用透明配景的canvas画布绘制文字水印,在利用Stack组件叠加在page跟容器上
方式一:利用canvas进行绘制
- Stack({ alignContent: Alignment.Center }) {
- Column() {
- Text("没有数据哦").fontColor("#495057")
- Image($r("app.media.empty")).width(300)
- }
- Canvas(this.context)
- .width("100%")
- .height("100%")
- .hitTestBehavior(HitTestMode.Transparent)
- .onReady(() => {
- this.context.fillStyle = '#10000000'
- this.context.font = "16vp"
- this.context.textAlign = "center"
- this.context.textBaseline = "middle"
- // 在这里绘制文字水印,也可以是图片水印
- for (let i = 0; i < this.context.width / 120; i++) {
- this.context.translate(120, 0)
- let j = 0
- for (; j < this.context.height / 120; j++) {
- this.context.rotate(-Math.PI / 180 * 30)
- // 此处水印数据是写死的,具体请替换为自己的水印
- this.context.fillText("水印水印水印", -60, -60)
- this.context.rotate(Math.PI / 180 * 30)
- this.context.translate(0, 120)
- }
- this.context.translate(0, -120 * j)
- }
- })
- }.layoutWeight(1)
复制代码 方式二:利用overlay属性绘制
方式二思路与方式一实现思路一致,该方式可以讲水印组件单独拧出来,在其他利用时利用overlay属性来利用,实现效果与方式一一致
- @Builder
- Watermark() {
- Canvas(this.context)
- .width("100%")
- .height("100%")
- .hitTestBehavior(HitTestMode.Transparent)
- .onReady(() => {
- this.context.fillStyle = '#10000000'
- this.context.font = "16vp"
- this.context.textAlign = "center"
- this.context.textBaseline = "middle"
- // 在这里绘制文字水印,也可以是图片水印
- for (let i = 0; i < this.context.width / 120; i++) {
- this.context.translate(120, 0)
- let j = 0
- for (; j < this.context.height / 120; j++) {
- this.context.rotate(-Math.PI / 180 * 30)
- // 此处水印数据是写死的,具体请替换为自己的水印
- this.context.fillText("水印水印水印", -60, -60)
- this.context.rotate(Math.PI / 180 * 30)
- this.context.translate(0, 120)
- }
- this.context.translate(0, -120 * j)
- }
- })
- }
- Column() {
- Text("没有数据哦").fontColor("#495057")
- Image($r("app.media.empty")).width(300)
- }
- .layoutWeight(1)
- .overlay(this.Watermark())
- .width("100%")
复制代码 场景二:
生存图片添加水印
方案
利用OffScreenCanvas离屏画布拿到图片源数据,在离屏画布上利用OffscreenCanvasRenderingContext2D.drawImage方法讲图片数据进行绘制,利用OffscreenCanvasRenderingContext2D.fillText方法绘制文字水印,通过 OffscreenCanvasRenderingContext2D.getPixelMap方法获取添加水印后的图片pixelMap数据,再通过安全控件方式拿到图库的uri路径,在这个uri下通过image.createImagePacker方法创建图片文件,通过fs.write方法写入这个图库的文件中,具体实当代码如下所示
核心代码
第一步:利用resourceManager.getMediaContent方法获取当前的图片资源
- getContext(this).resourceManager.getMediaContent($r(this.imagePath)).then((data) => {
- // ...
- }).catch((err: BusinessError) => {
- console.log("getPixelMap error" + err.message)
- })
复制代码 第二步:利用image.createImageSource方法创建图片资源,在利用OffscreenCanvasRenderingContext2D.drawImage方法绘制图片在离屏画布上
- let arrayBuffer = data.buffer.slice(data.byteOffset, data.byteLength + data.byteOffset)
- let imageSource: image.ImageSource = image.createImageSource(arrayBuffer);
- imageSource.getImageInfo((err, value) => {
- if (err) {
- return;
- }
- let opts: image.DecodingOptions = {
- editable: true,
- desiredSize: {
- height: value.size.height,
- width: value.size.width
- }
- };
- imageSource.createPixelMap(opts, async (err, pixelMap) => {
- // 这个回调的pixelMap就是当前图片的pixelMap
- let offScreenCanvas = new OffscreenCanvas(value.size.width, value.size.height)
- let OffScreenContext = offScreenCanvas.getContext("2d")
- this.imageScale = offScreenCanvas.width / display.getDefaultDisplaySync().width
- OffScreenContext.drawImage(pixelMap, 0, 0, offScreenCanvas.width, offScreenCanvas.height)
- // ...
- })
- })
复制代码 第三步:利用OffscreenCanvasRenderingContext2D.fillText绘制水印
- getContext(this).resourceManager.getMediaContent($r(this.imagePath)).then((data)
- let arrayBuffer = data.buffer.slice(data.byteOffset, data.byteLength + data.byteOffset)
- let imageSource: image.ImageSource = image.createImageSource(arrayBuffer);
- imageSource.getImageInfo((err, value) => {
- if (err) {
- return;
- }
- let opts: image.DecodingOptions = {
- editable: true,
- desiredSize: {
- height: value.size.height,
- width: value.size.width
- }
- };
- imageSource.createPixelMap(opts, async (err, pixelMap) => {
- // ...
- OffScreenContext.textAlign = "right"
- OffScreenContext.textBaseline = "bottom"
- OffScreenContext.fillStyle = '#30000000'
- OffScreenContext.font = 32 * this.imageScale + "vp"
- OffScreenContext.fillText("初九会画画", offScreenCanvas.width - 20 * this.imageScale, offScreenCanvas.height - 20 * this.imageScale)
- // ...
- })
- })
- }).catch((err: BusinessError) => {
- console.log("getPixelMap error" + err.message)
- })
复制代码 第四步:利用OffscreenCanvasRenderingContext2D.getPixelMap取出绘制后的图片数据
- // 获取新的PixelMap
- this.pixelMap = OffScreenContext.getPixelMap(0, 0, offScreenCanvas.width, offScreenCanvas.height)
复制代码 第五步:利用SaveButton生存到图库中
- SaveButton({ icon: SaveIconStyle.FULL_FILLED }).onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => {
- if (result == SaveButtonOnClickResult.SUCCESS) {
- try {
- let context = getContext(this);
- let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
- let uri = await phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg'); // 创建媒体文件
- this.imagePath = "app.media.img1"
- this.addWatermark()
- if (this.pixelMap) {
- saveToFile(this.pixelMap, uri)
- }
- } catch (err) {
- console.error('createAsset failed, message = ', err);
- }
- } else {
- console.error('SaveButtonOnClickResult createAsset failed');
- }
- })
复制代码 场景三:
照相添加水印
方案
利用cameraPicker拉起系统相机照相,拿到返回的picker.PickerResult.resultUri后利用fs.openSync读出图片文件转化为pixelMap,利用image组件渲染在页面上,在生存图片的时候通过drawing.TextBlob.makeFromString方法绘制水印后生存
核心代码
第一步:利用cameraPicker拉起系统相机
- import picker from '@ohos.multimedia.cameraPicker';
- import camera from '@ohos.multimedia.camera';
- async openCamera() {
- try {
- let pickerProfile: picker.PickerProfile = {
- cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK
- };
- let pickerResult: picker.PickerResult = await picker.pick(getContext(this),
- [picker.PickerMediaType.PHOTO, picker.PickerMediaType.VIDEO], pickerProfile);
- console.log("the pick pickerResult is:" + JSON.stringify(pickerResult));
- // ...
- } catch (error) {
- let err = error as BusinessError;
- console.error(`the pick call failed. error code: ${err.message}`);
- }
- }
复制代码 第二步:将相机拍摄的照片渲染在页面中,利用fs.readSync读出文件字节流,再利用image.createImageSource创建图片资源管理器获取到图片的pixelMap
- @State pixelMap: image.PixelMap | null = null
- async openCamera() {
- try {
- // ...
- if (pickerResult.resultUri) {
- this.showImage = true
- }
- let file = fs.openSync(pickerResult.resultUri)
- let buffer = new ArrayBuffer(fs.statSync(file.fd).size)
- fs.readSync(file.fd, buffer)
- let imageSource: image.ImageSource = image.createImageSource(buffer)
- imageSource.getImageInfo((err, value) => {
- if (err) {
- return;
- }
- let opts: image.DecodingOptions = {
- editable: true,
- desiredSize: {
- height: value.size.height,
- width: value.size.width
- }
- };
- imageSource.createPixelMap(opts, async (err, pixelMap) => {
- this.pixelMap = pixelMap
- })
- })
- } catch (error) {
- let err = error as BusinessError;
- console.error(`the pick call failed. error code: ${err.message}`);
- }
- }
- build() {
- // ...
- if(this.showImage) {
- Image(this.pixelMap).width("100%")
- // ...
- }
- }
复制代码 第三步:利用drawing.TextBlob.makeFromString绘制水印后 利用SaveButton生存在系统相册中
- addWaterMask(pixelMap: image.PixelMap) {
- this.imageScale = this.imageWidth / display.getDefaultDisplaySync().width
- const canvas = new drawing.Canvas(pixelMap)
- const pen = new drawing.Pen()
- pen.setColor({ alpha: 255, red: 0, green: 10, blue: 10 })
- const font = new drawing.Font()
- font.setSize(32 * this.imageScale)
- let textWidth = font.measureText("初九会画画", drawing.TextEncoding.TEXT_ENCODING_UTF8)
- const brush = new drawing.Brush()
- brush.setColor({ alpha: 255, red: 255, green: 0, blue: 0 })
- const textBlob = drawing.TextBlob.makeFromString("初九会画画", font, drawing.TextEncoding.TEXT_ENCODING_UTF8)
- canvas.attachBrush(brush)
- canvas.attachPen(pen)
- canvas.drawTextBlob(textBlob, this.imageWidth - 20 * this.imageScale - textWidth, this.imageHeight - 20 * this.imageScale)
- canvas.detachBrush();
- canvas.detachPen()
- return pixelMap
- }
- SaveButton()
- .onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => {
- if (result == SaveButtonOnClickResult.SUCCESS) {
- try {
- let context = getContext(this);
- let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
- let uri = await phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png'); // 创建媒体文件
- saveToFile(this.addWaterMask(this.pixelMap!), uri);
- } catch (err) {
- console.error('createAsset failed, message = ', err);
- }
- } else {
- console.error('SaveButtonOnClickResult createAsset failed');
- }
- })
复制代码 最后
小编在之前的鸿蒙系统扫盲中,有很多朋侪给我留言,差异的角度的问了一些问题,我明显感觉到一点,那就是很多人参与鸿蒙开辟,但是又不知道从那里动手,因为资料太多,太杂,传授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开辟技术?不知道需要重点把握哪些鸿蒙应用开辟知识点?而且学习时频繁踩坑,最终浪费大量时间。以是有一份实用的鸿蒙(HarmonyOS NEXT)文档用来跟着学习黑白常有必要的。
为了确保高效学习,发起规划清楚的学习路线,涵盖以下关键阶段:
→【纯血版鸿蒙全套最新学习文档】渴望这一份鸿蒙学习文档能够给大家带来帮助~
鸿蒙(HarmonyOS NEXT)最新学习路线
该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级装备开辟,不仅增补了华为官网未涉及的办理方案
路线图得当人群:
IT开辟职员:想要拓展职业边界
零基础小白:鸿蒙爱好者,渴望从0到1学习,增加一项技能。
技术提拔/进阶跳槽:发展瓶颈期,提拔职场竞争力,快速把握鸿蒙技术
2.学习视频+学习PDF文档
HarmonyOS Next 最新全套视频教程 (鸿蒙语法ArkTS、TypeScript、ArkUI教程……)
纯血版鸿蒙全套学习文档(面试、文档、全套视频等)
鸿蒙APP开辟必备
总结
【纯血版鸿蒙全套最新学习文档】
总的来说,华为鸿蒙不再兼容安卓,对步调员来说是一个挑衅,也是一个机会。只有积极应对变革,不停学习和提拔本身,才华在这个变革的时代中立于不败之地。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |