Skip to content

Commit 32f7b9c

Browse files
committed
Fix when one color e.g. '#ff0000' only have 1 or 2 or 3 pixel in one frame, the generated gif pixel will be '#9f0000'; fix some frame not transparent but black; reduce gif size 10x
1 parent 0584b4d commit 32f7b9c

File tree

4 files changed

+30
-63
lines changed

4 files changed

+30
-63
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,6 @@ getRuneScapeText(string, [options], [wordWrapOptions]);
159159
| font | `string` | No | `runescape_uf`| font name |
160160
| fps | `number` | No | `20` | Frames per second to render animations at, prefer integer values less than or equal to 60 |
161161
| cycleDuration | `number` | No | `3000` | Duration in milliseconds of one cycle before the animation loops |
162-
| quality | `number` | No | `10` | Quality to render animations at, more information [here](https://github.com/twolfson/gif-encoder#setqualityquality) |
163162
| imageSmoothingEnabled | `boolean` | No | `true` | Determines whether to linear filter the text image |
164163
| imageGradientEnabled | `boolean` | No | `true` | Determines whether to let the color in text image be gradient, if false, it's better also set `imageSmoothingEnabled` be false |
165164
| gradientThreshold | `number` | No | `100` | When `imageGradientEnabled` is false, if pixel's `a` > `gradientThreshold`, `a` will be modified to 255, otherwise `rgba` will be modified to `00000000` |

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,7 @@
7474
"@flyskywhy/react-native-gcanvas": "^5.1.7"
7575
},
7676
"dependencies": {
77-
"gif-encoder": "^0.7.2",
78-
"react-native-gifencoder": "^1.0.1",
77+
"gifenc": "1.0.3",
7978
"tinycolor2": "^1.4.1",
8079
"word-wrap": "^1.2.3"
8180
},

src/classes/Encoder.js

Lines changed: 29 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,49 @@
1-
const {GIFEncoder} = require('react-native-gifencoder');
1+
import {GIFEncoder, quantize, applyPalette} from 'gifenc';
22
const {Buffer} = require('buffer');
33

4-
// ref to https://github.com/flyskywhy/PixelShapeRN/blob/v1.1.27/src/workers/generateGif.worker.js#L22
5-
const isTransparencyPresent = (imageDataArr, transparentColor) => {
6-
let i = 0,
7-
transpUsed = -1;
8-
const len = imageDataArr.length;
9-
10-
for (; i < len; ) {
11-
transpUsed *=
12-
imageDataArr[i++] -
13-
transparentColor.r +
14-
imageDataArr[i++] -
15-
transparentColor.g +
16-
imageDataArr[i++] -
17-
transparentColor.b;
18-
19-
i++;
20-
21-
if (!transpUsed) {
22-
break;
23-
}
24-
transpUsed = -1;
25-
}
26-
return !transpUsed;
27-
};
28-
294
class Encoder {
305
constructor(config) {
316
this.config = config;
327
}
338

349
encodeGif(imageDatas, width, height) {
35-
const gif = new GIFEncoder();
36-
const transparentColor = 0x000000;
37-
const transpRGB = {r: 0, g: 0, b: 0};
10+
// Create an encoding stream
11+
const gif = GIFEncoder();
12+
13+
const delay = this.config.delayPerFrame;
3814

39-
gif.setRepeat(0);
40-
// we need to set disposal code of 2 for each frame
41-
// to be sure that the current frame will override the previous and won't overlap
42-
gif.setDispose(2);
43-
gif.setQuality(this.config.quality);
44-
gif.setDelay(this.config.delayPerFrame);
45-
gif.setSize(width, height);
46-
gif.setComment('');
15+
const framesLength = imageDatas.length;
16+
for (let i = 0; i < framesLength; i++) {
17+
const data = imageDatas[i].data;
4718

48-
let frames = [];
49-
imageDatas.map((imageData, index) => {
50-
const useTransparency = isTransparencyPresent(imageData.data, transpRGB);
51-
if (useTransparency) {
52-
gif.setTransparent(transparentColor);
53-
} else {
54-
gif.setTransparent(null);
55-
}
19+
// Quantize your colors to a 256-color RGB palette palette
20+
const palette = quantize(data, 256);
5621

57-
if (index === 0) {
58-
gif.start();
59-
} else {
60-
gif.cont();
61-
gif.setProperties(true, false); // started, firstFrame
62-
}
22+
// Get an indexed bitmap by reducing each pixel to the nearest color palette
23+
const index = applyPalette(data, palette);
6324

64-
gif.addFrame(imageData.data, true);
25+
// Write a single frame
26+
gif.writeFrame(index, width, height, {
27+
palette,
28+
delay,
29+
transparent: true,
30+
// dispose: 2,
31+
});
32+
33+
// Wait a tick so that we don't lock up browser
34+
// await new Promise(resolve => setTimeout(resolve, 0));
35+
}
6536

66-
if (imageDatas.length === index + 1) {
67-
gif.finish();
68-
}
37+
// Write end-of-stream character
38+
gif.finish();
6939

70-
frames = frames.concat(gif.stream().bin);
71-
});
40+
// Get the Uint8Array output of your binary GIF file
41+
const output = gif.bytes();
7242

7343
if (this.config.returnBufferType === 'Buffer') {
74-
return Buffer.from(frames);
44+
return Buffer.from(output);
7545
} else {
76-
return frames;
46+
return Array.from(output);
7747
}
7848
}
7949

src/config.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
"font": "runescape_uf",
1414
"fps": 20,
1515
"cycleDuration": 3000,
16-
"quality": 10,
1716
"imageSmoothingEnabled": true,
1817
"imageGradientEnabled": true,
1918
"gradientThreshold": 100,

0 commit comments

Comments
 (0)