Skip to content

Commit

Permalink
fix: Improve decoding performance of animated GIF
Browse files Browse the repository at this point in the history
  • Loading branch information
yegor-pelykh committed Apr 12, 2024
1 parent 28ed208 commit 55acf4f
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 19 deletions.
40 changes: 27 additions & 13 deletions src/formats/gif-decoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<number, number | undefined>();
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;
}
}
}
}
}
Expand Down
17 changes: 11 additions & 6 deletions src/formats/gif/gif-color-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 55acf4f

Please sign in to comment.