更新说明

1、.jpg .png .gif解码功能使用taskpool实现
2、 修复了内存缓存张数设置为1时gif图片消失的问题

Signed-off-by: 明月清风 <qiufeihu1@h-partners.com>
This commit is contained in:
明月清风 2023-11-30 17:39:20 +08:00
parent db7f176084
commit 2006641248
10 changed files with 157 additions and 125 deletions

View File

@ -1,3 +1,9 @@
## 2.1.1-rc.5
- .jpg .png .gif解码功能使用taskpool实现
- 修复了内存缓存张数设置为1时gif图片消失的问题
## 2.1.1-rc.4
- 删除pako源码依赖,使用ohpm依赖

View File

@ -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)
}

View File

@ -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', ()=> {

View File

@ -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",

View File

@ -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 变换后数据保存在磁盘

View File

@ -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

View File

@ -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
}

View File

@ -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<PixelMap> {
parseImage(imageinfo: ArrayBuffer, onCompleteFunction:(value:PixelMap)=>void | PromiseLike<PixelMap>, onErrorFunction:(reason?:BusinessError|string)=>void) {
parseImage(imageinfo: ArrayBuffer, onCompleteFunction: (value: PixelMap) => void | PromiseLike<PixelMap>, onErrorFunction: (reason?: BusinessError | string) => void) {
this.parseImageThumbnail(1, imageinfo, onCompleteFunction, onErrorFunction)
}
// scale(0,1)
parseImageThumbnail(scale: number, imageinfo: ArrayBuffer, onCompleteFunction:(value:PixelMap)=>void | PromiseLike<PixelMap>, 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<PixelMap>, onErrorFunction: (reason?: BusinessError | string) => void) {
taskPoolExecutePixelMap(imageinfo,scale,onCompleteFunction,onErrorFunction);
}
}
// let TAG:string = "ParseImageUtil_TASK"
@Concurrent
async function taskParseImage(arrayBuffer: ArrayBuffer,scale: number): Promise<PixelMap> {
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<PixelMap>, 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);
});
}

View File

@ -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<PixelMap>) => {
//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<GIFFrame[]> {
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);
});
}

View File

@ -6,6 +6,6 @@
"name": "imageknife",
"description": "example description",
"repository": {},
"version": "2.1.1-rc.4",
"version": "2.1.1-rc.5",
"dependencies": {}
}