Skip to content

Commit

Permalink
Merge pull request #3 from ful1e5/dev
Browse files Browse the repository at this point in the history
🚀 XCursor-Pro v1.1.1
  • Loading branch information
ful1e5 authored Mar 27, 2021
2 parents 0e38cd4 + 71ab69f commit 4c44837
Show file tree
Hide file tree
Showing 16 changed files with 394 additions and 361 deletions.
19 changes: 18 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [unreleased]

## [v1.1.1]- 27 Mar 2021

### Added

- **2 Space** format in `bitmapper`
- clickgen typing inside `xbpkg/generator.py`
- Use `sphinx` docsstring style inside `xbpkg`
- Linting error fixed inside `builder/xbpkg`
- clean builder cache on every make commands

### Changed

- Remove python3 **virtualenv** form `builder/Makefile`
- Compact XCursor-Pro build commands inside `builder/Makefile`

## [v1.1.0]- 15 Mar 2021

### Added
Expand All @@ -32,6 +47,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Logo and badges
- CI/CD Pipelines

[unreleased]: https://github.com/ful1e5/XCursor-pro/compare/v1.1.0...main
[unreleased]: https://github.com/ful1e5/XCursor-pro/compare/v1.1.1...main
[v1.1.1]: https://github.com/ful1e5/XCursor-pro/compare/v1.1.0...v1.1.1
[v1.1.0]: https://github.com/ful1e5/XCursor-pro/compare/v1.0.0...v1.1.0
[v1.0.0]: https://github.com/ful1e5/XCursor-pro/tree/v1.0.0
[v1.0.0]: https://github.com/ful1e5/XCursor-pro/tree/v1.0.0
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
all: clean render build

unix: clean render bitmaps
@cd builder && make build_unix
@cd builder && make build_unix clean

windows: clean render bitmaps
@cd builder && make build_windows
@cd builder && make build_windows clean

.PHONY: all

Expand All @@ -15,7 +15,7 @@ render: bitmapper svg
@cd bitmapper && $(MAKE)

build: bitmaps
@cd builder && $(MAKE)
@cd builder && make setup build clean

.ONESHELL:
SHELL:=/bin/bash
Expand Down
2 changes: 1 addition & 1 deletion bitmapper/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "xcursor-pro-bitmapper",
"version": "1.1.0",
"version": "1.1.1",
"main": "index.js",
"scripts": {
"watch": "nodemon --inspect src/index.ts",
Expand Down
32 changes: 16 additions & 16 deletions bitmapper/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import { Colors } from "./core/types";

interface Config {
themeName: string;
color: Colors;
themeName: string;
color: Colors;
}

const black = "#000000";
const white = "#FFFFFF";

const config: Config[] = [
{
themeName: "XCursor-Pro-Dark",
color: {
base: black,
outline: white,
},
},
{
themeName: "XCursor-Pro-Light",
color: {
base: white,
outline: black,
},
},
{
themeName: "XCursor-Pro-Dark",
color: {
base: black,
outline: white,
},
},
{
themeName: "XCursor-Pro-Light",
color: {
base: white,
outline: black,
},
},
];

export { config };
286 changes: 143 additions & 143 deletions bitmapper/src/core/BitmapsGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,148 +8,148 @@ 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();
}
/**
* 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 };
Loading

0 comments on commit 4c44837

Please sign in to comment.