@bcts/lifehash-cli 1.0.0-alpha.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +48 -0
- package/README.md +109 -0
- package/dist/index.cjs +317 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +191 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +191 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +308 -0
- package/dist/index.mjs.map +1 -0
- package/dist/main.mjs +209 -0
- package/dist/main.mjs.map +1 -0
- package/package.json +92 -0
- package/src/index.ts +104 -0
- package/src/main.ts +150 -0
- package/src/png-writer.ts +101 -0
- package/src/utils.ts +75 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PNG writer for LifeHash images.
|
|
3
|
+
*
|
|
4
|
+
* Ported from bc-lifehash-cli C++ implementation (png-writer.hpp).
|
|
5
|
+
* Uses pngjs instead of libpng.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { writeFileSync } from "fs";
|
|
11
|
+
import { PNG } from "pngjs";
|
|
12
|
+
import type { Image } from "@bcts/lifehash";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Writes a LifeHash image to a PNG file.
|
|
16
|
+
*
|
|
17
|
+
* Port of `write_image()` from lifehash.cpp lines 174-186 and
|
|
18
|
+
* PNGWriter class from png-writer.hpp.
|
|
19
|
+
*
|
|
20
|
+
* @param image - The LifeHash image to write
|
|
21
|
+
* @param filename - The output filename
|
|
22
|
+
* @category PNG Encoding
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import { makeFromUtf8 } from "@bcts/lifehash";
|
|
27
|
+
*
|
|
28
|
+
* const image = makeFromUtf8("Hello");
|
|
29
|
+
* writeImage(image, "Hello.png");
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function writeImage(image: Image, filename: string): void {
|
|
33
|
+
const png = new PNG({
|
|
34
|
+
width: image.width,
|
|
35
|
+
height: image.height,
|
|
36
|
+
colorType: 2, // RGB
|
|
37
|
+
bitDepth: 8,
|
|
38
|
+
inputColorType: 2,
|
|
39
|
+
inputHasAlpha: false,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Copy RGB data from image to PNG
|
|
43
|
+
// PNG expects RGBA, so we need to add alpha channel
|
|
44
|
+
for (let y = 0; y < image.height; y++) {
|
|
45
|
+
for (let x = 0; x < image.width; x++) {
|
|
46
|
+
const srcOffset = (y * image.width + x) * 3;
|
|
47
|
+
const dstOffset = (y * image.width + x) * 4;
|
|
48
|
+
|
|
49
|
+
// Copy RGB from source
|
|
50
|
+
png.data[dstOffset] = image.colors[srcOffset]; // R
|
|
51
|
+
png.data[dstOffset + 1] = image.colors[srcOffset + 1]; // G
|
|
52
|
+
png.data[dstOffset + 2] = image.colors[srcOffset + 2]; // B
|
|
53
|
+
png.data[dstOffset + 3] = 255; // A (fully opaque)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Write to file
|
|
58
|
+
const buffer = PNG.sync.write(png);
|
|
59
|
+
writeFileSync(filename, buffer);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Generates a PNG buffer from a LifeHash image without writing to disk.
|
|
64
|
+
*
|
|
65
|
+
* @param image - The LifeHash image to encode
|
|
66
|
+
* @returns A Buffer containing the PNG data
|
|
67
|
+
* @category PNG Encoding
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* import { makeFromUtf8 } from "@bcts/lifehash";
|
|
72
|
+
*
|
|
73
|
+
* const image = makeFromUtf8("Hello");
|
|
74
|
+
* const pngBuffer = generatePNG(image);
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export function generatePNG(image: Image): Buffer {
|
|
78
|
+
const png = new PNG({
|
|
79
|
+
width: image.width,
|
|
80
|
+
height: image.height,
|
|
81
|
+
colorType: 2,
|
|
82
|
+
bitDepth: 8,
|
|
83
|
+
inputColorType: 2,
|
|
84
|
+
inputHasAlpha: false,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Copy RGB data from image to PNG
|
|
88
|
+
for (let y = 0; y < image.height; y++) {
|
|
89
|
+
for (let x = 0; x < image.width; x++) {
|
|
90
|
+
const srcOffset = (y * image.width + x) * 3;
|
|
91
|
+
const dstOffset = (y * image.width + x) * 4;
|
|
92
|
+
|
|
93
|
+
png.data[dstOffset] = image.colors[srcOffset];
|
|
94
|
+
png.data[dstOffset + 1] = image.colors[srcOffset + 1];
|
|
95
|
+
png.data[dstOffset + 2] = image.colors[srcOffset + 2];
|
|
96
|
+
png.data[dstOffset + 3] = 255;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return PNG.sync.write(png);
|
|
101
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for the LifeHash CLI.
|
|
3
|
+
*
|
|
4
|
+
* Ported from bc-lifehash-cli C++ implementation.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Appends a path component to a path, handling trailing slashes correctly.
|
|
11
|
+
*
|
|
12
|
+
* Port of `appending_path_component()` from lifehash.cpp lines 18-24.
|
|
13
|
+
*
|
|
14
|
+
* @param path - The base path
|
|
15
|
+
* @param component - The component to append
|
|
16
|
+
* @returns The combined path
|
|
17
|
+
* @category Utilities
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* appendingPathComponent("", "file.png") // => "file.png"
|
|
22
|
+
* appendingPathComponent("/tmp/", "file.png") // => "/tmp/file.png"
|
|
23
|
+
* appendingPathComponent("/tmp", "file.png") // => "/tmp/file.png"
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function appendingPathComponent(path: string, component: string): string {
|
|
27
|
+
if (path === "") {
|
|
28
|
+
return component;
|
|
29
|
+
}
|
|
30
|
+
if (path.endsWith("/")) {
|
|
31
|
+
return `${path}${component}`;
|
|
32
|
+
}
|
|
33
|
+
return `${path}/${component}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Selects a random element from an array.
|
|
38
|
+
*
|
|
39
|
+
* Port of `random_element()` template from lifehash.cpp lines 38-50.
|
|
40
|
+
*
|
|
41
|
+
* @param array - The array to select from
|
|
42
|
+
* @returns A random element from the array
|
|
43
|
+
* @category Utilities
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* randomElement(["A", "B", "C"]) // => "A" or "B" or "C"
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function randomElement<T>(array: T[]): T {
|
|
51
|
+
const index = Math.floor(Math.random() * array.length);
|
|
52
|
+
return array[index];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Generates a random input string in "XXX-XXX" format where X is a random uppercase letter.
|
|
57
|
+
*
|
|
58
|
+
* Port of `make_random_input()` from lifehash.cpp lines 52-57.
|
|
59
|
+
*
|
|
60
|
+
* @returns A random string in "XXX-XXX" format
|
|
61
|
+
* @category Utilities
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* makeRandomInput() // => "ABC-DEF" (random letters)
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export function makeRandomInput(): string {
|
|
69
|
+
const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
|
|
70
|
+
|
|
71
|
+
const letter = (): string => randomElement(letters);
|
|
72
|
+
const cluster = (): string => `${letter()}${letter()}${letter()}`;
|
|
73
|
+
|
|
74
|
+
return `${cluster()}-${cluster()}`;
|
|
75
|
+
}
|