@@ -1,3 +1 @@
|
|||||||
liberapay: ful1e5
|
github: ful1e5
|
||||||
patreon: ful1e5
|
|
||||||
custom: https://www.paypal.me/kaizkhatri
|
|
||||||
|
|||||||
@@ -1,142 +1,7 @@
|
|||||||
# Custom
|
# Custom
|
||||||
bitmaps
|
|
||||||
themes
|
themes
|
||||||
bin
|
bin
|
||||||
|
|
||||||
# Python
|
|
||||||
# Byte-compiled / optimized / DLL files
|
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
*$py.class
|
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Distribution / packaging
|
|
||||||
.Python
|
|
||||||
build/
|
|
||||||
develop-eggs/
|
|
||||||
dist/
|
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
.eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
wheels/
|
|
||||||
pip-wheel-metadata/
|
|
||||||
share/python-wheels/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
MANIFEST
|
|
||||||
|
|
||||||
# PyInstaller
|
|
||||||
# Usually these files are written by a python script from a template
|
|
||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
||||||
*.manifest
|
|
||||||
*.spec
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
htmlcov/
|
|
||||||
.tox/
|
|
||||||
.nox/
|
|
||||||
.coverage
|
|
||||||
.coverage.*
|
|
||||||
.cache
|
|
||||||
nosetests.xml
|
|
||||||
coverage.xml
|
|
||||||
*.cover
|
|
||||||
*.py,cover
|
|
||||||
.hypothesis/
|
|
||||||
.pytest_cache/
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
*.pot
|
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
local_settings.py
|
|
||||||
db.sqlite3
|
|
||||||
db.sqlite3-journal
|
|
||||||
|
|
||||||
# Flask stuff:
|
|
||||||
instance/
|
|
||||||
.webassets-cache
|
|
||||||
|
|
||||||
# Scrapy stuff:
|
|
||||||
.scrapy
|
|
||||||
|
|
||||||
# Sphinx documentation
|
|
||||||
docs/_build/
|
|
||||||
|
|
||||||
# PyBuilder
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Jupyter Notebook
|
|
||||||
.ipynb_checkpoints
|
|
||||||
|
|
||||||
# IPython
|
|
||||||
profile_default/
|
|
||||||
ipython_config.py
|
|
||||||
|
|
||||||
# pyenv
|
|
||||||
.python-version
|
|
||||||
|
|
||||||
# pipenv
|
|
||||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
||||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
||||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
||||||
# install all needed dependencies.
|
|
||||||
#Pipfile.lock
|
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
||||||
__pypackages__/
|
|
||||||
|
|
||||||
# Celery stuff
|
|
||||||
celerybeat-schedule
|
|
||||||
celerybeat.pid
|
|
||||||
|
|
||||||
# SageMath parsed files
|
|
||||||
*.sage.py
|
|
||||||
|
|
||||||
# Environments
|
|
||||||
.env
|
|
||||||
.venv
|
|
||||||
env/
|
|
||||||
venv/
|
|
||||||
ENV/
|
|
||||||
env.bak/
|
|
||||||
venv.bak/
|
|
||||||
|
|
||||||
# Spyder project settings
|
|
||||||
.spyderproject
|
|
||||||
.spyproject
|
|
||||||
|
|
||||||
# Rope project settings
|
|
||||||
.ropeproject
|
|
||||||
|
|
||||||
# mkdocs documentation
|
|
||||||
/site
|
|
||||||
|
|
||||||
# mypy
|
|
||||||
.mypy_cache/
|
|
||||||
.dmypy.json
|
|
||||||
dmypy.json
|
|
||||||
|
|
||||||
# Pyre type checker
|
|
||||||
.pyre/
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------- Nodejs
|
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
@@ -14,9 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Fix `None` value warning in `builder/symlinks.py`
|
|
||||||
- sponsorship links updated
|
|
||||||
- fixed #17
|
- fixed #17
|
||||||
|
- fixed #21
|
||||||
|
|
||||||
## [v1.0.3] - 13 Nov 2021
|
## [v1.0.3] - 13 Nov 2021
|
||||||
|
|
||||||
|
|||||||
@@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively
|
|||||||
state the exclusion of warranty; and each file should have at least
|
state the exclusion of warranty; and each file should have at least
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
Extended KDE Cursor
|
||||||
Copyright (C) <year> <name of author>
|
Copyright (C) 2022 Abdulkaiz Khatri
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
|
|||||||
If the program does terminal interaction, make it output a short
|
If the program does terminal interaction, make it output a short
|
||||||
notice like this when it starts in an interactive mode:
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
<program> Copyright (C) <year> <name of author>
|
BreezeX_Cursor Copyright (C) 2022 Abdulkaiz Khatri
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
This is free software, and you are welcome to redistribute it
|
This is free software, and you are welcome to redistribute it
|
||||||
under certain conditions; type `show c' for details.
|
under certain conditions; type `show c' for details.
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
all: clean render build
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@rm -rf bitmaps themes
|
|
||||||
|
|
||||||
render: bitmapper svg
|
|
||||||
@cd bitmapper && $(MAKE)
|
|
||||||
|
|
||||||
build: bitmaps
|
|
||||||
@cd builder && make build clean
|
|
||||||
|
|
||||||
.PHONY: all
|
|
||||||
|
|
||||||
unix: clean render bitmaps
|
|
||||||
@cd builder && make build_unix clean
|
|
||||||
|
|
||||||
windows: clean render bitmaps
|
|
||||||
@cd builder && make build_windows clean
|
|
||||||
|
|
||||||
|
|
||||||
# Installation
|
|
||||||
.ONESHELL:
|
|
||||||
SHELL:=/bin/bash
|
|
||||||
THEME_PREFIX = BreezeX
|
|
||||||
|
|
||||||
src = ./themes/$(THEME_PREFIX)-*
|
|
||||||
local := ~/.icons
|
|
||||||
local_dest := $(local)/$(THEME_PREFIX)-*
|
|
||||||
|
|
||||||
root := /usr/share/icons
|
|
||||||
root_dest := $(root)/$(THEME_PREFIX)-*
|
|
||||||
|
|
||||||
install: themes
|
|
||||||
@if [[ $EUID -ne 0 ]]; then
|
|
||||||
@echo "> Installing '$(THEME_PREFIX)' cursors inside $(local)/..."
|
|
||||||
@mkdir -p $(local)
|
|
||||||
@cp -r $(src) $(local)/ && echo "> Installed!"
|
|
||||||
@else
|
|
||||||
@echo "> Installing '$(THEME_PREFIX)' cursors inside $(root)/..."
|
|
||||||
@mkdir -p $(root)
|
|
||||||
@sudo cp -r $(src) $(root)/ && echo "> Installed!"
|
|
||||||
@fi
|
|
||||||
|
|
||||||
uninstall:
|
|
||||||
@if [[ $EUID -ne 0 ]]; then
|
|
||||||
@echo "> Removing '$(THEME_PREFIX)' cursors from '$(local)'..."
|
|
||||||
@rm -rf $(local_dest)
|
|
||||||
@else
|
|
||||||
@echo "> Removing '$(THEME_PREFIX)' cursors from '$(root)'..."
|
|
||||||
@sudo rm -rf $(root_dest)
|
|
||||||
@fi
|
|
||||||
|
|
||||||
reinstall: uninstall install
|
|
||||||
|
|
||||||
# generates binaries
|
|
||||||
BIN_DIR = ../bin
|
|
||||||
THEMES = Dark Light Black
|
|
||||||
prepare: bitmaps themes
|
|
||||||
@rm -rf bin && mkdir bin
|
|
||||||
@$(foreach theme,$(THEMES), mkdir -p bin/$(THEME_PREFIX)-$(theme);)
|
|
||||||
@cd bitmaps
|
|
||||||
@$(foreach theme,$(THEMES), zip -r $(BIN_DIR)/$(THEME_PREFIX)-$(theme)/bitmaps.zip $(THEME_PREFIX)-$(theme);)
|
|
||||||
@zip -r $(BIN_DIR)/bitmaps.zip *
|
|
||||||
@cd ..
|
|
||||||
@cd themes
|
|
||||||
@$(foreach theme,$(THEMES), tar -czvf $(BIN_DIR)/$(THEME_PREFIX)-$(theme)/$(THEME_PREFIX)-$(theme).tar.gz $(THEME_PREFIX)-$(theme);)
|
|
||||||
@$(foreach theme,$(THEMES), zip -r $(BIN_DIR)/$(THEME_PREFIX)-$(theme)/$(THEME_PREFIX)-$(theme)-Windows.zip $(THEME_PREFIX)-$(theme)-Windows;)
|
|
||||||
@cd ..
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# BreezeX Cursor
|
# BreezeX Cursor
|
||||||
|
|
||||||
Extended KDE Cursor theme, Highly inspired on **KDE Breeze** for `Windows` and `Linux` with _HiDPi Support_ 🎉.
|
Extended KDE cursor, Highly inspired on **KDE Breeze** for `Windows` and `Linux` with _HiDPi Support_ 🎉.
|
||||||
|
|
||||||
[](https://github.com/ful1e5/BreezeX_Cursor/actions)
|
[](https://github.com/ful1e5/BreezeX_Cursor/actions)
|
||||||
[](https://www.codefactor.io/repository/github/ful1e5/breezex_cursor)
|
[](https://www.codefactor.io/repository/github/ful1e5/breezex_cursor)
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
all: install render
|
|
||||||
|
|
||||||
.PHONY: all
|
|
||||||
|
|
||||||
install: node_modules package.json
|
|
||||||
@yarn install
|
|
||||||
|
|
||||||
render:
|
|
||||||
@yarn render
|
|
||||||
|
|
||||||
watch:
|
|
||||||
@yarn watch
|
|
||||||
|
|
||||||
node_modules:
|
|
||||||
@mkdir -p $@
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@rm -rf node_modules yarn.lock
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "breezex-bitmapper",
|
|
||||||
"version": "1.0.3",
|
|
||||||
"description": "extended KDE cursor",
|
|
||||||
"main": "index.js",
|
|
||||||
"repository": "git@github.com:ful1e5/BreezeX_Cursor.git",
|
|
||||||
"author": "Kaiz Khatri",
|
|
||||||
"license": "GPL-3.0",
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"render": "npx ts-node src/index.ts"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/pixelmatch": "^5.2.2",
|
|
||||||
"@types/pngjs": "^3.4.2",
|
|
||||||
"@types/puppeteer": "^5.4.2",
|
|
||||||
"nodemon": "^2.0.7",
|
|
||||||
"ts-node": "^9.1.1",
|
|
||||||
"typescript": "^4.1.3"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"pixelmatch": "^5.2.1",
|
|
||||||
"pngjs": "^6.0.0",
|
|
||||||
"puppeteer": "^5.5.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import { Colors } from "./core/types";
|
|
||||||
|
|
||||||
interface Config {
|
|
||||||
themeName: string;
|
|
||||||
color: Colors;
|
|
||||||
}
|
|
||||||
|
|
||||||
const breeze = "#4D4D4D";
|
|
||||||
const white = "#FFFFFF";
|
|
||||||
const black = "#000000";
|
|
||||||
|
|
||||||
const config: Config[] = [
|
|
||||||
{
|
|
||||||
themeName: "BreezeX-Dark",
|
|
||||||
color: {
|
|
||||||
base: breeze,
|
|
||||||
outline: white,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
themeName: "BreezeX-Light",
|
|
||||||
color: {
|
|
||||||
base: white,
|
|
||||||
outline: breeze,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
themeName: "BreezeX-Black",
|
|
||||||
color: {
|
|
||||||
base: black,
|
|
||||||
outline: white,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export { config };
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
import fs from "fs";
|
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
import puppeteer, { Browser, ElementHandle, Page } from "puppeteer";
|
|
||||||
|
|
||||||
import { frameNumber } from "./util/frameNumber";
|
|
||||||
import { matchImages } from "./util/matchImages";
|
|
||||||
import { toHTML } from "./util/toHTML";
|
|
||||||
|
|
||||||
class BitmapsGenerator {
|
|
||||||
/**
|
|
||||||
* Generate Png files from svg code.
|
|
||||||
* @param themeName Give name, So all bitmaps files are organized in one directory.
|
|
||||||
* @param bitmapsDir `absolute` or `relative` path, Where `.png` files will store.
|
|
||||||
*/
|
|
||||||
constructor(private bitmapsDir: string) {
|
|
||||||
this.bitmapsDir = path.resolve(bitmapsDir);
|
|
||||||
this.createDir(this.bitmapsDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create directory if it doesn't exists.
|
|
||||||
* @param dirPath directory `absolute` path.
|
|
||||||
*/
|
|
||||||
private createDir(dirPath: string) {
|
|
||||||
if (!fs.existsSync(dirPath)) {
|
|
||||||
fs.mkdirSync(dirPath, { recursive: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare headless browser.
|
|
||||||
*/
|
|
||||||
public async getBrowser(): Promise<Browser> {
|
|
||||||
return await puppeteer.launch({
|
|
||||||
ignoreDefaultArgs: ["--no-sandbox"],
|
|
||||||
headless: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getSvgElement(
|
|
||||||
page: Page,
|
|
||||||
content: string
|
|
||||||
): Promise<ElementHandle<Element>> {
|
|
||||||
if (!content) {
|
|
||||||
throw new Error(`${content} File Read error`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const html = toHTML(content);
|
|
||||||
await page.setContent(html, { timeout: 0 });
|
|
||||||
|
|
||||||
const svg = await page.$("#container svg");
|
|
||||||
|
|
||||||
if (!svg) {
|
|
||||||
throw new Error("svg element not found!");
|
|
||||||
}
|
|
||||||
return svg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async generateStatic(browser: Browser, content: string, key: string) {
|
|
||||||
const page = await browser.newPage();
|
|
||||||
const svg = await this.getSvgElement(page, content);
|
|
||||||
|
|
||||||
const out = path.resolve(this.bitmapsDir, `${key}.png`);
|
|
||||||
|
|
||||||
await svg.screenshot({ omitBackground: true, path: out });
|
|
||||||
await page.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async screenshot(
|
|
||||||
element: ElementHandle<Element>
|
|
||||||
): Promise<Buffer | string> {
|
|
||||||
const buffer = await element.screenshot({
|
|
||||||
encoding: "binary",
|
|
||||||
omitBackground: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!buffer) {
|
|
||||||
throw new Error("SVG element screenshot not working");
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async stopAnimation(page: Page) {
|
|
||||||
const client = await page.target().createCDPSession();
|
|
||||||
await client.send("Animation.setPlaybackRate", {
|
|
||||||
playbackRate: 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async resumeAnimation(page: Page, playbackRate: number) {
|
|
||||||
const client = await page.target().createCDPSession();
|
|
||||||
await client.send("Animation.setPlaybackRate", {
|
|
||||||
playbackRate,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async saveFrameImage(key: string, frame: Buffer | string) {
|
|
||||||
const out_path = path.resolve(this.bitmapsDir, key);
|
|
||||||
fs.writeFileSync(out_path, frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async generateAnimated(
|
|
||||||
browser: Browser,
|
|
||||||
content: string,
|
|
||||||
key: string,
|
|
||||||
options?: {
|
|
||||||
playbackRate?: number;
|
|
||||||
diff?: number;
|
|
||||||
frameLimit?: number;
|
|
||||||
framePadding?: number;
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
const opt = Object.assign(
|
|
||||||
{ playbackRate: 0.1, diff: 0, frameLimit: 300, framePadding: 4 },
|
|
||||||
options
|
|
||||||
);
|
|
||||||
|
|
||||||
const page = await browser.newPage();
|
|
||||||
const svg = await this.getSvgElement(page, content);
|
|
||||||
await this.stopAnimation(page);
|
|
||||||
|
|
||||||
let index = 1;
|
|
||||||
let breakRendering = false;
|
|
||||||
let prevImg: Buffer | string;
|
|
||||||
|
|
||||||
// Rendering frames till `imgN` matched to `imgN-1` (When Animation is done)
|
|
||||||
while (!breakRendering) {
|
|
||||||
if (index > opt.frameLimit) {
|
|
||||||
throw new Error("Reached the frame limit.");
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.resumeAnimation(page, opt.playbackRate);
|
|
||||||
const img: string | Buffer = await this.screenshot(svg);
|
|
||||||
await this.stopAnimation(page);
|
|
||||||
|
|
||||||
if (index > 1) {
|
|
||||||
// @ts-ignore
|
|
||||||
const diff = matchImages(prevImg, img);
|
|
||||||
if (diff <= opt.diff) {
|
|
||||||
breakRendering = !breakRendering;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const number = frameNumber(index, opt.framePadding);
|
|
||||||
const frame = `${key}-${number}.png`;
|
|
||||||
|
|
||||||
this.saveFrameImage(frame, img);
|
|
||||||
|
|
||||||
prevImg = img;
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
await page.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export { BitmapsGenerator };
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
import fs from "fs";
|
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
interface Svg {
|
|
||||||
key: string;
|
|
||||||
content: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
class SvgDirectoryParser {
|
|
||||||
/**
|
|
||||||
* Manage and Parse SVG file path in `absolute` fashion.
|
|
||||||
* This Parser look svg files as below fashion:
|
|
||||||
* `
|
|
||||||
* <@svgDir>/static
|
|
||||||
* <@svgDir>/animated
|
|
||||||
* `
|
|
||||||
* @param svgDir is relative/absolute path, Where `SVG` files are stored.
|
|
||||||
*/
|
|
||||||
semiAnimated: boolean = false;
|
|
||||||
constructor(private svgDir: string) {
|
|
||||||
if (!fs.existsSync(this.svgDir)) {
|
|
||||||
throw new Error(`SVG files not found in ${this.svgDir}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readData(f: string): Svg {
|
|
||||||
const content = fs.readFileSync(f, "utf-8");
|
|
||||||
const key = path.basename(f, ".svg");
|
|
||||||
return { content, key };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return absolute paths array of SVG files data located inside '@svgDir/static'
|
|
||||||
*/
|
|
||||||
public getStatic(): Svg[] {
|
|
||||||
const staticDir = path.resolve(this.svgDir, "static");
|
|
||||||
|
|
||||||
if (!fs.existsSync(staticDir)) {
|
|
||||||
console.log(`${this.svgDir} contains semi-animated .svg files`);
|
|
||||||
this.semiAnimated = true;
|
|
||||||
return [];
|
|
||||||
} else {
|
|
||||||
const svgs = fs
|
|
||||||
.readdirSync(staticDir)
|
|
||||||
.map((f) => this.readData(path.resolve(staticDir, f)));
|
|
||||||
|
|
||||||
if (svgs.length == 0) {
|
|
||||||
throw new Error("Static Cursors directory is empty");
|
|
||||||
}
|
|
||||||
return svgs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Return absolute paths array of SVG files data located inside '@svgDir/animated'
|
|
||||||
*/
|
|
||||||
public getAnimated(): Svg[] {
|
|
||||||
const animatedDir = path.resolve(this.svgDir, "animated");
|
|
||||||
|
|
||||||
if (!fs.existsSync(animatedDir)) {
|
|
||||||
throw new Error("Animated Cursors directory not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
const svgs = fs
|
|
||||||
.readdirSync(animatedDir)
|
|
||||||
.map((f) => this.readData(path.resolve(animatedDir, f)));
|
|
||||||
|
|
||||||
if (svgs.length == 0 && this.semiAnimated) {
|
|
||||||
throw new Error(
|
|
||||||
`Can't parse svg directory ${this.svgDir} as semi-animated theme`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return svgs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { SvgDirectoryParser };
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
import { Colors } from "../types";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default Key Colors for generating colored svg.
|
|
||||||
* base="#00FF00" (Green)
|
|
||||||
* outline="#0000FF" (Blue)
|
|
||||||
* watch.background="#FF0000" (Red)
|
|
||||||
* */
|
|
||||||
const defaultKeyColors: Colors = {
|
|
||||||
base: "#00FF00",
|
|
||||||
outline: "#0000FF",
|
|
||||||
watch: {
|
|
||||||
background: "#FF0000",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Customize colors of svg code.
|
|
||||||
* @param {string} content SVG code.
|
|
||||||
* @param {Colors} colors Customize colors.
|
|
||||||
* @param {Colors} [keys] Colors Key, That was written SVG code.
|
|
||||||
* @returns {string} SVG code with colors.
|
|
||||||
*/
|
|
||||||
const colorSvg = (
|
|
||||||
content: string,
|
|
||||||
colors: Colors,
|
|
||||||
keys: Colors = defaultKeyColors
|
|
||||||
): string => {
|
|
||||||
content = content
|
|
||||||
.replace(new RegExp(keys.base, "ig"), colors.base)
|
|
||||||
.replace(new RegExp(keys.outline, "ig"), colors.outline);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// === trying to replace `watch` color ===
|
|
||||||
|
|
||||||
if (!colors.watch?.background) {
|
|
||||||
throw new Error("");
|
|
||||||
}
|
|
||||||
const { background: b } = colors.watch;
|
|
||||||
content = content.replace(new RegExp(keys.watch!.background, "ig"), b); // Watch Background
|
|
||||||
} catch (error) {
|
|
||||||
// === on error => replace `watch` color as `base` ===
|
|
||||||
|
|
||||||
content = content.replace(
|
|
||||||
new RegExp(keys.watch!.background, "ig"),
|
|
||||||
colors.base
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return content;
|
|
||||||
};
|
|
||||||
|
|
||||||
export { colorSvg };
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import { colorSvg } from "./colorSvg";
|
|
||||||
import { SvgDirectoryParser } from "./SvgDirectoryParser";
|
|
||||||
|
|
||||||
export { colorSvg, SvgDirectoryParser };
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import { BitmapsGenerator } from "./BitmapsGenerator";
|
|
||||||
import * as SVGHandler from "./SVGHandler";
|
|
||||||
|
|
||||||
export { BitmapsGenerator, SVGHandler };
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
/**
|
|
||||||
* Hex Colors in string Format.
|
|
||||||
*
|
|
||||||
* `Example: `"#FFFFFF"
|
|
||||||
*/
|
|
||||||
type HexColor = string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Colors expect `base`, `outline` & `watch-background` colors in **HexColor** Format.
|
|
||||||
* @default background is `base` color.
|
|
||||||
*/
|
|
||||||
type Colors = {
|
|
||||||
base: HexColor;
|
|
||||||
outline: HexColor;
|
|
||||||
watch?: {
|
|
||||||
background: HexColor;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Colors };
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
export const frameNumber = (index: number, padding: number) => {
|
|
||||||
let result = "" + index;
|
|
||||||
while (result.length < padding) {
|
|
||||||
result = "0" + result;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
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,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
export const template = `
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Render Template</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="container">
|
|
||||||
<svginjection>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const toHTML = (svgData: string): string =>
|
|
||||||
template.replace("<svginjection>", svgData);
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import path from "path";
|
|
||||||
|
|
||||||
import { BitmapsGenerator, SVGHandler } from "./core";
|
|
||||||
import { config } from "./config";
|
|
||||||
|
|
||||||
const root = path.resolve(__dirname, "../../");
|
|
||||||
const svgDir = path.resolve(root, "svg");
|
|
||||||
|
|
||||||
const main = async () => {
|
|
||||||
for (const { themeName, color } of config) {
|
|
||||||
console.log("Generating bitmaps for", themeName);
|
|
||||||
|
|
||||||
const bitmapsDir = path.resolve(root, "bitmaps", themeName);
|
|
||||||
const svg = new SVGHandler.SvgDirectoryParser(svgDir);
|
|
||||||
|
|
||||||
const png = new BitmapsGenerator(bitmapsDir);
|
|
||||||
const browser = await png.getBrowser();
|
|
||||||
|
|
||||||
for (let { key, content } of svg.getStatic()) {
|
|
||||||
console.log(" ==> Saving", key, "...");
|
|
||||||
|
|
||||||
content = SVGHandler.colorSvg(content, color);
|
|
||||||
await png.generateStatic(browser, content, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let { key, content } of svg.getAnimated()) {
|
|
||||||
console.log(" ==> Saving", key, "...");
|
|
||||||
|
|
||||||
content = SVGHandler.colorSvg(content, color);
|
|
||||||
await png.generateAnimated(browser, content, key, { playbackRate: 0.3 });
|
|
||||||
}
|
|
||||||
|
|
||||||
await browser.close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
main();
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"strict": true,
|
|
||||||
"noUnusedLocals": true,
|
|
||||||
"strictNullChecks": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"target": "ES2015",
|
|
||||||
"module": "commonjs",
|
|
||||||
"lib": ["es2015", "dom"],
|
|
||||||
"noUnusedParameters": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |