diff --git a/bitmapper/src/index.ts b/bitmapper/src/index.ts index 2b95690..9cff291 100644 --- a/bitmapper/src/index.ts +++ b/bitmapper/src/index.ts @@ -1,12 +1,10 @@ import fs from "fs"; import path from "path"; -import Pixelmatch from "pixelmatch"; - -import { PNG } from "pngjs"; import puppeteer, { ElementHandle, Page } from "puppeteer"; import { animatedCursors, outDir, staticCursors } from "./config"; -import { getFrameName } from "./utils/getFrameName"; +import { frameNumber } from "./utils/frameNumber"; +import { matchImages } from "./utils/matchImages"; import { toHTML } from "./utils/toHTML"; const getSVGElement = async (page: Page) => { @@ -19,13 +17,27 @@ const getSVGElement = async (page: Page) => { }; const screenshot = async (element: ElementHandle): Promise => { - return await element.screenshot({ + return element.screenshot({ omitBackground: true, encoding: "binary", }); }; -const saveFrame = (key: string, frame: Buffer) => { +const stopAnimation = async (page: Page) => { + // @ts-ignore + await page._client.send("Animation.setPlaybackRate", { + playbackRate: 0, + }); +}; + +const resumeAnimation = async (page: Page, playbackRate: number = 0.1) => { + // @ts-ignore + await page._client.send("Animation.setPlaybackRate", { + playbackRate, + }); +}; + +const saveFrameImage = (key: string, frame: Buffer) => { const out_path = path.resolve(outDir, key); fs.writeFileSync(out_path, frame, { encoding: "binary" }); }; @@ -73,56 +85,38 @@ const main = async () => { await page.setContent(html); const svg = await getSVGElement(page); + await stopAnimation(page); let index = 1; - const playbackRate = 0.1; + const frameLimit = 300; let breakRendering = false; + let prevImg: Buffer; - // Rendering 1st frame - const img1 = await screenshot(svg); - const key1 = getFrameName(index, svgFilePath, 4); - - console.log("Saving", key1, "..."); - saveFrame(key1, img1); - - // stop animation - // @ts-ignore - await page._client.send("Animation.setPlaybackRate", { - playbackRate: 0, - }); - - // Rendering frames till `imgN` matched to `img1` + // Rendering frames till `imgN` matched to `imgN-1` (When Animation is done) while (!breakRendering) { - ++index; - - // resume animation - // @ts-ignore - await page._client.send("Animation.setPlaybackRate", { - playbackRate, - }); - - const imgN = await screenshot(svg); - const keyN = getFrameName(index, svgFilePath, 4); - - const { data: img1Data, width, height } = PNG.sync.read(img1); - const { data: imgNData } = PNG.sync.read(imgN); - - const diff = Pixelmatch(img1Data, imgNData, null, width, height, { - threshold: 0.12, - }); - - if (diff <= 100) { - breakRendering = !breakRendering; - } else { - console.log("Saving", keyN, "..."); - saveFrame(keyN, imgN); - - // stop animation - // @ts-ignore - await page._client.send("Animation.setPlaybackRate", { - playbackRate: 0, - }); + if (index > frameLimit) { + throw new Error("Reached the frame limit."); } + + resumeAnimation(page); + const img = await screenshot(svg); + stopAnimation(page); + + if (index > 1) { + // @ts-ignore + const diff = matchImages(prevImg, img); + if (diff <= 100) { + breakRendering = !breakRendering; + } + } + const frame = frameNumber(index, 3); + const key = `${path.basename(svgFilePath, ".svg")}-${frame}.png`; + + console.log("Saving", key, "..."); + saveFrameImage(key, img); + + prevImg = img; + ++index; } await page.close(); diff --git a/bitmapper/src/utils/frameNumber.ts b/bitmapper/src/utils/frameNumber.ts new file mode 100644 index 0000000..76d1165 --- /dev/null +++ b/bitmapper/src/utils/frameNumber.ts @@ -0,0 +1,7 @@ +export const frameNumber = (index: number, padding: number) => { + let result = "" + index; + while (result.length < padding) { + result = "0" + result; + } + return result; +}; diff --git a/bitmapper/src/utils/getFrameName.ts b/bitmapper/src/utils/getFrameName.ts deleted file mode 100644 index d7d5d70..0000000 --- a/bitmapper/src/utils/getFrameName.ts +++ /dev/null @@ -1,18 +0,0 @@ -import path from "path"; - -export const frameNumber = (index: number, endIndex: number) => { - let result = "" + index; - while (result.length < endIndex) { - result = "0" + result; - } - return result; -}; - -export const getFrameName = ( - index: number, - fileName: string, - padding: number = 2 -) => { - const frame = frameNumber(index, padding); - return `${path.basename(fileName, ".svg")}-${frame}.png`; -}; diff --git a/bitmapper/src/utils/matchImages.ts b/bitmapper/src/utils/matchImages.ts new file mode 100644 index 0000000..6d09a95 --- /dev/null +++ b/bitmapper/src/utils/matchImages.ts @@ -0,0 +1,11 @@ +import Pixelmatch from "pixelmatch"; +import { PNG } from "pngjs"; + +export const matchImages = (img1: Buffer, img2: Buffer): number => { + const { data: img1Data, width, height } = PNG.sync.read(img1); + const { data: imgNData } = PNG.sync.read(img2); + + return Pixelmatch(img1Data, imgNData, null, width, height, { + threshold: 0.1, + }); +}; diff --git a/svg/animated/left_ptr_watch.svg b/svg/animated/left_ptr_watch.svg index 74fec06..eeae5ea 100644 --- a/svg/animated/left_ptr_watch.svg +++ b/svg/animated/left_ptr_watch.svg @@ -1,7 +1,7 @@ + begin="0s" dur="0.6s" repeatCount="1" /> diff --git a/svg/animated/wait.svg b/svg/animated/wait.svg index 43ee9ce..26710b5 100644 --- a/svg/animated/wait.svg +++ b/svg/animated/wait.svg @@ -4,7 +4,7 @@ + begin="0s" dur="0.6s" repeatCount="1" />