From 0fe8b2f1d380449ce1dbdbae5f7dd449957e6bc7 Mon Sep 17 00:00:00 2001 From: ful1e5 <24286590+ful1e5@users.noreply.github.com> Date: Tue, 26 Jan 2021 19:52:54 +0530 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=9D=20Performance=20tweak=20&=20pretti?= =?UTF-8?q?er?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .prettierrc | 4 +- hotspots.json | 118 ++++++++++++++-------------- nodemon.json | 22 +++--- package.json | 62 +++++++-------- src/config.ts | 11 ++- src/index.ts | 182 +++++++++++++++++++++----------------------- src/utils/toHTML.ts | 2 +- 7 files changed, 197 insertions(+), 204 deletions(-) diff --git a/.prettierrc b/.prettierrc index 55ea2b2..222861c 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,4 @@ { - "tabWidth": 4, - "useTabs": false + "tabWidth": 2, + "useTabs": false } diff --git a/hotspots.json b/hotspots.json index 40bde3d..adbba3b 100644 --- a/hotspots.json +++ b/hotspots.json @@ -1,102 +1,102 @@ { - "all_scroll": { "xhot": 100, "yhot": 100 }, + "all_scroll": { "xhot": 100, "yhot": 100 }, - "bottom_left_corner": { "xhot": 100, "yhot": 100 }, - "fd_double_arrow": { "xhot": 100, "yhot": 100 }, - "top_right_corner": { "xhot": 100, "yhot": 100 }, + "bottom_left_corner": { "xhot": 100, "yhot": 100 }, + "fd_double_arrow": { "xhot": 100, "yhot": 100 }, + "top_right_corner": { "xhot": 100, "yhot": 100 }, - "bottom_right_corner": { "xhot": 100, "yhot": 100 }, - "bd_double_arrow": { "xhot": 100, "yhot": 100 }, - "top_left_corner": { "xhot": 100, "yhot": 100 }, + "bottom_right_corner": { "xhot": 100, "yhot": 100 }, + "bd_double_arrow": { "xhot": 100, "yhot": 100 }, + "top_left_corner": { "xhot": 100, "yhot": 100 }, - "bottom_tee": { "xhot": 141, "yhot": 99 }, + "bottom_tee": { "xhot": 141, "yhot": 99 }, - "center_ptr": { "xhot": 61, "yhot": 100 }, + "center_ptr": { "xhot": 61, "yhot": 100 }, - "circle": { "xhot": 47, "yhot": 39 }, - "crossed_circle": { "xhot": 47, "yhot": 39 }, - "dnd_no_drop": { "xhot": 47, "yhot": 39 }, + "circle": { "xhot": 47, "yhot": 39 }, + "crossed_circle": { "xhot": 47, "yhot": 39 }, + "dnd_no_drop": { "xhot": 47, "yhot": 39 }, - "context_menu": { "xhot": 61, "yhot": 58 }, + "context_menu": { "xhot": 61, "yhot": 58 }, - "copy": { "xhot": 47, "yhot": 39 }, - "dnd_copy": { "xhot": 47, "yhot": 39 }, + "copy": { "xhot": 47, "yhot": 39 }, + "dnd_copy": { "xhot": 47, "yhot": 39 }, - "cross": { "xhot": 100, "yhot": 100 }, - "tcross": { "xhot": 100, "yhot": 100 }, + "cross": { "xhot": 100, "yhot": 100 }, + "tcross": { "xhot": 100, "yhot": 100 }, - "crosshair": { "xhot": 100, "yhot": 100 }, + "crosshair": { "xhot": 100, "yhot": 100 }, - "dotbox": { "xhot": 100, "yhot": 100 }, + "dotbox": { "xhot": 100, "yhot": 100 }, - "hand1": { "xhot": 94, "yhot": 105 }, + "hand1": { "xhot": 94, "yhot": 105 }, - "hand2": { "xhot": 66, "yhot": 34 }, + "hand2": { "xhot": 66, "yhot": 34 }, - "left_ptr": { "xhot": 68, "yhot": 41 }, + "left_ptr": { "xhot": 68, "yhot": 41 }, - "left_side": { "xhot": 100, "yhot": 100 }, - "right_side": { "xhot": 100, "yhot": 100 }, + "left_side": { "xhot": 100, "yhot": 100 }, + "right_side": { "xhot": 100, "yhot": 100 }, - "left_tee": { "xhot": 100, "yhot": 58 }, + "left_tee": { "xhot": 100, "yhot": 58 }, - "link": { "xhot": 61, "yhot": 105 }, - "dnd_link": { "xhot": 61, "yhot": 105 }, + "link": { "xhot": 61, "yhot": 105 }, + "dnd_link": { "xhot": 61, "yhot": 105 }, - "ll_angle": { "xhot": 141, "yhot": 58 }, + "ll_angle": { "xhot": 141, "yhot": 58 }, - "lr_angle": { "xhot": 141, "yhot": 138 }, + "lr_angle": { "xhot": 141, "yhot": 138 }, - "move": { "xhot": 80, "yhot": 106 }, - "dnd_move": { "xhot": 80, "yhot": 106 }, - "dnd_none": { "xhot": 80, "yhot": 106 }, - "grabbing": { "xhot": 80, "yhot": 106 }, - "pointer_move": { "xhot": 80, "yhot": 106 }, + "move": { "xhot": 80, "yhot": 106 }, + "dnd_move": { "xhot": 80, "yhot": 106 }, + "dnd_none": { "xhot": 80, "yhot": 106 }, + "grabbing": { "xhot": 80, "yhot": 106 }, + "pointer_move": { "xhot": 80, "yhot": 106 }, - "pencil": { "xhot": 141, "yhot": 58 }, + "pencil": { "xhot": 141, "yhot": 58 }, - "plus": { "xhot": 100, "yhot": 100 }, + "plus": { "xhot": 100, "yhot": 100 }, - "question_arrow": { "xhot": 105, "yhot": 105 }, - "dnd_ask": { "xhot": 105, "yhot": 105 }, + "question_arrow": { "xhot": 105, "yhot": 105 }, + "dnd_ask": { "xhot": 105, "yhot": 105 }, - "right_ptr": { "xhot": 61, "yhot": 138 }, + "right_ptr": { "xhot": 61, "yhot": 138 }, - "right_tee": { "xhot": 100, "yhot": 138 }, + "right_tee": { "xhot": 100, "yhot": 138 }, - "sb_down_arrow": { "xhot": 133, "yhot": 99 }, + "sb_down_arrow": { "xhot": 133, "yhot": 99 }, - "sb_h_double_arrow": { "xhot": 100, "yhot": 100 }, + "sb_h_double_arrow": { "xhot": 100, "yhot": 100 }, - "sb_left_arrow": { "xhot": 100, "yhot": 68 }, + "sb_left_arrow": { "xhot": 100, "yhot": 68 }, - "sb_right_arrow": { "xhot": 100, "yhot": 138 }, + "sb_right_arrow": { "xhot": 100, "yhot": 138 }, - "sb_up_arrow": { "xhot": 68, "yhot": 99 }, + "sb_up_arrow": { "xhot": 68, "yhot": 99 }, - "sb_v_double_arrow": { "xhot": 100, "yhot": 100 }, + "sb_v_double_arrow": { "xhot": 100, "yhot": 100 }, - "top_side": { "xhot": 100, "yhot": 100 }, - "bottom_side": { "xhot": 100, "yhot": 100 }, + "top_side": { "xhot": 100, "yhot": 100 }, + "bottom_side": { "xhot": 100, "yhot": 100 }, - "top_tee": { "xhot": 61, "yhot": 99 }, + "top_tee": { "xhot": 61, "yhot": 99 }, - "ul_angle": { "xhot": 61, "yhot": 65 }, + "ul_angle": { "xhot": 61, "yhot": 65 }, - "ur_angle": { "xhot": 61, "yhot": 138 }, + "ur_angle": { "xhot": 61, "yhot": 138 }, - "vertical_text": { "xhot": 100, "yhot": 102 }, + "vertical_text": { "xhot": 100, "yhot": 102 }, - "wait": { "xhot": 104, "yhot": 105 }, - "left_ptr_watch": { "xhot": 104, "yhot": 105 }, + "wait": { "xhot": 104, "yhot": 105 }, + "left_ptr_watch": { "xhot": 104, "yhot": 105 }, - "wayland_cursor": { "xhot": 100, "yhot": 100 }, + "wayland_cursor": { "xhot": 100, "yhot": 100 }, - "x_cursor": { "xhot": 100, "yhot": 100 }, + "x_cursor": { "xhot": 100, "yhot": 100 }, - "xterm": { "xhot": 97, "yhot": 97 }, + "xterm": { "xhot": 97, "yhot": 97 }, - "zoom_in": { "xhot": 76, "yhot": 78 }, + "zoom_in": { "xhot": 76, "yhot": 78 }, - "zoom_out": { "xhot": 76, "yhot": 78 } + "zoom_out": { "xhot": 76, "yhot": 78 } } diff --git a/nodemon.json b/nodemon.json index add0447..cde9605 100644 --- a/nodemon.json +++ b/nodemon.json @@ -1,13 +1,13 @@ { - "restartable": "rs", - "ignore": [".git", "node_modules/**/node_modules"], - "verbose": true, - "execMap": { - "ts": "node --require ts-node/register" - }, - "watch": ["src/"], - "env": { - "NODE_ENV": "development" - }, - "ext": "js,json,ts" + "restartable": "rs", + "ignore": [".git", "node_modules/**/node_modules"], + "verbose": true, + "execMap": { + "ts": "node --require ts-node/register" + }, + "watch": ["src/"], + "env": { + "NODE_ENV": "development" + }, + "ext": "js,json,ts" } diff --git a/package.json b/package.json index 6f82618..1ddaefa 100644 --- a/package.json +++ b/package.json @@ -1,33 +1,33 @@ { - "name": "apple_cursor", - "version": "1.0.6", - "description": "šŸŽ macOS Cursor Theme", - "main": "index.js", - "scripts": { - "clean": "rm -rf bitmaps themes", - "dev": "nodemon src/index.ts", - "watch": "nodemon --inspect src/index.ts", - "py_install": "pip install -r requirements.txt", - "render": "yarn ts-node src/index.ts", - "build": "python build.py", - "compile": "yarn clean && yarn render && yarn build" - }, - "repository": "git@github.com:ful1e5/apple_cursor.git", - "author": "Kaiz Khatri", - "license": "GPL-3.0", - "private": true, - "devDependencies": { - "@types/pixelmatch": "^5.2.2", - "@types/pngjs": "^3.4.2", - "@types/puppeteer": "^3.0.1", - "nodemon": "^2.0.4", - "ts-node": "^8.10.2", - "tslint": "^6.1.2", - "typescript": "^3.9.7" - }, - "dependencies": { - "pixelmatch": "^5.2.1", - "pngjs": "^6.0.0", - "puppeteer": "^5.2.1" - } + "name": "apple_cursor", + "version": "1.0.6", + "description": "šŸŽ macOS Cursor Theme", + "main": "index.js", + "scripts": { + "clean": "rm -rf bitmaps themes", + "dev": "nodemon src/index.ts", + "watch": "nodemon --inspect src/index.ts", + "py_install": "pip install -r requirements.txt", + "render": "yarn ts-node src/index.ts", + "build": "python build.py", + "compile": "yarn clean && yarn render && yarn build" + }, + "repository": "git@github.com:ful1e5/apple_cursor.git", + "author": "Kaiz Khatri", + "license": "GPL-3.0", + "private": true, + "devDependencies": { + "@types/pixelmatch": "^5.2.2", + "@types/pngjs": "^3.4.2", + "@types/puppeteer": "^3.0.1", + "nodemon": "^2.0.4", + "ts-node": "^8.10.2", + "tslint": "^6.1.2", + "typescript": "^3.9.7" + }, + "dependencies": { + "pixelmatch": "^5.2.1", + "pngjs": "^6.0.0", + "puppeteer": "^5.2.1" + } } diff --git a/src/config.ts b/src/config.ts index a69a14e..3aa67cc 100644 --- a/src/config.ts +++ b/src/config.ts @@ -2,13 +2,12 @@ import { resolve } from "path"; import { readdirSync, existsSync } from "fs"; // Source Directory -const svgsDir = resolve(__dirname, "svg"); -if (!existsSync(svgsDir)) { - console.log("Source .svg files not found"); -} +const staticCursorsDir = resolve(__dirname, "svg", "static"); +const animatedCursorsDir = resolve(__dirname, "svg", "animated"); -const staticCursorsDir = resolve(svgsDir, "static"); -const animatedCursorsDir = resolve(svgsDir, "animated"); +if (!existsSync(staticCursorsDir) || !existsSync(animatedCursorsDir)) { + throw new Error("svg directory not found"); +} // Out Directory const bitmapsDir = resolve(__dirname, "../", "bitmaps"); diff --git a/src/index.ts b/src/index.ts index e0a20ab..7ca4ed4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,16 +1,40 @@ +import "module-alias/register"; + import fs from "fs"; import path from "path"; -import puppeteer from "puppeteer"; +import Pixelmatch from "pixelmatch"; -import { htmlTemplate } from "./utils/htmlTemplate"; -import { staticCursors, bitmapsDir, animatedCursors } from "./config"; -import { matchImages } from "./utils/matchImages"; -import { saveFrames, Frames } from "./utils/saveFrames"; +import { PNG } from "pngjs"; +import puppeteer, { ElementHandle, Page } from "puppeteer"; + +import { animatedCursors, bitmapsDir, staticCursors } from "./config"; import { getFrameName } from "./utils/getFrameName"; +import { toHTML } from "./utils/toHTML"; + +const getSVGElement = async (page: Page) => { + const svg = await page.$("#container svg"); + + if (!svg) { + throw new Error("svg element not found!"); + } + return svg; +}; + +const screenshot = async (element: ElementHandle): Promise => { + return await element.screenshot({ + omitBackground: true, + encoding: "binary", + }); +}; + +const saveFrame = (key: string, frame: Buffer) => { + const out_path = path.resolve(bitmapsDir, key); + fs.writeFileSync(out_path, frame, { encoding: "binary" }); +}; const main = async () => { const browser = await puppeteer.launch({ - ignoreDefaultArgs: [" --single-process ", "--no-sandbox"], + ignoreDefaultArgs: ["--single-process", "--no-sandbox"], headless: true, }); @@ -18,100 +42,70 @@ const main = async () => { fs.mkdirSync(bitmapsDir); } - try { - console.log("šŸ“ø Rendering Static Cursors..."); - - for (let svgPath of staticCursors) { - const buffer = fs.readFileSync(path.resolve(svgPath), "utf8"); - if (!buffer) throw new Error(`${svgPath} File Read error`); - - // Generating HTML Template - const data = buffer.toString(); - const template = htmlTemplate(data); - - // config - const bitmapName = `${path.basename(svgPath, ".svg")}.png`; - const out = path.resolve(bitmapsDir, bitmapName); - - // Render - const page = await browser.newPage(); - await page.setContent(template); - - await page.waitForSelector("#container"); - const svgElement = await page.$("#container svg"); - if (!svgElement) throw new Error("svg element not found"); - await svgElement.screenshot({ omitBackground: true, path: out }); - - await page.close(); + for (const svgFilePath of staticCursors) { + const svgData = fs.readFileSync(svgFilePath, "utf-8"); + if (!svgData) { + throw new Error(`${svgFilePath} File Read error`); } - console.log("šŸŽ„ Rendering Animated Cursors..."); + const page = await browser.newPage(); + const html = toHTML(svgData); - for (let svgPath of animatedCursors) { - const buffer = fs.readFileSync(svgPath, "utf8"); - if (!buffer) throw new Error(`${svgPath} File Read error`); + await page.setContent(html); + const svg = await getSVGElement(page); - // Generating HTML Template - const data = buffer.toString(); - const template = htmlTemplate(data); + const key = `${path.basename(svgFilePath, ".svg")}.png`; + const out = path.join(bitmapsDir, key); - const page = await browser.newPage(); - await page.setContent(template, { waitUntil: "networkidle2" }); - - await page.waitForSelector("#container"); - const svgElement = await page.$("#container svg"); - if (!svgElement) throw new Error("svg element not found"); - - // Render Config - let index = 1; - let breakRendering = false; - const frames: Frames = {}; - const firstKey = getFrameName(index, svgPath); - - console.log("Rendering", path.basename(svgPath), "..."); - console.log(firstKey); - - // 1st Frame - frames[firstKey] = { - buffer: await svgElement.screenshot({ - omitBackground: true, - encoding: "binary", - }), - }; - - // Pushing frames until it match to 1st frame - index++; - while (!breakRendering) { - const newFrame = await svgElement.screenshot({ - omitBackground: true, - encoding: "binary", - }); - const key = getFrameName(index, svgPath); - console.log(key); - const diff = matchImages({ - img1Buff: frames[firstKey].buffer, - img2Buff: newFrame, - }); - - if (!(diff < 700)) { - frames[key] = { buffer: newFrame }; - } else { - breakRendering = true; - } - index++; - } - - saveFrames(frames); - - await page.close(); - } - - console.log(`\nBitmaps stored at ${bitmapsDir}\n\nšŸŽ‰ Render Done.`); - process.exit(0); - } catch (error) { - console.error(error); - process.exit(1); + console.log("Saving", key, "..."); + await svg.screenshot({ omitBackground: true, path: out }); + await page.close(); } + + for (const svgFilePath of animatedCursors) { + const svgData = fs.readFileSync(svgFilePath, "utf8"); + if (!svgData) { + throw new Error(`${svgFilePath} File Read error`); + } + + const page = await browser.newPage(); + const html = toHTML(svgData); + + await page.setContent(html); + const svg = await getSVGElement(page); + + let index = 1; + let breakRendering = false; + + // Rendering 1st frame + const img1 = await screenshot(svg); + const key1 = getFrameName(index, svgFilePath); + + console.log("Saving", key1, "..."); + saveFrame(key1, img1); + + // Rendering frames till `imgN` matched to `img1` + while (!breakRendering) { + ++index; + const imgN = await screenshot(svg); + const keyN = getFrameName(index, svgFilePath); + + console.log("Saving", keyN, "..."); + saveFrame(keyN, imgN); + + const { data: img1Data, width, height } = PNG.sync.read(img1); + const { data: imgNData } = PNG.sync.read(imgN); + + const diff = Pixelmatch(img1Data, imgNData, null, width, height); + + if (diff <= 100) { + breakRendering = !breakRendering; + } + } + + await page.close(); + } + await browser.close(); }; main(); diff --git a/src/utils/toHTML.ts b/src/utils/toHTML.ts index e64ef19..36fbbf4 100644 --- a/src/utils/toHTML.ts +++ b/src/utils/toHTML.ts @@ -16,4 +16,4 @@ export const template = ` `; export const toHTML = (svgData: string): string => - template.replace("", svgData); + template.replace("", svgData);