🚀 use gifsicle binaries and node gif encoder
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
import { execFileSync } from "child_process";
|
||||||
import { createCanvas } from "canvas";
|
import { createCanvas } from "canvas";
|
||||||
import { Grid, copyGrid, Color } from "@snk/types/grid";
|
import { Grid, copyGrid, Color } from "@snk/types/grid";
|
||||||
import { Snake } from "@snk/types/snake";
|
import { Snake } from "@snk/types/snake";
|
||||||
@@ -10,7 +11,9 @@ import {
|
|||||||
} from "@snk/draw/drawWorld";
|
} from "@snk/draw/drawWorld";
|
||||||
import { step } from "@snk/solver/step";
|
import { step } from "@snk/solver/step";
|
||||||
import tmp from "tmp";
|
import tmp from "tmp";
|
||||||
import execa from "execa";
|
import gifsicle from "gifsicle";
|
||||||
|
// @ts-ignore
|
||||||
|
import GIFEncoder from "gif-encoder-2";
|
||||||
|
|
||||||
const withTmpDir = async <T>(
|
const withTmpDir = async <T>(
|
||||||
handler: (dir: string) => Promise<T>
|
handler: (dir: string) => Promise<T>
|
||||||
@@ -41,6 +44,11 @@ export const createGif = async (
|
|||||||
const grid = copyGrid(grid0);
|
const grid = copyGrid(grid0);
|
||||||
const stack: Color[] = [];
|
const stack: Color[] = [];
|
||||||
|
|
||||||
|
const encoder = new GIFEncoder(width, height, "octree", false);
|
||||||
|
encoder.setRepeat(0);
|
||||||
|
encoder.setDelay(gifOptions.frameDuration);
|
||||||
|
encoder.start();
|
||||||
|
|
||||||
for (let i = 0; i < chain.length; i += 1) {
|
for (let i = 0; i < chain.length; i += 1) {
|
||||||
const snake0 = chain[i];
|
const snake0 = chain[i];
|
||||||
const snake1 = chain[Math.min(chain.length - 1, i + 1)];
|
const snake1 = chain[Math.min(chain.length - 1, i + 1)];
|
||||||
@@ -60,41 +68,18 @@ export const createGif = async (
|
|||||||
drawOptions
|
drawOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
const buffer = canvas.toBuffer("image/png", {
|
encoder.addFrame(ctx);
|
||||||
compressionLevel: 0,
|
|
||||||
filters: canvas.PNG_FILTER_NONE,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fileName = path.join(
|
|
||||||
dir,
|
|
||||||
`${(i * gifOptions.step + k).toString().padStart(4, "0")}.png`
|
|
||||||
);
|
|
||||||
|
|
||||||
fs.writeFileSync(fileName, buffer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const outFileName = path.join(dir, "out.gif");
|
const outFileName = path.join(dir, "out.gif");
|
||||||
const optimizedFileName = path.join(dir, "out.optimized.gif");
|
const optimizedFileName = path.join(dir, "out.optimized.gif");
|
||||||
|
|
||||||
await execa(
|
encoder.finish();
|
||||||
"gm",
|
fs.writeFileSync(outFileName, encoder.out.getData());
|
||||||
[
|
|
||||||
"convert",
|
|
||||||
["-loop", "0"],
|
|
||||||
["-delay", (gifOptions.frameDuration / 10).toString()],
|
|
||||||
// ["-dispose", "2"], // for transparent gif
|
|
||||||
// ["-layers", "OptimizeFrame"],
|
|
||||||
// ["-compress", "LZW"],
|
|
||||||
// ["-strip"],
|
|
||||||
|
|
||||||
path.join(dir, "*.png"),
|
execFileSync(
|
||||||
outFileName,
|
gifsicle,
|
||||||
].flat()
|
|
||||||
);
|
|
||||||
|
|
||||||
await execa(
|
|
||||||
"gifsicle",
|
|
||||||
[
|
[
|
||||||
//
|
//
|
||||||
"--optimize=3",
|
"--optimize=3",
|
||||||
|
|||||||
@@ -5,11 +5,12 @@
|
|||||||
"@snk/draw": "1.0.0",
|
"@snk/draw": "1.0.0",
|
||||||
"@snk/solver": "1.0.0",
|
"@snk/solver": "1.0.0",
|
||||||
"canvas": "2.8.0",
|
"canvas": "2.8.0",
|
||||||
"execa": "5.1.1",
|
"tmp": "0.2.1",
|
||||||
"tmp": "0.2.1"
|
"gif-encoder-2": "1.0.5",
|
||||||
|
"gifsicle": "5.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/execa": "2.0.0",
|
"@types/gifsicle": "5.2.0",
|
||||||
"@types/tmp": "0.2.1",
|
"@types/tmp": "0.2.1",
|
||||||
"@zeit/ncc": "0.22.3"
|
"@zeit/ncc": "0.22.3"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user