From 36ba0f9617c43be285a1fd5c1b023a06f5fc22a1 Mon Sep 17 00:00:00 2001 From: zhanghanyong Date: Wed, 17 Apr 2024 16:14:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=8A=A0=E8=BD=BD=E7=9A=84?= =?UTF-8?q?=E7=BD=91=E7=BB=9Cgif=E5=9B=BE=E8=AE=BE=E7=BD=AE=E5=9C=86?= =?UTF-8?q?=E8=A7=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhanghanyong --- CHANGELOG.md | 1 + .../testImageKnifeOptionChangedPage5.ets | 59 +++++++++++++++++++ .../imageknife/ImageKnifeComponent.ets | 50 ++++++++++++++++ .../imageknife/ImageKnifeDrawFactory.ets | 21 ++++++- 4 files changed, 128 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 262ece6..89b03f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - 修改ImageKnife跳过网络,从内存中获取图片 cacheType参数未使用bug - 新增WEBP图片解析能力。 - 新增gif图片支持暂停播放功能 +- drawLifeCycle支持gif图 ## 2.1.2-rc.12 - 新增gif播放次数功能 diff --git a/entry/src/main/ets/pages/testImageKnifeOptionChangedPage5.ets b/entry/src/main/ets/pages/testImageKnifeOptionChangedPage5.ets index 47c1119..4b82c6d 100644 --- a/entry/src/main/ets/pages/testImageKnifeOptionChangedPage5.ets +++ b/entry/src/main/ets/pages/testImageKnifeOptionChangedPage5.ets @@ -27,6 +27,9 @@ import { ImageKnifeDrawFactory } from '@ohos/libraryimageknife' import worker from '@ohos.worker'; + +let gifUrl: string = 'https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658'; + @Entry @Component struct TestImageKnifeOptionChangedPage5 { @@ -83,6 +86,62 @@ struct TestImageKnifeOptionChangedPage5 { }; }).margin({ left: 5 }).backgroundColor(Color.Blue) }.margin({ top: 15 }) + Flex({ direction: FlexDirection.Row }) { + Button("本地gif") + .onClick(() => { + this.imageKnifeOption1 = { + loadSrc: $r('app.media.gifSample'), + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + }).margin({ left: 5 }).backgroundColor(Color.Blue) + Button("网络gif") + .onClick(() => { + this.imageKnifeOption1 = { + loadSrc: gifUrl, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + }; + }).margin({ left: 5 }).backgroundColor(Color.Blue) + Button("网络gif - 圆角小") + .onClick(() => { + this.imageKnifeOption1 = { + loadSrc: gifUrl, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + drawLifeCycle:ImageKnifeDrawFactory.createRoundLifeCycle(3,"#ff0000", 30) + }; + }).margin({ left: 5 }).backgroundColor(Color.Blue) + Button("本地gif - 圆角大") + .onClick(() => { + this.imageKnifeOption1 = { + loadSrc: $r('app.media.gifSample'), + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + drawLifeCycle:ImageKnifeDrawFactory.createRoundLifeCycle(5,"#ffff00", 300) + }; + }).margin({ left: 5 }).backgroundColor(Color.Blue) + }.margin({ top: 30 }) + Flex({ direction: FlexDirection.Row }) { + Button("网络gif-椭圆长方形资源") + .onClick(() => { + this.imageKnifeOption1 = { + loadSrc: gifUrl, + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + drawLifeCycle:ImageKnifeDrawFactory.createOvalLifeCycle(8,"#88ee00") + }; + }).margin({ left: 5 }).backgroundColor(Color.Blue) + Button("本地gif-椭圆正方形资源") + .onClick(() => { + this.imageKnifeOption1 = { + loadSrc: $r('app.media.gifSample'), + placeholderSrc: $r('app.media.icon_loading'), + errorholderSrc: $r('app.media.icon_failed'), + drawLifeCycle:ImageKnifeDrawFactory.createOvalLifeCycle(5,"#ff00ff") + }; + }).margin({ left: 5 }).backgroundColor(Color.Blue) + }.margin({ top: 30 }) Text("下面为展示图片区域").margin({ top: 5 }) Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { diff --git a/library/src/main/ets/components/imageknife/ImageKnifeComponent.ets b/library/src/main/ets/components/imageknife/ImageKnifeComponent.ets index e8ea770..3fe841a 100644 --- a/library/src/main/ets/components/imageknife/ImageKnifeComponent.ets +++ b/library/src/main/ets/components/imageknife/ImageKnifeComponent.ets @@ -27,6 +27,7 @@ import { ObjectKey } from './ObjectKey' import componentUtils from '@ohos.arkui.componentUtils' import inspector from '@ohos.arkui.inspector' import util from '@ohos.util' +import { ImageKnifeDrawFactory } from './ImageKnifeDrawFactory' interface KeyCanvas { keyId:string @@ -415,6 +416,7 @@ export struct ImageKnifeComponent { } displayMainSource = (data: ImageKnifeData|number|undefined)=> { + ImageKnifeDrawFactory.type = undefined; if(data == undefined || typeof data == 'number'){ return } @@ -899,10 +901,58 @@ export struct ImageKnifeComponent { ScaleTypeHelper.drawImageWithScaleType(context, scaleType, pixelmap, px2vp(frameW), px2vp(frameH), compWidth, compHeight, px2vp(frame.dims.left), px2vp(frame.dims.top)) // tips:worker如果不是在展示页面中创建,使用子线程回来的数据创建的图片,会导致canvas绘制不出来 context.restore(); + if (ImageKnifeDrawFactory.type === undefined) { + return; + } + // 通过 destination-in 裁剪出圆角 + if (ImageKnifeDrawFactory?.type === DrawType.Round || ImageKnifeDrawFactory?.type === DrawType.Oval) { + context.save(); + context.globalCompositeOperation = 'destination-in'; + if (ImageKnifeDrawFactory.type === DrawType.Round) { + ImageKnifeDrawFactory.setRect(context, scaleType, pixelmap, px2vp(frameW), px2vp(frameH), compWidth, + compHeight, 0, 0, ImageKnifeDrawFactory.borderWidth, ImageKnifeDrawFactory.connerRadius); + } else { + context.beginPath(); + ImageKnifeDrawFactory.setOval(context, scaleType, pixelmap, px2vp(frameW), px2vp(frameH), compWidth, + compHeight, 0, 0, ImageKnifeDrawFactory.borderWidth); + context.closePath(); + } + context.fill(); + context.restore(); + if (ImageKnifeDrawFactory.borderWidth > 0) { + // 为圆角添加边框 + context.save(); + context.strokeStyle = ImageKnifeDrawFactory.colorString; + context.lineWidth = ImageKnifeDrawFactory.borderWidth; + context.globalCompositeOperation = 'source-over'; + if (ImageKnifeDrawFactory.type === DrawType.Round) { + ImageKnifeDrawFactory.setRect(context, scaleType, pixelmap, px2vp(frameW), px2vp(frameH), compWidth, + compHeight, 0, 0, ImageKnifeDrawFactory.borderWidth, ImageKnifeDrawFactory.connerRadius); + } else { + context.beginPath(); + ImageKnifeDrawFactory.setOval(context, scaleType, pixelmap, px2vp(frameW), px2vp(frameH), compWidth, + compHeight, 0, 0, ImageKnifeDrawFactory.borderWidth); + context.closePath(); + } + context.stroke(); + context.restore(); + } + context.restore(); + } LogUtil.log('ImageKnifeComponent canvasDrawPixelMap end!') } } +export enum DrawType{ + + Normal = 0, + + Oval = 1, + + Round = 2 + +} + export enum FrameDisposalType { // 0 - No disposal specified. The decoder is not required to take any action. // 不使用处置方法 diff --git a/library/src/main/ets/components/imageknife/ImageKnifeDrawFactory.ets b/library/src/main/ets/components/imageknife/ImageKnifeDrawFactory.ets index f67bfad..5080f1f 100644 --- a/library/src/main/ets/components/imageknife/ImageKnifeDrawFactory.ets +++ b/library/src/main/ets/components/imageknife/ImageKnifeDrawFactory.ets @@ -16,9 +16,13 @@ import { ImageKnifeOption } from '../imageknife/ImageKnifeOption' import { ImageKnifeData } from '../imageknife/ImageKnifeData' import { GIFFrame } from '../imageknife/utils/gif/GIFFrame' import { IDrawLifeCycle } from '../imageknife/interface/IDrawLifeCycle' -import { ScaleTypeHelper,ScaleType } from '../imageknife/ImageKnifeComponent' +import { ScaleTypeHelper,ScaleType, DrawType } from '../imageknife/ImageKnifeComponent' export class ImageKnifeDrawFactory{ + public static borderWidth: number; + public static type: DrawType | undefined = undefined; + public static colorString: string; + public static connerRadius: number; /** * 绘制PixelMap内容情况下,主图的椭圆裁剪,可添加边框 @@ -81,6 +85,11 @@ export class ImageKnifeDrawFactory{ }) return true; } + if (data.isGIFFrame()) { + ImageKnifeDrawFactory.type = DrawType.Oval; + ImageKnifeDrawFactory.borderWidth = borderWidth; + ImageKnifeDrawFactory.colorString = colorString; + } return false; }, // 展示重试图层 @@ -108,7 +117,7 @@ export class ImageKnifeDrawFactory{ * @param imageOffsetY * @param borderWidth */ - private static setOval(context: CanvasRenderingContext2D, scaleType: ScaleType, source: PixelMap | undefined, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX:number,imageOffsetY:number + public static setOval(context: CanvasRenderingContext2D, scaleType: ScaleType, source: PixelMap | undefined, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX:number,imageOffsetY:number ,borderWidth:number) { let scaleW = compWidth / imageWidth let scaleH = compHeight / imageHeight @@ -240,6 +249,12 @@ export class ImageKnifeDrawFactory{ }) return true; } + if (data.isGIFFrame()) { + ImageKnifeDrawFactory.type = DrawType.Round; + ImageKnifeDrawFactory.borderWidth = borderWidth; + ImageKnifeDrawFactory.colorString = colorString; + ImageKnifeDrawFactory.connerRadius = connerRadius; + } return false; }, // 展示重试图层 @@ -268,7 +283,7 @@ export class ImageKnifeDrawFactory{ * @param borderWidth * @param cornerRadius */ - private static setRect(context: CanvasRenderingContext2D, scaleType: ScaleType, source: PixelMap | undefined, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX:number,imageOffsetY:number + public static setRect(context: CanvasRenderingContext2D, scaleType: ScaleType, source: PixelMap | undefined, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX:number,imageOffsetY:number ,borderWidth:number,cornerRadius:number) { let scaleW = compWidth / imageWidth let scaleH = compHeight / imageHeight