diff --git a/entry/src/main/ets/pages/testGifDontAnimatePage.ets b/entry/src/main/ets/pages/testGifDontAnimatePage.ets index 2cc5593..c673562 100644 --- a/entry/src/main/ets/pages/testGifDontAnimatePage.ets +++ b/entry/src/main/ets/pages/testGifDontAnimatePage.ets @@ -15,14 +15,15 @@ import {ImageKnifeComponent} from '@ohos/imageknife' import {ImageKnifeOption} from '@ohos/imageknife' import {RotateImageTransformation} from '@ohos/imageknife' - +import ArkWorker from '@ohos.worker' @Entry @Component struct TestGifDontAnimatePage { + private globalGifWorker:any = undefined @State imageKnifeOption1: ImageKnifeOption = { loadSrc: $r('app.media.jpgSample'), - size: { width: 300, height: 300 }, + size: { width: '300', height: '300' }, placeholderSrc: $r('app.media.icon_loading'), errorholderSrc: $r('app.media.icon_failed'), margin:{left:15,top:15,right:15,bottom:15} @@ -36,8 +37,8 @@ struct TestGifDontAnimatePage { Button('本地资源gif') .onClick(() => { this.imageKnifeOption1 = { - loadSrc: $r('app.media.gifSample'), - size: { width: 300, height: 300 }, + loadSrc: $r('app.media.testGif2'), + size: { width: '300', height: '300' }, placeholderSrc: $r('app.media.icon_loading'), errorholderSrc: $r('app.media.icon_failed'), margin: { left: 15, top: 15, right: 15, bottom: 15 } @@ -48,7 +49,7 @@ struct TestGifDontAnimatePage { .onClick(()=>{ this.imageKnifeOption1 = { loadSrc: $r('app.media.gifSample'), - size: { width: 300, height: 300 }, + size: { width: '300', height: '300' }, placeholderSrc: $r('app.media.icon_loading'), errorholderSrc: $r('app.media.icon_failed'), margin:{left:15,top:15,right:15,bottom:15}, @@ -63,7 +64,7 @@ struct TestGifDontAnimatePage { .onClick(()=>{ this.imageKnifeOption1 = { loadSrc: 'https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700', - size: { width: 300, height: 300 }, + size: { width: '300', height: '300' }, placeholderSrc: $r('app.media.icon_loading'), errorholderSrc: $r('app.media.icon_failed'), margin:{left:15,top:15,right:15,bottom:15} @@ -73,7 +74,7 @@ struct TestGifDontAnimatePage { .onClick(()=>{ this.imageKnifeOption1 = { loadSrc: 'https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700', - size: { width: 300, height: 300 }, + size: { width: '300', height: '300' }, placeholderSrc: $r('app.media.icon_loading'), errorholderSrc: $r('app.media.icon_failed'), margin:{left:15,top:15,right:15,bottom:15}, @@ -91,8 +92,16 @@ struct TestGifDontAnimatePage { } aboutToAppear() { - console.log('aboutToAppear()') + this.globalGifWorker = new ArkWorker.Worker('entry/ets/pages/workers/gifParseWorker.ts', { + type: 'classic', + name: 'ImageKnifeParseGIF' + }) + globalThis.ImageKnife.setGifWorker(this.globalGifWorker) + } + aboutToDisappear(){ + if(this.globalGifWorker){ + this.globalGifWorker.terminate(); + } } } -var ImageKnife = globalThis.ImageKnife \ No newline at end of file diff --git a/entry/src/main/ets/pages/workers/gifParseWorker.ts b/entry/src/main/ets/pages/workers/gifParseWorker.ts new file mode 100644 index 0000000..e50cb22 --- /dev/null +++ b/entry/src/main/ets/pages/workers/gifParseWorker.ts @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import arkWorker from '@ohos.worker'; +import { gifHandler } from '@ohos/imageknife/src/main/ets/components/imageknife/utils/gif/worker/GifWorker' + +arkWorker.parentPort.onmessage = gifHandler; + + + + + + diff --git a/imageknife/src/main/ets/components/imageknife/utils/gif/GIFFrame.ts b/imageknife/src/main/ets/components/imageknife/utils/gif/GIFFrame.ts new file mode 100644 index 0000000..dd753bb --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/gif/GIFFrame.ts @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export class GIFFrame { + + // 显示帧 width 宽 height 高 top上边距 left左边距 + dims: { + width: number; + height: number; + top: number; + left: number + } + + // 当前帧的像素数据指向的颜色数组 只为了生成patch,非必要 + colorTable?: [number, number, number][] + + // 当前帧到下一帧的间隔时长 + delay: number + + // 当前帧绘制要求 0保留 1在上一帧绘制此帧 2恢复画布背景 3.将画布恢复到绘制当前图像之前的先前状态 + disposalType: number + + // Uint8CampedArray颜色转换后的补片信息用于绘制 必要 + patch?: Uint8ClampedArray + + // drawPixelMap 如果像素转换为PixelMap后使用PixelMap展示, patch和drawPixelMap 2选1 + drawPixelMap? + + // 当前帧每个像素的颜色表查找索引 只为了生成patch,非必要 + pixels?: number[] + + // 表示透明度的可选颜色索引 + transparentIndex: number +} \ 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 new file mode 100644 index 0000000..d43d2a5 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/gif/GIFParseImpl.ets @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { IParseGif } from './IParseGif' +import { GIFFrame } from './GIFFrame' +import { LoadType } from './worker/GifWorker' +import { parseBufferToFrame } from './parse/GIFParse' +import image from '@ohos.multimedia.image' + +export class GIFParseImpl implements IParseGif { + parseGifs(imageinfo: ArrayBuffer, callback: (data?, err?) => void, worker?,runMainThread?:boolean) { + let resolveWorker = worker; + console.log('parseGifs resolveWorker1 is null =' + (resolveWorker == null)) + if (!resolveWorker) { + resolveWorker = globalThis.ImageKnife.getGifWorker(); + } + console.log('parseGifs resolveWorker2 is null =' + (resolveWorker == null)) + + if (!!resolveWorker && !runMainThread) { + console.log('parseGifs in worker thread!') + this.useWorkerParse(resolveWorker, imageinfo, (data, err) => { + if (err) { + callback(undefined, err) + } else { + this.createPixelMapAll(data).then((pixelmaps) => { + if (pixelmaps.length == data.length) { + for (let i = 0;i < data.length; i++) { + let frame = data[i]; + frame['drawPixelMap'] = pixelmaps[i]; + frame['patch'] = null; + } + callback(data, undefined) + } + }).catch(err => { + callback(undefined, err) + }) + } + }) + } else { + console.log('parseGifs in main thread!') + let frames = parseBufferToFrame(imageinfo) + console.log('frames length =' + frames.length) + this.createPixelMapAll(frames).then((pixelmaps) => { + if (pixelmaps.length == frames.length) { + for (let i = 0;i < frames.length; i++) { + let frame = frames[i]; + frame['drawPixelMap'] = pixelmaps[i]; + frame['patch'] = null; + } + console.log('parseGifs in main thread! callback is done!') + callback(frames, undefined) + } + }).catch(err => { + console.log('parseGifs in main thread! err =' + err) + callback(undefined, err) + }) + } + } + + private createPixelMapAll(frames): Promise { + let promises = [] + let filterCriteria = (item) => { + if (!item['drawPixelMap']) { + return true; + } + } + frames.filter(filterCriteria, frames).flatMap((frame) => { + promises.push(image.createPixelMap(frame.patch.buffer, { + 'size': { + 'height': frame.dims.height as number, + 'width': frame.dims.width as number + } + })) + }) + return Promise.all(promises) + } + + private useWorkerParse(worker: any, buffer: ArrayBuffer, callback: (data?, err?) => void) { + + worker.onerror = function (data) { + callback(undefined, data) + } + + worker.onmessageerror = function (event) { + callback(undefined, event) + } + + worker.onexit = function () { + console.log('gifWork worker.onexit!') + } + + worker.onmessage = (e) => { + var data = e.data; + switch (data.type) { + case LoadType.loadBufferByWorker: + let pages = data.data; + if (this.gifDecodeCorrect(pages)) { + let images = this.recDecodedData(pages); + callback(images, undefined) + } else { + callback(undefined, 'GIF Worker Decoder Data Is Error!') + } + break; + default: + break + } + } + + var obj = { type: LoadType.loadBufferByWorker, data: buffer } + worker.postMessage(obj, [buffer]) + + } + + private gifDecodeCorrect(frames) { + if ( + (frames.patch.length == frames.dims.length) && + (frames.patch.length == frames.delay.length) && + (frames.patch.length == frames.disposalType.length) && + (frames.patch.length == frames.patch.length) && + (frames.patch.length == frames.transparentIndex.length) + ) { + return true; + } + return false; + } + + // 子线程数据回传处理 + private recDecodedData(pages): GIFFrame[] { + let images = [] + for (let i = 0; i < pages.patch.length; i++) { + let frame = {} + frame['dims'] = pages.dims[i] + pages.dims[i] = null + frame['delay'] = pages.delay[i] + pages.delay[i] = null + frame['disposalType'] = pages.disposalType[i] + pages.disposalType[i] = null + let uint8ClampedArray = new Uint8ClampedArray(pages.patch[i]) + frame['patch'] = uint8ClampedArray + pages.patch[i] = null + frame['transparentIndex'] = pages.transparentIndex[i] + pages.transparentIndex[i] = null + images.push(frame) + } + pages = null + return images; + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/PixelMapPack.ets b/imageknife/src/main/ets/components/imageknife/utils/gif/IParseGif.ets similarity index 77% rename from imageknife/src/main/ets/components/imageknife/PixelMapPack.ets rename to imageknife/src/main/ets/components/imageknife/utils/gif/IParseGif.ets index c8b8dbc..19ff54b 100644 --- a/imageknife/src/main/ets/components/imageknife/PixelMapPack.ets +++ b/imageknife/src/main/ets/components/imageknife/utils/gif/IParseGif.ets @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -export class PixelMapPack { - pixelMap:PixelMap +export interface IParseGif{ + // gif解析 + parseGifs(imageinfo:ArrayBuffer,callback:(data?,err?)=>void,worker?) } \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/utils/gif/parse/GIFParse.ts b/imageknife/src/main/ets/components/imageknife/utils/gif/parse/GIFParse.ts new file mode 100644 index 0000000..1883e30 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/gif/parse/GIFParse.ts @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { decompressFrames, parseGIF } from './index' +import { fixLoseGCE} from '../utils/ParseHelperUtils' +import { GIFFrame } from '../GIFFrame' + +export function parseBufferToFrame(arraybuffer: ArrayBuffer): GIFFrame[] { + let gif = parseGIF(arraybuffer) + fixLoseGCE(gif) + let origins = decompressFrames(gif, true) + return origins as GIFFrame[]; + +} + + + diff --git a/imageknife/src/main/ets/components/imageknife/utils/gif/parse/deinterlace.js b/imageknife/src/main/ets/components/imageknife/utils/gif/parse/deinterlace.js new file mode 100644 index 0000000..1344785 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/gif/parse/deinterlace.js @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Deinterlace function from https://github.com/shachaf/jsgif + */ +export function deinterlace(pixels, width) { + var newPixels = new Array(pixels.length); + var rows = pixels.length / width; + + var cpRow = function cpRow(toRow, fromRow) { + var fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width); + newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels)); + }; // See appendix E. + + + var offsets = [0, 4, 2, 1]; + var steps = [8, 8, 4, 2]; + var fromRow = 0; + + for (var pass = 0; pass < 4; pass++) { + for (var toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) { + cpRow(toRow, fromRow); + fromRow++; + } + } + return newPixels; +}; diff --git a/imageknife/src/main/ets/components/imageknife/utils/gif/parse/index.js b/imageknife/src/main/ets/components/imageknife/utils/gif/parse/index.js new file mode 100644 index 0000000..a9134e3 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/gif/parse/index.js @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var _gif = _interopRequireDefault(require("js-binary-schema-parser/lib/schemas/gif")); + +var _jsBinarySchemaParser = require("js-binary-schema-parser"); + +var _uint = require("js-binary-schema-parser/lib/parsers/uint8"); + +import {deinterlace} from './deinterlace' +import {lzw} from './lzw' + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +export function parseGIF(arrayBuffer) { + var byteData = new Uint8Array(arrayBuffer); + return (0, _jsBinarySchemaParser.parse)((0, _uint.buildStream)(byteData), _gif["default"]); +}; + + + +export function generatePatch(image) { + var totalPixels = image.pixels.length; + var patchData = new Uint8ClampedArray(totalPixels * 4); + + for (var i = 0; i < totalPixels; i++) { + var pos = i * 4; + var colorIndex = image.pixels[i]; + var color = image.colorTable[colorIndex] || [0, 0, 0]; + patchData[pos] = color[2]; + patchData[pos + 1] = color[1]; + patchData[pos + 2] = color[0]; + patchData[pos + 3] = colorIndex !== image.transparentIndex ? 255 : 0; + } + + return patchData; +}; + +export function decompressFrame(frame, gct, buildImagePatch) { + if (!frame.image) { + + return; + } + + var image = frame.image; // get the number of pixels + + var totalPixels = image.descriptor.width * image.descriptor.height; // do lzw decompression + + var pixels = lzw(image.data.minCodeSize, image.data.blocks, totalPixels); // deal with interlacing if necessary + + if (image.descriptor.lct.interlaced) { + pixels = deinterlace(pixels, image.descriptor.width); + } + + var resultImage = { + pixels: pixels, + dims: { + top: frame.image.descriptor.top, + left: frame.image.descriptor.left, + width: frame.image.descriptor.width, + height: frame.image.descriptor.height + } + }; // color table + + if (image.descriptor.lct && image.descriptor.lct.exists) { + resultImage['colorTable'] = image.lct; + } else { + resultImage['colorTable'] = gct; + } // add per frame relevant gce information + + + if (frame.gce) { + resultImage['delay'] = (frame.gce.delay || 10) * 10; // convert to ms + + resultImage['disposalType'] = frame.gce.extras.disposal; // transparency + + if (frame.gce.extras.transparentColorGiven) { + resultImage['transparentIndex'] = frame.gce.transparentColorIndex; + } + } // create canvas usable imagedata if desired + + + if (buildImagePatch) { + resultImage['patch'] = generatePatch(resultImage); + resultImage['colorTable'] = null + resultImage['transparentIndex'] = null + resultImage['pixels'] = null + } + + return resultImage; +}; + + + +export function decompressFrames(parsedGif, buildImagePatches) { + return parsedGif.frames.filter(function (f) { + return f.image; + }).map(function (f) { + return decompressFrame(f, parsedGif.gct, buildImagePatches); + }); +}; + diff --git a/imageknife/src/main/ets/components/imageknife/utils/gif/parse/lzw.js b/imageknife/src/main/ets/components/imageknife/utils/gif/parse/lzw.js new file mode 100644 index 0000000..113a8d4 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/gif/parse/lzw.js @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * javascript port of java LZW decompression + * Original java author url: https://gist.github.com/devunwired/4479231 + */ +export function lzw(minCodeSize, data, pixelCount) { + var MAX_STACK_SIZE = 4096; + var nullCode = -1; + var npix = pixelCount; + var available; + var clear; + var codeMask; + var codeSize; + var endOfInformation; + var inCode; + var oldCode; + var bits; + var code; + var i; + var datum; + var dataSize; + var first; + var top; + var bi; + var pi; + var dstPixels = new Array(pixelCount); + var prefix = new Array(MAX_STACK_SIZE); + var suffix = new Array(MAX_STACK_SIZE); + var pixelStack = new Array(MAX_STACK_SIZE + 1); // Initialize GIF data stream decoder. + + dataSize = minCodeSize; + clear = 1 << dataSize; + endOfInformation = clear + 1; + available = clear + 2; + oldCode = nullCode; + codeSize = dataSize + 1; + codeMask = (1 << codeSize) - 1; + + for (code = 0; code < clear; code++) { + prefix[code] = 0; + suffix[code] = code; + } // Decode GIF pixel stream. + + + var datum, bits, count, first, top, pi, bi; + datum = bits = count = first = top = pi = bi = 0; + + for (i = 0; i < npix;) { + if (top === 0) { + if (bits < codeSize) { + // get the next byte + datum += data[bi] << bits; + bits += 8; + bi++; + continue; + } // Get the next code. + + + code = datum & codeMask; + datum >>= codeSize; + bits -= codeSize; // Interpret the code + + if (code > available || code == endOfInformation) { + break; + } + + if (code == clear) { + // Reset decoder. + codeSize = dataSize + 1; + codeMask = (1 << codeSize) - 1; + available = clear + 2; + oldCode = nullCode; + continue; + } + + if (oldCode == nullCode) { + pixelStack[top++] = suffix[code]; + oldCode = code; + first = code; + continue; + } + + inCode = code; + + if (code == available) { + pixelStack[top++] = first; + code = oldCode; + } + + while (code > clear) { + pixelStack[top++] = suffix[code]; + code = prefix[code]; + } + + first = suffix[code] & 0xff; + pixelStack[top++] = first; // add a new string to the table, but only if space is available + // if not, just continue with current table until a clear code is found + // (deferred clear code implementation as per GIF spec) + + if (available < MAX_STACK_SIZE) { + prefix[available] = oldCode; + suffix[available] = first; + available++; + + if ((available & codeMask) === 0 && available < MAX_STACK_SIZE) { + codeSize++; + codeMask += available; + } + } + + oldCode = inCode; + } // Pop a pixel off the pixel stack. + + + top--; + dstPixels[pi++] = pixelStack[top]; + i++; + } + + for (i = pi; i < npix; i++) { + dstPixels[i] = 0; // clear missing pixels + } + + return dstPixels; +}; diff --git a/imageknife/src/main/ets/components/imageknife/utils/gif/utils/ParseHelperUtils.ts b/imageknife/src/main/ets/components/imageknife/utils/gif/utils/ParseHelperUtils.ts new file mode 100644 index 0000000..7db1c2e --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/gif/utils/ParseHelperUtils.ts @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export function fixLoseGCE(gif) { + let currentGce = null; + for (const frame of gif.frames) { + currentGce = frame.gce ? frame.gce : currentGce; + // fix loosing graphic control extension for same frames + if ("image" in frame && !("gce" in frame)) { + frame.gce = currentGce; + } + } +} \ No newline at end of file diff --git a/imageknife/src/main/ets/components/imageknife/utils/gif/worker/GifWorker.ts b/imageknife/src/main/ets/components/imageknife/utils/gif/worker/GifWorker.ts new file mode 100644 index 0000000..0c0bb71 --- /dev/null +++ b/imageknife/src/main/ets/components/imageknife/utils/gif/worker/GifWorker.ts @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import arkWorker from '@ohos.worker'; +import { parseBufferToFrame } from '../parse/GIFParse' + +export enum LoadType { + loadBufferByWorker = "loadBufferByWorker" +} + +// Send or Receive Format Data Such as: {type: yourResolveType, data: yourDataJson, error?: yourErrorInfo } +export function gifHandler(e) { + let data = e.data; + switch (data.type) { + case LoadType.loadBufferByWorker: + loadBufferByWorker(data.data, data.type); + break; + default: + break + } + + function loadBufferByWorker(buffer: ArrayBuffer, recType: string) { + let images = parseBufferToFrame(buffer); + let dimss = []; + let delays = []; + let disposalTypes = []; + let patchs = []; + let transparentIndexs = []; + for (let i = 0; i < images.length; i++) { + dimss.push(images[i].dims) + delays.push(images[i].delay) + disposalTypes.push(images[i].disposalType) + patchs.push(images[i].patch.buffer) + transparentIndexs.push(images[i].transparentIndex) + } + let frame = { + dims: dimss, + // 当前帧到下一帧的间隔时长 + delay: delays, + // 当前帧绘制要求 0保留 1在上一帧绘制此帧 2恢复画布背景 3.将画布恢复到绘制当前图像之前的先前状态 + disposalType: disposalTypes, + // Uint8CampedArray颜色转换后的补片信息用于绘制 + patch: patchs, + // 表示透明度的可选颜色索引 + transparentIndex: transparentIndexs + } + let dataObj = { type: recType, data: frame } + arkWorker.parentPort.postMessage(dataObj, patchs); + } +} + + + + + + +