diff --git a/CHANGELOG.md b/CHANGELOG.md index adb55c0..d751c46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.1.1-rc.5 +- .jpg .png .gif解码功能使用taskpool实现 +- 修复了内存缓存张数设置为1时gif图片消失的问题 + + + ## 2.1.1-rc.4 - 删除pako源码依赖,使用ohpm依赖 diff --git a/entry/src/main/ets/pages/index.ets b/entry/src/main/ets/pages/index.ets index 1c1459d..a4cb9a5 100644 --- a/entry/src/main/ets/pages/index.ets +++ b/entry/src/main/ets/pages/index.ets @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import router from '@system.router'; +import router from '@ohos.router'; import { ImageKnifeComponent, ImageKnifeOption, @@ -67,7 +67,6 @@ struct IndexFunctionDemo { .onClick(() => { this.imageKnifeOption2 = { loadSrc: 'https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658', - placeholderSrc: $r('app.media.icon_loading'), errorholderSrc: $r('app.media.icon_failed'), displayProgress:true, @@ -80,7 +79,7 @@ struct IndexFunctionDemo { Button("ImageKnife测试目录页面") .onClick(() => { console.log("pages/imageknifeTestCaseIndex 页面跳转") - router.push({ uri: "pages/imageknifeTestCaseIndex" }); + router.replaceUrl({ url: "pages/imageknifeTestCaseIndex" }); }).margin({ top: 15 }) }.width('100%').height(60).backgroundColor(Color.Pink) } diff --git a/entry/src/ohosTest/ets/test/imageknife.test.ets b/entry/src/ohosTest/ets/test/imageknife.test.ets index 2186d29..368a7a6 100644 --- a/entry/src/ohosTest/ets/test/imageknife.test.ets +++ b/entry/src/ohosTest/ets/test/imageknife.test.ets @@ -14,7 +14,7 @@ */ import hilog from '@ohos.hilog'; import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium' -import {ImageKnife,ImageKnifeDrawFactory,ImageKnifeGlobal} from '@ohos/libraryimageknife' +import {ImageKnife,ImageKnifeDrawFactory,ImageKnifeGlobal} from '@ohos/imageknife' export default function ImageKnifeTest() { describe('ImageKnifeTest', ()=> { diff --git a/imageknife/oh-package.json5 b/imageknife/oh-package.json5 index c55ced7..271b901 100644 --- a/imageknife/oh-package.json5 +++ b/imageknife/oh-package.json5 @@ -14,12 +14,12 @@ "main": "index.ets", "repository": "https://gitee.com/openharmony-tpc/ImageKnife", "type": "module", - "version": "2.1.1-rc.4", + "version": "2.1.1-rc.5", "dependencies": { + "pako": "^2.1.0", "@ohos/disklrucache": "^2.0.2-rc.0", "@ohos/svg": "^2.1.1-rc.0", - "@ohos/gpu_transform": "^1.0.0", - "pako": "^2.1.0" + "@ohos/gpu_transform": "^1.0.0" }, "tags": [ "ImageCache", diff --git a/imageknife/src/main/ets/components/imageknife/ImageKnife.ets b/imageknife/src/main/ets/components/imageknife/ImageKnife.ets index 95463a5..c2976c3 100644 --- a/imageknife/src/main/ets/components/imageknife/ImageKnife.ets +++ b/imageknife/src/main/ets/components/imageknife/ImageKnife.ets @@ -330,12 +330,6 @@ export class ImageKnife { let signature = request.signature; - if (signature != undefined) { - console.log("唯一标识:" + signature.getKey()) - } - - - cacheKey = factories.generateMemoryCacheKey(loadKey,size,transformed,dontAnimateFlag,signature); // 生成磁盘缓存变换后数据key 变换后数据保存在磁盘 diff --git a/imageknife/src/main/ets/components/imageknife/ImageKnifeComponent.ets b/imageknife/src/main/ets/components/imageknife/ImageKnifeComponent.ets index 7f1a64c..e997ec7 100644 --- a/imageknife/src/main/ets/components/imageknife/ImageKnifeComponent.ets +++ b/imageknife/src/main/ets/components/imageknife/ImageKnifeComponent.ets @@ -85,6 +85,9 @@ export struct ImageKnifeComponent { private detachFromLayout:DetachFromLayout|undefined = undefined; + private detachFromLayoutGIF :DetachFromLayout|undefined = undefined; + + build() { Canvas(this.context) .width('100%') @@ -519,7 +522,11 @@ export struct ImageKnifeComponent { LogUtil.log('ImageKnifeComponent default drawMainSource end!') }) } else if (data.isGIFFrame()) { - this.drawGIFFrame(context, data, imageKnifeOption, compWidth, compHeight, setGifTimeId) + if(data.drawGIFFrame != undefined) { + data.drawGIFFrame.isShowOnComponent = true + this.detachFromLayoutGIF = data.drawGIFFrame.detachFromLayoutGIF + this.drawGIFFrame(context, data, imageKnifeOption, compWidth, compHeight, setGifTimeId) + } } } @@ -604,7 +611,9 @@ export struct ImageKnifeComponent { if(this.detachFromLayout != undefined){ this.detachFromLayout.detach(); } - + if(this.detachFromLayoutGIF != undefined){ + this.detachFromLayoutGIF.detach(); + } this.resetGifData(); } @@ -750,23 +759,7 @@ export struct ImageKnifeComponent { LogUtil.log('ImageKnifeComponent canvasDrawPixelMap index=' + index) let frame = frames[index]; let pixelmap = frame['drawPixelMap'] - let disposal = 0 - // disposal value is from preFrame - if (index >= 1) { - let preFrame = frames[index-1] - disposal = preFrame.disposalType - - if (disposal === FrameDisposalType.DISPOSE_RestoreBackground) { - let left:number = preFrame.dims.left; - let top:number = preFrame.dims.top - context.clearRect(left, top, compWidth, compHeight); - } - } else { - if (disposal === FrameDisposalType.DISPOSE_RestoreBackground) { - context.clearRect(0, 0, compWidth, compHeight) - } - } - + context.clearRect(0, 0, compWidth, compHeight) let scaleType = (typeof this.imageKnifeOption.mainScaleType == 'number') ? this.imageKnifeOption.mainScaleType : ScaleType.FIT_CENTER context.save(); let frameW = frames[0].dims.left + frames[0].dims.width diff --git a/imageknife/src/main/ets/components/imageknife/ImageKnifeData.ets b/imageknife/src/main/ets/components/imageknife/ImageKnifeData.ets index 2179d11..575b451 100644 --- a/imageknife/src/main/ets/components/imageknife/ImageKnifeData.ets +++ b/imageknife/src/main/ets/components/imageknife/ImageKnifeData.ets @@ -13,6 +13,7 @@ * limitations under the License. */ import { GIFFrame } from './utils/gif/GIFFrame' +import { DetachFromLayout } from './RequestOption' export enum ImageKnifeType { PIXELMAP = 'PixelMap', @@ -35,6 +36,26 @@ export class DrawResource { export class DrawGIFFrame { imageGIFFrames: GIFFrame[] | undefined = undefined + isShowOnComponent:boolean = false;//gif是否显示在组件上 true:显示在组件上 false:不显示在组件上 + isLruCacheRelease:boolean = false;//当前lru是否释放gif资源,true的就释放了gif资源 false就是没有释放 + + detachFromLayoutGIF :DetachFromLayout = { + detach:()=> { + this.isShowOnComponent = false + if(this.isLruCacheRelease) { + let gifFrames = this.imageGIFFrames; + if (gifFrames != undefined) { + for (let i = 0; i < gifFrames.length; i++) { + let tempFrame = gifFrames[i]; + if (tempFrame.drawPixelMap != undefined) { + tempFrame.drawPixelMap.release() + } + } + } + this.imageGIFFrames = undefined; + } + } + }; } export class ImageKnifeData { @@ -97,14 +118,21 @@ export class ImageKnifeData { } } if(this.isGIFFrame()){ - if(this.drawGIFFrame != undefined){ - let gifFrames = this.drawGIFFrame.imageGIFFrames; - if(gifFrames != undefined){ - for (let i = 0; i < gifFrames.length; i++) { - let tempFrame = gifFrames[i]; - if(tempFrame.drawPixelMap != undefined){ - tempFrame.drawPixelMap.release() + if (this.drawGIFFrame != undefined) { + this.drawGIFFrame.isLruCacheRelease = true; + + if(this.drawGIFFrame.isShowOnComponent){ + return; + }else { + let gifFrames = this.drawGIFFrame.imageGIFFrames; + if (gifFrames != undefined) { + for (let i = 0; i < gifFrames.length; i++) { + let tempFrame = gifFrames[i]; + if (tempFrame.drawPixelMap != undefined) { + tempFrame.drawPixelMap.release() + } } + this.drawGIFFrame.imageGIFFrames = undefined } this.drawGIFFrame.imageGIFFrames = undefined } diff --git a/imageknife/src/main/ets/components/imageknife/utils/ParseImageUtil.ets b/imageknife/src/main/ets/components/imageknife/utils/ParseImageUtil.ets index 9e43f20..a4ae4a5 100644 --- a/imageknife/src/main/ets/components/imageknife/utils/ParseImageUtil.ets +++ b/imageknife/src/main/ets/components/imageknife/utils/ParseImageUtil.ets @@ -13,44 +13,54 @@ * limitations under the License. */ -import {IParseImage} from '../interface/IParseImage' +import { IParseImage } from '../interface/IParseImage' import image from '@ohos.multimedia.image'; import { BusinessError } from '@ohos.base' +import taskpool from '@ohos.taskpool'; +import { LogUtil } from './LogUtil'; + export class ParseImageUtil implements IParseImage { - parseImage(imageinfo: ArrayBuffer, onCompleteFunction:(value:PixelMap)=>void | PromiseLike, onErrorFunction:(reason?:BusinessError|string)=>void) { + parseImage(imageinfo: ArrayBuffer, onCompleteFunction: (value: PixelMap) => void | PromiseLike, onErrorFunction: (reason?: BusinessError | string) => void) { this.parseImageThumbnail(1, imageinfo, onCompleteFunction, onErrorFunction) } // scale(0,1) - parseImageThumbnail(scale: number, imageinfo: ArrayBuffer, onCompleteFunction:(value:PixelMap)=>void | PromiseLike, onErrorFunction:(reason?:BusinessError|string)=>void) { - let imageSource:image.ImageSource = image.createImageSource(imageinfo); // 步骤一:文件转为pixelMap 然后变换 给Image组件 - imageSource.getImageInfo((err, value) => { - if (err) { - onErrorFunction(err); - return; - } - let hValue = Math.round(value.size.height * scale); - let wValue = Math.round(value.size.width * scale); - let defaultSize:image.Size = { - height: hValue, - width: wValue - }; - - let opts:image.DecodingOptions = { - editable: true, - desiredSize: defaultSize - }; - - - imageSource.createPixelMap(opts, (err, pixelmap) => { - if (err) { - onErrorFunction(err); - } else { - onCompleteFunction(pixelmap); - } - imageSource.release() - }) - - }) + parseImageThumbnail(scale: number, imageinfo: ArrayBuffer, onCompleteFunction: (value: PixelMap) => void | PromiseLike, onErrorFunction: (reason?: BusinessError | string) => void) { + taskPoolExecutePixelMap(imageinfo,scale,onCompleteFunction,onErrorFunction); } +} + + +// let TAG:string = "ParseImageUtil_TASK" + +@Concurrent +async function taskParseImage(arrayBuffer: ArrayBuffer,scale: number): Promise { + let imageSource: image.ImageSource = image.createImageSource(arrayBuffer); // 步骤一:文件转为pixelMap 然后变换 给Image组件 + let value = await imageSource.getImageInfo(); + let hValue = Math.round(value.size.height * scale); + let wValue = Math.round(value.size.width * scale); + let defaultSize: image.Size = { + height: hValue, + width: wValue + }; + let opts: image.DecodingOptions = { + editable: true, + desiredSize: defaultSize + }; + let pixelMap = await imageSource.createPixelMap(opts) + LogUtil.log( "ceshi321 : Succeeded in creating pixelmap taskpool " + pixelMap.getPixelBytesNumber()) + imageSource.release() + return pixelMap; +} + +function taskPoolExecutePixelMap(arrayBuffer: ArrayBuffer, scale: number, onCompleteFunction: (value: PixelMap) => void | PromiseLike, onErrorFunction: (reason?: BusinessError | string) => void) { + LogUtil.log("ceshi321 : arrayBuffer长度" + arrayBuffer.byteLength) + let task = new taskpool.Task(taskParseImage, arrayBuffer,scale) + taskpool.execute(task).then((pixelmap: image.PixelMap) => { + LogUtil.log('ceshi321 : Succeeded in creating pixelmap Ui .' + pixelmap.getPixelBytesNumber()) + onCompleteFunction(pixelmap); + }).catch((err: string) => { + LogUtil.log("ceshi321 : test occur error: " + err) + onErrorFunction(err); + }); } \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/utils/gif/GIFParseImpl.ets b/imageknife/src/main/ets/components/imageknife/utils/gif/GIFParseImpl.ets index 6f2e5d8..6846e6f 100644 --- a/imageknife/src/main/ets/components/imageknife/utils/gif/GIFParseImpl.ets +++ b/imageknife/src/main/ets/components/imageknife/utils/gif/GIFParseImpl.ets @@ -12,68 +12,70 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { IParseGif } from './IParseGif' +import { IParseGif } from './IParseGif' import { Dims, GIFFrame } from './GIFFrame' import image from '@ohos.multimedia.image' import { BusinessError } from '@ohos.base' import worker, { ErrorEvent, MessageEvents } from '@ohos.worker'; +import taskpool from '@ohos.taskpool' +import { LogUtil } from '../LogUtil' -export interface senderData{ - type:string, - data:ArrayBuffer; +export interface senderData { + type: string, + data: ArrayBuffer; } -export interface gifBackData{ - dims:Dims[], - delay:number[], - disposalType:number[], - patch:Uint8ClampedArray[], - transparentIndex:number[] +export interface gifBackData { + dims: Dims[], + delay: number[], + disposalType: number[], + patch: Uint8ClampedArray[], + transparentIndex: number[] } + export class GIFParseImpl implements IParseGif { - // - parseGifs(imageinfo: ArrayBuffer, callback: (data?:GIFFrame[], err?:BusinessError|string) => void, worker?:worker.ThreadWorker,runMainThread?:boolean) { - // 硬解码流程 - let imageSource = image.createImageSource(imageinfo); - let decodeOpts: image.DecodingOptions = { - sampleSize: 1, - editable: true, - rotate: 0 - } - let data:GIFFrame[] = []; - imageSource.createPixelMapList(decodeOpts).then((pixelList: Array) => { - //sdk的api接口发生变更:从.getDelayTime() 变为.getDelayTimeList() - imageSource.getDelayTimeList().then(delayTimes => { - if (pixelList.length > 0) { - let pixelmap1 = pixelList[0]; - pixelmap1.getImageInfo().then(imageInfo => { - for (let i = 0; i < pixelList.length; i++) { - let frame = new GIFFrame(); - frame.drawPixelMap = pixelList[i]; - frame.dims = { width: imageInfo.size.width, height: imageInfo.size.height, top: 0, left: 0 } - if (i < delayTimes.length) { - frame.delay = delayTimes[i]; - } else { - frame.delay = delayTimes[delayTimes.length - 1] - } - data.push(frame) - } - callback(data,undefined) - imageSource.release(); - }).catch((err: string) => { - imageSource.release(); - callback(undefined,err) - }) - } - }).catch((err: string) => { - imageSource.release(); - callback(undefined,err) - }) - }).catch((err: string) => { - imageSource.release(); - callback(undefined,err) - }) - + parseGifs(imageinfo: ArrayBuffer, callback: (data?: GIFFrame[], err?: BusinessError | string) => void) { + taskPoolExecutePixelMapList(imageinfo,callback); } +} +@Concurrent +async function taskParseGif(arrayBuffer: ArrayBuffer): Promise { + let imageSource = image.createImageSource(arrayBuffer); + let data: GIFFrame[] = []; + let decodeOpts: image.DecodingOptions = { + sampleSize: 1, + editable: true, + rotate: 0 + } + let pixelList = await imageSource.createPixelMapList(decodeOpts); + if (pixelList.length > 0) { + let pixelmap1 = pixelList[0]; + let imageInfo = await pixelmap1.getImageInfo(); + let delayTimes = await imageSource.getDelayTimeList(); + for (let i = 0; i < pixelList.length; i++) { + let frame = new GIFFrame(); + frame.drawPixelMap = pixelList[i]; + frame.dims = { width: imageInfo.size.width, height: imageInfo.size.height, top: 0, left: 0 } + if (i < delayTimes.length) { + frame.delay = delayTimes[i]; + } else { + frame.delay = delayTimes[delayTimes.length - 1] + } + data.push(frame) + } + } + return data; +} + +function taskPoolExecutePixelMapList(arrayBuffer: ArrayBuffer, callback: (data?: GIFFrame[], err?: BusinessError | string) => void) { + LogUtil.log("ceshi321 : arrayBuffer长度" + arrayBuffer.byteLength) + let task = new taskpool.Task(taskParseGif, arrayBuffer) + taskpool.execute(task).then((imageFrames: GIFFrame[]) => { + // LogUtil.log('ceshi321 : Succeeded in creating pixelmap Ui .' + imageFrames.getPixelBytesNumber()) + callback(imageFrames,undefined) + }).catch((err: string) => { + LogUtil.log("ceshi321 : test occur error: " + err) + callback(undefined,err); + }); } \ No newline at end of file diff --git a/oh-package.json5 b/oh-package.json5 index 5360e8c..966e3d8 100644 --- a/oh-package.json5 +++ b/oh-package.json5 @@ -6,6 +6,6 @@ "name": "imageknife", "description": "example description", "repository": {}, - "version": "2.1.1-rc.4", + "version": "2.1.1-rc.5", "dependencies": {} }