From 55acf4f97ca446603235b3a282c66a05df60c2a4 Mon Sep 17 00:00:00 2001 From: Yegor Pelykh Date: Fri, 12 Apr 2024 23:17:07 +0300 Subject: [PATCH] fix: Improve decoding performance of animated GIF --- src/formats/gif-decoder.ts | 40 +++++++++++++++++++++----------- src/formats/gif/gif-color-map.ts | 17 +++++++++----- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/formats/gif-decoder.ts b/src/formats/gif-decoder.ts index cf3e2a2..22407b8 100644 --- a/src/formats/gif-decoder.ts +++ b/src/formats/gif-decoder.ts @@ -723,19 +723,33 @@ export class GifDecoder implements Decoder { if (frame.disposal === 2) { nextImage.clear(colorMap.getColor(this._info.backgroundColor!.r)); } else if (frame.disposal !== 3) { - const nextBytes = nextImage.toUint8Array(); - const lastBytes = lastImage.toUint8Array(); - const lp = lastImage.palette!; - for (let i = 0, l = nextBytes.length; i < l; ++i) { - const lc = lastBytes[i]; - const nc = colorMap.findColor( - lp.getRed(lc), - lp.getGreen(lc), - lp.getBlue(lc), - lp.getAlpha(lc) - ); - if (nc !== -1) { - nextBytes[i] = nc; + if ( + frame.x !== 0 || + frame.y !== 0 || + frame.width !== lastImage.width || + frame.height !== lastImage.height + ) { + if (frame.colorMap !== undefined) { + const lp = lastImage.palette!; + const remapColors = new Map(); + for (let ci = 0; ci < colorMap.numColors; ++ci) { + const nc = colorMap.findColor( + lp.getRed(ci), + lp.getGreen(ci), + lp.getBlue(ci), + lp.getAlpha(ci) + ); + remapColors.set(ci, nc); + } + const nextBytes = nextImage.toUint8Array(); + const lastBytes = lastImage.toUint8Array(); + for (let i = 0, l = nextBytes.length; i < l; ++i) { + const lc = lastBytes[i]; + const nc = remapColors.get(lc); + if (nc !== undefined) { + nextBytes[i] = nc; + } + } } } } diff --git a/src/formats/gif/gif-color-map.ts b/src/formats/gif/gif-color-map.ts index 5393913..da2082b 100644 --- a/src/formats/gif/gif-color-map.ts +++ b/src/formats/gif/gif-color-map.ts @@ -62,18 +62,23 @@ export class GifColorMap { this._palette.setRgb(index, r, g, b); } - public findColor(r: number, g: number, b: number, a: number): number { + public findColor( + r: number, + g: number, + b: number, + a: number + ): number | undefined { for (let i = 0; i < this._numColors; ++i) { if ( - this._palette.getRed(i) == r && - this._palette.getGreen(i) == g && - this._palette.getBlue(i) == b && - this._palette.getAlpha(i) == a + this._palette.getRed(i) === r && + this._palette.getGreen(i) === g && + this._palette.getBlue(i) === b && + this._palette.getAlpha(i) === a ) { return i; } } - return -1; + return undefined; } public getRed(color: number): number {