Skip to content

Commit

Permalink
Fix when one color e.g. '#ff0000' only have 1 or 2 or 3 pixel in one …
Browse files Browse the repository at this point in the history
…frame, the generated gif pixel will be '#9f0000'; fix some frame not transparent but black; reduce gif size 10x
  • Loading branch information
flyskywhy committed Apr 7, 2023
1 parent 0584b4d commit 32f7b9c
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 63 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ getRuneScapeText(string, [options], [wordWrapOptions]);
| font | `string` | No | `runescape_uf`| font name |
| fps | `number` | No | `20` | Frames per second to render animations at, prefer integer values less than or equal to 60 |
| cycleDuration | `number` | No | `3000` | Duration in milliseconds of one cycle before the animation loops |
| quality | `number` | No | `10` | Quality to render animations at, more information [here](https://github.com/twolfson/gif-encoder#setqualityquality) |
| imageSmoothingEnabled | `boolean` | No | `true` | Determines whether to linear filter the text image |
| 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 |
| 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` |
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@
"@flyskywhy/react-native-gcanvas": "^5.1.7"
},
"dependencies": {
"gif-encoder": "^0.7.2",
"react-native-gifencoder": "^1.0.1",
"gifenc": "1.0.3",
"tinycolor2": "^1.4.1",
"word-wrap": "^1.2.3"
},
Expand Down
88 changes: 29 additions & 59 deletions src/classes/Encoder.js
Original file line number Diff line number Diff line change
@@ -1,79 +1,49 @@
const {GIFEncoder} = require('react-native-gifencoder');
import {GIFEncoder, quantize, applyPalette} from 'gifenc';
const {Buffer} = require('buffer');

// ref to https://github.com/flyskywhy/PixelShapeRN/blob/v1.1.27/src/workers/generateGif.worker.js#L22
const isTransparencyPresent = (imageDataArr, transparentColor) => {
let i = 0,
transpUsed = -1;
const len = imageDataArr.length;

for (; i < len; ) {
transpUsed *=
imageDataArr[i++] -
transparentColor.r +
imageDataArr[i++] -
transparentColor.g +
imageDataArr[i++] -
transparentColor.b;

i++;

if (!transpUsed) {
break;
}
transpUsed = -1;
}
return !transpUsed;
};

class Encoder {
constructor(config) {
this.config = config;
}

encodeGif(imageDatas, width, height) {
const gif = new GIFEncoder();
const transparentColor = 0x000000;
const transpRGB = {r: 0, g: 0, b: 0};
// Create an encoding stream
const gif = GIFEncoder();

const delay = this.config.delayPerFrame;

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

let frames = [];
imageDatas.map((imageData, index) => {
const useTransparency = isTransparencyPresent(imageData.data, transpRGB);
if (useTransparency) {
gif.setTransparent(transparentColor);
} else {
gif.setTransparent(null);
}
// Quantize your colors to a 256-color RGB palette palette
const palette = quantize(data, 256);

if (index === 0) {
gif.start();
} else {
gif.cont();
gif.setProperties(true, false); // started, firstFrame
}
// Get an indexed bitmap by reducing each pixel to the nearest color palette
const index = applyPalette(data, palette);

gif.addFrame(imageData.data, true);
// Write a single frame
gif.writeFrame(index, width, height, {
palette,
delay,
transparent: true,
// dispose: 2,
});

// Wait a tick so that we don't lock up browser
// await new Promise(resolve => setTimeout(resolve, 0));
}

if (imageDatas.length === index + 1) {
gif.finish();
}
// Write end-of-stream character
gif.finish();

frames = frames.concat(gif.stream().bin);
});
// Get the Uint8Array output of your binary GIF file
const output = gif.bytes();

if (this.config.returnBufferType === 'Buffer') {
return Buffer.from(frames);
return Buffer.from(output);
} else {
return frames;
return Array.from(output);
}
}

Expand Down
1 change: 0 additions & 1 deletion src/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"font": "runescape_uf",
"fps": 20,
"cycleDuration": 3000,
"quality": 10,
"imageSmoothingEnabled": true,
"imageGradientEnabled": true,
"gradientThreshold": 100,
Expand Down

0 comments on commit 32f7b9c

Please sign in to comment.