@spark-apps/piclet 1.0.4 → 1.0.6
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/dist/cli.js +327 -314
- package/dist/cli.js.map +1 -1
- package/dist/gui/css/theme.css +18 -10
- package/dist/gui/piclet.html +73 -50
- package/package.json +1 -1
- package/dist/gui/border.html +0 -229
- package/dist/gui/extract-frames.html +0 -156
- package/dist/gui/filter.html +0 -180
- package/dist/gui/iconpack.html +0 -113
- package/dist/gui/makeicon.html +0 -165
- package/dist/gui/recolor.html +0 -243
- package/dist/gui/remove-bg.html +0 -178
- package/dist/gui/rescale.html +0 -195
- package/dist/gui/storepack.html +0 -179
- package/dist/gui/transform.html +0 -202
package/dist/cli.js
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
-
}) : x)(function(x) {
|
|
5
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
-
});
|
|
8
2
|
|
|
9
3
|
// src/cli.ts
|
|
10
|
-
import
|
|
4
|
+
import chalk18 from "chalk";
|
|
11
5
|
|
|
12
6
|
// src/cli/index.ts
|
|
13
|
-
import
|
|
7
|
+
import chalk17 from "chalk";
|
|
14
8
|
import { Command } from "commander";
|
|
15
9
|
|
|
16
10
|
// src/lib/banner.ts
|
|
11
|
+
import chalk from "chalk";
|
|
17
12
|
import figlet from "figlet";
|
|
18
13
|
import gradient from "gradient-string";
|
|
19
14
|
var GRADIENT_COLORS = ["#22c55e", "#84cc16", "#eab308", "#fcd34d"];
|
|
@@ -24,36 +19,37 @@ function renderLogo() {
|
|
|
24
19
|
});
|
|
25
20
|
return gradient(GRADIENT_COLORS)(ascii);
|
|
26
21
|
}
|
|
22
|
+
var SUBTITLE_COLOR = "#eab308";
|
|
27
23
|
function showBanner(subtitle = "Image manipulation utility toolkit with Windows shell integration") {
|
|
28
24
|
try {
|
|
29
25
|
console.log(`
|
|
30
26
|
${renderLogo()}`);
|
|
31
27
|
if (subtitle) {
|
|
32
|
-
|
|
33
|
-
console.log(subtleGradient(` ${subtitle}
|
|
28
|
+
console.log(chalk.hex(SUBTITLE_COLOR)(`${subtitle}
|
|
34
29
|
`));
|
|
35
30
|
}
|
|
36
31
|
} catch {
|
|
37
32
|
console.log("\n\x1B[1mPicLet\x1B[0m");
|
|
38
33
|
if (subtitle) {
|
|
39
|
-
console.log(`\x1B[
|
|
34
|
+
console.log(`\x1B[38;2;234;179;8m${subtitle}\x1B[0m
|
|
40
35
|
`);
|
|
41
36
|
}
|
|
42
37
|
}
|
|
43
38
|
}
|
|
44
39
|
|
|
45
40
|
// src/cli/commands/border.ts
|
|
46
|
-
import
|
|
41
|
+
import chalk3 from "chalk";
|
|
47
42
|
|
|
48
43
|
// src/tools/border.ts
|
|
49
|
-
import { existsSync as
|
|
44
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
50
45
|
import { tmpdir } from "os";
|
|
51
|
-
import { basename as basename2, join as
|
|
46
|
+
import { basename as basename2, join as join4 } from "path";
|
|
52
47
|
|
|
53
48
|
// src/lib/gui-server.ts
|
|
54
49
|
import { spawn } from "child_process";
|
|
50
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
55
51
|
import { createServer } from "http";
|
|
56
|
-
import { dirname as dirname2, join as join2 } from "path";
|
|
52
|
+
import { dirname as dirname2, extname, join as join2 } from "path";
|
|
57
53
|
import { fileURLToPath } from "url";
|
|
58
54
|
import express from "express";
|
|
59
55
|
|
|
@@ -506,14 +502,12 @@ function startGuiServer(options) {
|
|
|
506
502
|
return;
|
|
507
503
|
}
|
|
508
504
|
try {
|
|
509
|
-
|
|
510
|
-
const path = __require("path");
|
|
511
|
-
if (!fs.existsSync(outputPath)) {
|
|
505
|
+
if (!existsSync2(outputPath)) {
|
|
512
506
|
res.json({ success: false, error: "Output file not found" });
|
|
513
507
|
return;
|
|
514
508
|
}
|
|
515
|
-
const buffer =
|
|
516
|
-
const ext =
|
|
509
|
+
const buffer = readFileSync2(outputPath);
|
|
510
|
+
const ext = extname(outputPath).toLowerCase();
|
|
517
511
|
const mimeTypes = {
|
|
518
512
|
".png": "image/png",
|
|
519
513
|
".jpg": "image/jpeg",
|
|
@@ -632,7 +626,7 @@ function clearLine() {
|
|
|
632
626
|
|
|
633
627
|
// src/lib/magick.ts
|
|
634
628
|
import { exec } from "child_process";
|
|
635
|
-
import { copyFileSync, existsSync as
|
|
629
|
+
import { copyFileSync, existsSync as existsSync3, mkdirSync as mkdirSync2, unlinkSync } from "fs";
|
|
636
630
|
import { dirname as dirname3 } from "path";
|
|
637
631
|
import { promisify } from "util";
|
|
638
632
|
var execAsync = promisify(exec);
|
|
@@ -822,14 +816,14 @@ async function createIcoFromMultiple(pngPaths, outputPath) {
|
|
|
822
816
|
}
|
|
823
817
|
function ensureDir(filePath) {
|
|
824
818
|
const dir = dirname3(filePath);
|
|
825
|
-
if (!
|
|
819
|
+
if (!existsSync3(dir)) {
|
|
826
820
|
mkdirSync2(dir, { recursive: true });
|
|
827
821
|
}
|
|
828
822
|
}
|
|
829
823
|
function cleanup(...files) {
|
|
830
824
|
for (const file of files) {
|
|
831
825
|
try {
|
|
832
|
-
if (
|
|
826
|
+
if (existsSync3(file)) {
|
|
833
827
|
unlinkSync(file);
|
|
834
828
|
}
|
|
835
829
|
} catch {
|
|
@@ -1100,7 +1094,8 @@ async function simplifyGif(inputPath, outputPath, skipFactor) {
|
|
|
1100
1094
|
}
|
|
1101
1095
|
|
|
1102
1096
|
// src/lib/paths.ts
|
|
1103
|
-
import {
|
|
1097
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
1098
|
+
import { basename, dirname as dirname4, extname as extname2, join as join3, resolve } from "path";
|
|
1104
1099
|
function windowsToWsl(winPath) {
|
|
1105
1100
|
if (winPath.startsWith("/mnt/")) {
|
|
1106
1101
|
return winPath;
|
|
@@ -1131,7 +1126,7 @@ function normalizePath(inputPath) {
|
|
|
1131
1126
|
function getFileInfo(filePath) {
|
|
1132
1127
|
const dir = dirname4(filePath);
|
|
1133
1128
|
const base = basename(filePath);
|
|
1134
|
-
const ext =
|
|
1129
|
+
const ext = extname2(filePath);
|
|
1135
1130
|
const name = base.slice(0, -ext.length);
|
|
1136
1131
|
return {
|
|
1137
1132
|
dirname: dir,
|
|
@@ -1140,6 +1135,20 @@ function getFileInfo(filePath) {
|
|
|
1140
1135
|
extension: ext
|
|
1141
1136
|
};
|
|
1142
1137
|
}
|
|
1138
|
+
function getOutputDir(inputPath) {
|
|
1139
|
+
const dir = dirname4(inputPath);
|
|
1140
|
+
if (basename(dir) === "PicLet") {
|
|
1141
|
+
return dir;
|
|
1142
|
+
}
|
|
1143
|
+
return join3(dir, "PicLet");
|
|
1144
|
+
}
|
|
1145
|
+
function ensureOutputDir(inputPath) {
|
|
1146
|
+
const outDir = getOutputDir(inputPath);
|
|
1147
|
+
if (!existsSync4(outDir)) {
|
|
1148
|
+
mkdirSync3(outDir, { recursive: true });
|
|
1149
|
+
}
|
|
1150
|
+
return outDir;
|
|
1151
|
+
}
|
|
1143
1152
|
|
|
1144
1153
|
// src/lib/prompts.ts
|
|
1145
1154
|
import prompts from "prompts";
|
|
@@ -1288,7 +1297,7 @@ async function run(inputRaw) {
|
|
|
1288
1297
|
return false;
|
|
1289
1298
|
}
|
|
1290
1299
|
const input = normalizePath(inputRaw);
|
|
1291
|
-
if (!
|
|
1300
|
+
if (!existsSync5(input)) {
|
|
1292
1301
|
error(`File not found: ${input}`);
|
|
1293
1302
|
await pauseOnError();
|
|
1294
1303
|
return false;
|
|
@@ -1307,7 +1316,7 @@ async function run(inputRaw) {
|
|
|
1307
1316
|
}
|
|
1308
1317
|
async function runGUI(inputRaw) {
|
|
1309
1318
|
const input = normalizePath(inputRaw);
|
|
1310
|
-
if (!
|
|
1319
|
+
if (!existsSync5(input)) {
|
|
1311
1320
|
error(`File not found: ${input}`);
|
|
1312
1321
|
return false;
|
|
1313
1322
|
}
|
|
@@ -1375,8 +1384,8 @@ async function runGUI(inputRaw) {
|
|
|
1375
1384
|
async function generatePreview(input, options) {
|
|
1376
1385
|
const tempDir = tmpdir();
|
|
1377
1386
|
const timestamp = Date.now();
|
|
1378
|
-
const tempSource =
|
|
1379
|
-
const tempOutput =
|
|
1387
|
+
const tempSource = join4(tempDir, `piclet-preview-${timestamp}-src.png`);
|
|
1388
|
+
const tempOutput = join4(tempDir, `piclet-preview-${timestamp}.png`);
|
|
1380
1389
|
try {
|
|
1381
1390
|
let previewInput = input;
|
|
1382
1391
|
if (isMultiFrame(input)) {
|
|
@@ -1390,7 +1399,7 @@ async function generatePreview(input, options) {
|
|
|
1390
1399
|
cleanup(tempSource, tempOutput);
|
|
1391
1400
|
return { success: false, error: "Border failed" };
|
|
1392
1401
|
}
|
|
1393
|
-
const buffer =
|
|
1402
|
+
const buffer = readFileSync3(tempOutput);
|
|
1394
1403
|
const base64 = buffer.toString("base64");
|
|
1395
1404
|
const imageData = `data:image/png;base64,${base64}`;
|
|
1396
1405
|
const dims = await getDimensions(tempOutput);
|
|
@@ -1413,16 +1422,10 @@ var config = {
|
|
|
1413
1422
|
extensions: [".png", ".jpg", ".jpeg", ".gif", ".bmp"]
|
|
1414
1423
|
};
|
|
1415
1424
|
|
|
1416
|
-
// src/cli/utils.ts
|
|
1417
|
-
import { extname as extname3 } from "path";
|
|
1418
|
-
import { dirname as dirname9 } from "path";
|
|
1419
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1420
|
-
import chalk from "chalk";
|
|
1421
|
-
|
|
1422
1425
|
// src/tools/extract-frames.ts
|
|
1423
|
-
import { existsSync as
|
|
1426
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync4 } from "fs";
|
|
1424
1427
|
import { tmpdir as tmpdir2 } from "os";
|
|
1425
|
-
import { basename as basename3, join as
|
|
1428
|
+
import { basename as basename3, join as join5 } from "path";
|
|
1426
1429
|
async function run2(inputRaw) {
|
|
1427
1430
|
if (!await checkImageMagick()) {
|
|
1428
1431
|
error("ImageMagick not found. Please install it:");
|
|
@@ -1431,7 +1434,7 @@ async function run2(inputRaw) {
|
|
|
1431
1434
|
return false;
|
|
1432
1435
|
}
|
|
1433
1436
|
const input = normalizePath(inputRaw);
|
|
1434
|
-
if (!
|
|
1437
|
+
if (!existsSync6(input)) {
|
|
1435
1438
|
error(`File not found: ${input}`);
|
|
1436
1439
|
await pauseOnError();
|
|
1437
1440
|
return false;
|
|
@@ -1462,7 +1465,7 @@ async function run2(inputRaw) {
|
|
|
1462
1465
|
const outputDir = `${fileInfo.dirname}/${fileInfo.filename}_frames`;
|
|
1463
1466
|
console.log("");
|
|
1464
1467
|
wip("Extracting frames...");
|
|
1465
|
-
|
|
1468
|
+
mkdirSync4(outputDir, { recursive: true });
|
|
1466
1469
|
const frames = await extractAllFrames(input, outputDir, "frame");
|
|
1467
1470
|
if (frames.length === 0) {
|
|
1468
1471
|
wipDone(false, "Extraction failed");
|
|
@@ -1475,7 +1478,7 @@ async function run2(inputRaw) {
|
|
|
1475
1478
|
}
|
|
1476
1479
|
async function runGUI2(inputRaw) {
|
|
1477
1480
|
const input = normalizePath(inputRaw);
|
|
1478
|
-
if (!
|
|
1481
|
+
if (!existsSync6(input)) {
|
|
1479
1482
|
error(`File not found: ${input}`);
|
|
1480
1483
|
return false;
|
|
1481
1484
|
}
|
|
@@ -1514,7 +1517,7 @@ async function runGUI2(inputRaw) {
|
|
|
1514
1517
|
}
|
|
1515
1518
|
logs.push({ type: "info", message: `Extracting ${frameCount} frames...` });
|
|
1516
1519
|
const outputDir = `${fileInfo.dirname}/${fileInfo.filename}_frames`;
|
|
1517
|
-
|
|
1520
|
+
mkdirSync4(outputDir, { recursive: true });
|
|
1518
1521
|
const frames = await extractAllFrames(input, outputDir, "frame");
|
|
1519
1522
|
if (frames.length > 0) {
|
|
1520
1523
|
logs.push({ type: "success", message: `Extracted ${frames.length} frames` });
|
|
@@ -1532,12 +1535,12 @@ async function runGUI2(inputRaw) {
|
|
|
1532
1535
|
async function generateFramePreview(input, frameIndex) {
|
|
1533
1536
|
const tempDir = tmpdir2();
|
|
1534
1537
|
const timestamp = Date.now();
|
|
1535
|
-
const tempOutput =
|
|
1538
|
+
const tempOutput = join5(tempDir, `piclet-frame-${timestamp}.png`);
|
|
1536
1539
|
try {
|
|
1537
1540
|
if (!await extractFirstFrame(input, tempOutput, frameIndex)) {
|
|
1538
1541
|
return { success: false, error: "Failed to extract frame" };
|
|
1539
1542
|
}
|
|
1540
|
-
const buffer =
|
|
1543
|
+
const buffer = readFileSync4(tempOutput);
|
|
1541
1544
|
const base64 = buffer.toString("base64");
|
|
1542
1545
|
const imageData = `data:image/png;base64,${base64}`;
|
|
1543
1546
|
const dims = await getDimensions(tempOutput);
|
|
@@ -1561,9 +1564,9 @@ var config2 = {
|
|
|
1561
1564
|
};
|
|
1562
1565
|
|
|
1563
1566
|
// src/tools/filter.ts
|
|
1564
|
-
import { existsSync as
|
|
1567
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
|
|
1565
1568
|
import { tmpdir as tmpdir3 } from "os";
|
|
1566
|
-
import { basename as basename4, join as
|
|
1569
|
+
import { basename as basename4, join as join6 } from "path";
|
|
1567
1570
|
var FILTER_LABELS = {
|
|
1568
1571
|
"grayscale": "Grayscale",
|
|
1569
1572
|
"sepia": "Sepia",
|
|
@@ -1637,7 +1640,7 @@ async function run3(inputRaw) {
|
|
|
1637
1640
|
return false;
|
|
1638
1641
|
}
|
|
1639
1642
|
const input = normalizePath(inputRaw);
|
|
1640
|
-
if (!
|
|
1643
|
+
if (!existsSync7(input)) {
|
|
1641
1644
|
error(`File not found: ${input}`);
|
|
1642
1645
|
await pauseOnError();
|
|
1643
1646
|
return false;
|
|
@@ -1656,7 +1659,7 @@ async function run3(inputRaw) {
|
|
|
1656
1659
|
}
|
|
1657
1660
|
async function runGUI3(inputRaw) {
|
|
1658
1661
|
const input = normalizePath(inputRaw);
|
|
1659
|
-
if (!
|
|
1662
|
+
if (!existsSync7(input)) {
|
|
1660
1663
|
error(`File not found: ${input}`);
|
|
1661
1664
|
return false;
|
|
1662
1665
|
}
|
|
@@ -1721,8 +1724,8 @@ async function runGUI3(inputRaw) {
|
|
|
1721
1724
|
async function generatePreview2(input, options) {
|
|
1722
1725
|
const tempDir = tmpdir3();
|
|
1723
1726
|
const timestamp = Date.now();
|
|
1724
|
-
const tempSource =
|
|
1725
|
-
const tempOutput =
|
|
1727
|
+
const tempSource = join6(tempDir, `piclet-preview-${timestamp}-src.png`);
|
|
1728
|
+
const tempOutput = join6(tempDir, `piclet-preview-${timestamp}.png`);
|
|
1726
1729
|
try {
|
|
1727
1730
|
let previewInput = input;
|
|
1728
1731
|
if (isMultiFrame(input)) {
|
|
@@ -1736,7 +1739,7 @@ async function generatePreview2(input, options) {
|
|
|
1736
1739
|
cleanup(tempSource, tempOutput);
|
|
1737
1740
|
return { success: false, error: "Filter failed" };
|
|
1738
1741
|
}
|
|
1739
|
-
const buffer =
|
|
1742
|
+
const buffer = readFileSync5(tempOutput);
|
|
1740
1743
|
const base64 = buffer.toString("base64");
|
|
1741
1744
|
const imageData = `data:image/png;base64,${base64}`;
|
|
1742
1745
|
const dims = await getDimensions(tempOutput);
|
|
@@ -1760,7 +1763,7 @@ var config3 = {
|
|
|
1760
1763
|
};
|
|
1761
1764
|
|
|
1762
1765
|
// src/tools/iconpack.ts
|
|
1763
|
-
import { existsSync as
|
|
1766
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync5 } from "fs";
|
|
1764
1767
|
import { basename as basename5, dirname as dirname5 } from "path";
|
|
1765
1768
|
var WEB_ICONS = [
|
|
1766
1769
|
{ filename: "favicon-16x16.png", size: 16 },
|
|
@@ -1811,8 +1814,8 @@ async function generateIcons(outputDir, sourceImg, icons) {
|
|
|
1811
1814
|
current++;
|
|
1812
1815
|
const outputPath = `${outputDir}/${icon.filename}`;
|
|
1813
1816
|
const subdir = dirname5(outputPath);
|
|
1814
|
-
if (!
|
|
1815
|
-
|
|
1817
|
+
if (!existsSync8(subdir)) {
|
|
1818
|
+
mkdirSync5(subdir, { recursive: true });
|
|
1816
1819
|
}
|
|
1817
1820
|
clearLine();
|
|
1818
1821
|
wip(`[${current}/${total}] Generating ${icon.filename}...`);
|
|
@@ -1857,7 +1860,7 @@ async function run4(inputRaw) {
|
|
|
1857
1860
|
return false;
|
|
1858
1861
|
}
|
|
1859
1862
|
const input = normalizePath(inputRaw);
|
|
1860
|
-
if (!
|
|
1863
|
+
if (!existsSync8(input)) {
|
|
1861
1864
|
error(`File not found: ${input}`);
|
|
1862
1865
|
await pauseOnError();
|
|
1863
1866
|
return false;
|
|
@@ -1899,7 +1902,7 @@ async function run4(inputRaw) {
|
|
|
1899
1902
|
const doAndroid = platforms.includes("android");
|
|
1900
1903
|
const doIos = platforms.includes("ios");
|
|
1901
1904
|
const outputDir = `${fileInfo.dirname}/${fileInfo.filename}_icons`;
|
|
1902
|
-
|
|
1905
|
+
mkdirSync5(outputDir, { recursive: true });
|
|
1903
1906
|
info(`Output directory: ${outputDir}`);
|
|
1904
1907
|
console.log("");
|
|
1905
1908
|
wip("Preparing source image...");
|
|
@@ -1921,7 +1924,7 @@ async function run4(inputRaw) {
|
|
|
1921
1924
|
console.log("");
|
|
1922
1925
|
header("Web Icons");
|
|
1923
1926
|
const webDir = `${outputDir}/web`;
|
|
1924
|
-
|
|
1927
|
+
mkdirSync5(webDir, { recursive: true });
|
|
1925
1928
|
if (!await generateFavicon(webDir, tempSource)) {
|
|
1926
1929
|
totalFailed++;
|
|
1927
1930
|
}
|
|
@@ -1931,14 +1934,14 @@ async function run4(inputRaw) {
|
|
|
1931
1934
|
console.log("");
|
|
1932
1935
|
header("Android Icons");
|
|
1933
1936
|
const androidDir = `${outputDir}/android`;
|
|
1934
|
-
|
|
1937
|
+
mkdirSync5(androidDir, { recursive: true });
|
|
1935
1938
|
totalFailed += await generateIcons(androidDir, tempSource, ANDROID_ICONS);
|
|
1936
1939
|
}
|
|
1937
1940
|
if (doIos) {
|
|
1938
1941
|
console.log("");
|
|
1939
1942
|
header("iOS Icons");
|
|
1940
1943
|
const iosDir = `${outputDir}/ios`;
|
|
1941
|
-
|
|
1944
|
+
mkdirSync5(iosDir, { recursive: true });
|
|
1942
1945
|
totalFailed += await generateIcons(iosDir, tempSource, IOS_ICONS);
|
|
1943
1946
|
}
|
|
1944
1947
|
cleanup(tempSource);
|
|
@@ -1964,7 +1967,7 @@ async function run4(inputRaw) {
|
|
|
1964
1967
|
}
|
|
1965
1968
|
async function runGUI4(inputRaw) {
|
|
1966
1969
|
const input = normalizePath(inputRaw);
|
|
1967
|
-
if (!
|
|
1970
|
+
if (!existsSync8(input)) {
|
|
1968
1971
|
error(`File not found: ${input}`);
|
|
1969
1972
|
return false;
|
|
1970
1973
|
}
|
|
@@ -2009,7 +2012,7 @@ async function runGUI4(inputRaw) {
|
|
|
2009
2012
|
};
|
|
2010
2013
|
}
|
|
2011
2014
|
const outputDir = `${fileInfo.dirname}/${fileInfo.filename}_icons`;
|
|
2012
|
-
|
|
2015
|
+
mkdirSync5(outputDir, { recursive: true });
|
|
2013
2016
|
logs.push({ type: "info", message: `Output: ${outputDir}` });
|
|
2014
2017
|
logs.push({ type: "info", message: "Preparing source image..." });
|
|
2015
2018
|
const tempSource = `${outputDir}/.source_1024.png`;
|
|
@@ -2027,7 +2030,7 @@ async function runGUI4(inputRaw) {
|
|
|
2027
2030
|
if (doWeb) {
|
|
2028
2031
|
logs.push({ type: "info", message: "Generating Web icons..." });
|
|
2029
2032
|
const webDir = `${outputDir}/web`;
|
|
2030
|
-
|
|
2033
|
+
mkdirSync5(webDir, { recursive: true });
|
|
2031
2034
|
if (!await generateFaviconSilent(webDir, tempSource)) {
|
|
2032
2035
|
totalFailed++;
|
|
2033
2036
|
}
|
|
@@ -2037,14 +2040,14 @@ async function runGUI4(inputRaw) {
|
|
|
2037
2040
|
if (doAndroid) {
|
|
2038
2041
|
logs.push({ type: "info", message: "Generating Android icons..." });
|
|
2039
2042
|
const androidDir = `${outputDir}/android`;
|
|
2040
|
-
|
|
2043
|
+
mkdirSync5(androidDir, { recursive: true });
|
|
2041
2044
|
totalFailed += await generateIconsSilent(androidDir, tempSource, ANDROID_ICONS, logs);
|
|
2042
2045
|
logs.push({ type: "success", message: `Android: ${ANDROID_ICONS.length} icons` });
|
|
2043
2046
|
}
|
|
2044
2047
|
if (doIos) {
|
|
2045
2048
|
logs.push({ type: "info", message: "Generating iOS icons..." });
|
|
2046
2049
|
const iosDir = `${outputDir}/ios`;
|
|
2047
|
-
|
|
2050
|
+
mkdirSync5(iosDir, { recursive: true });
|
|
2048
2051
|
totalFailed += await generateIconsSilent(iosDir, tempSource, IOS_ICONS, logs);
|
|
2049
2052
|
logs.push({ type: "success", message: `iOS: ${IOS_ICONS.length} icons` });
|
|
2050
2053
|
}
|
|
@@ -2069,8 +2072,8 @@ async function generateIconsSilent(outputDir, sourceImg, icons, _logs) {
|
|
|
2069
2072
|
for (const icon of icons) {
|
|
2070
2073
|
const outputPath = `${outputDir}/${icon.filename}`;
|
|
2071
2074
|
const subdir = dirname5(outputPath);
|
|
2072
|
-
if (!
|
|
2073
|
-
|
|
2075
|
+
if (!existsSync8(subdir)) {
|
|
2076
|
+
mkdirSync5(subdir, { recursive: true });
|
|
2074
2077
|
}
|
|
2075
2078
|
if (!await scaleToSize(sourceImg, outputPath, icon.size)) {
|
|
2076
2079
|
failed++;
|
|
@@ -2100,9 +2103,9 @@ var config4 = {
|
|
|
2100
2103
|
};
|
|
2101
2104
|
|
|
2102
2105
|
// src/tools/makeicon.ts
|
|
2103
|
-
import { existsSync as
|
|
2106
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
|
|
2104
2107
|
import { tmpdir as tmpdir4 } from "os";
|
|
2105
|
-
import { basename as basename6, join as
|
|
2108
|
+
import { basename as basename6, join as join7 } from "path";
|
|
2106
2109
|
async function run5(inputRaw) {
|
|
2107
2110
|
if (!await checkImageMagick()) {
|
|
2108
2111
|
error("ImageMagick not found. Please install it:");
|
|
@@ -2111,7 +2114,7 @@ async function run5(inputRaw) {
|
|
|
2111
2114
|
return false;
|
|
2112
2115
|
}
|
|
2113
2116
|
const input = normalizePath(inputRaw);
|
|
2114
|
-
if (!
|
|
2117
|
+
if (!existsSync9(input)) {
|
|
2115
2118
|
error(`File not found: ${input}`);
|
|
2116
2119
|
await pauseOnError();
|
|
2117
2120
|
return false;
|
|
@@ -2209,9 +2212,9 @@ async function processForIcon(input, output, options, logs) {
|
|
|
2209
2212
|
async function generatePreview3(input, options) {
|
|
2210
2213
|
const tempDir = tmpdir4();
|
|
2211
2214
|
const timestamp = Date.now();
|
|
2212
|
-
const tempTrimmed =
|
|
2213
|
-
const tempSquare =
|
|
2214
|
-
const tempOutput =
|
|
2215
|
+
const tempTrimmed = join7(tempDir, `piclet-preview-trimmed-${timestamp}.png`);
|
|
2216
|
+
const tempSquare = join7(tempDir, `piclet-preview-square-${timestamp}.png`);
|
|
2217
|
+
const tempOutput = join7(tempDir, `piclet-preview-${timestamp}.png`);
|
|
2215
2218
|
try {
|
|
2216
2219
|
let currentInput = input;
|
|
2217
2220
|
if (options.trim) {
|
|
@@ -2235,7 +2238,7 @@ async function generatePreview3(input, options) {
|
|
|
2235
2238
|
}
|
|
2236
2239
|
if (currentInput === tempSquare) cleanup(tempSquare);
|
|
2237
2240
|
else if (currentInput === tempTrimmed) cleanup(tempTrimmed);
|
|
2238
|
-
const buffer =
|
|
2241
|
+
const buffer = readFileSync6(tempOutput);
|
|
2239
2242
|
const base64 = buffer.toString("base64");
|
|
2240
2243
|
const imageData = `data:image/png;base64,${base64}`;
|
|
2241
2244
|
const dims = await getDimensions(tempOutput);
|
|
@@ -2253,7 +2256,7 @@ async function generatePreview3(input, options) {
|
|
|
2253
2256
|
}
|
|
2254
2257
|
async function runGUI5(inputRaw) {
|
|
2255
2258
|
const input = normalizePath(inputRaw);
|
|
2256
|
-
if (!
|
|
2259
|
+
if (!existsSync9(input)) {
|
|
2257
2260
|
error(`File not found: ${input}`);
|
|
2258
2261
|
return false;
|
|
2259
2262
|
}
|
|
@@ -2318,16 +2321,16 @@ var config5 = {
|
|
|
2318
2321
|
};
|
|
2319
2322
|
|
|
2320
2323
|
// src/tools/piclet-main.ts
|
|
2321
|
-
import { existsSync as
|
|
2324
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync7, renameSync, writeFileSync as writeFileSync2 } from "fs";
|
|
2322
2325
|
import { tmpdir as tmpdir5 } from "os";
|
|
2323
|
-
import { basename as basename7, dirname as dirname6, extname as
|
|
2326
|
+
import { basename as basename7, dirname as dirname6, extname as extname3, join as join8 } from "path";
|
|
2324
2327
|
var TOOL_ORDER = ["removebg", "scale", "icons", "storepack"];
|
|
2325
2328
|
async function generateCombinedPreview(input, borderColor, opts) {
|
|
2326
2329
|
const tempDir = tmpdir5();
|
|
2327
2330
|
const ts = Date.now();
|
|
2328
2331
|
const temps = [];
|
|
2329
2332
|
const makeTempPath = (suffix) => {
|
|
2330
|
-
const p =
|
|
2333
|
+
const p = join8(tempDir, `piclet-${ts}-${suffix}.png`);
|
|
2331
2334
|
temps.push(p);
|
|
2332
2335
|
return p;
|
|
2333
2336
|
};
|
|
@@ -2349,7 +2352,7 @@ async function generateCombinedPreview(input, borderColor, opts) {
|
|
|
2349
2352
|
previewPath2 = scaled;
|
|
2350
2353
|
}
|
|
2351
2354
|
}
|
|
2352
|
-
const buffer2 =
|
|
2355
|
+
const buffer2 = readFileSync7(previewPath2);
|
|
2353
2356
|
const finalDims2 = await getDimensions(previewPath2);
|
|
2354
2357
|
cleanup(...temps);
|
|
2355
2358
|
return {
|
|
@@ -2434,7 +2437,7 @@ async function generateCombinedPreview(input, borderColor, opts) {
|
|
|
2434
2437
|
previewPath = scaled;
|
|
2435
2438
|
}
|
|
2436
2439
|
}
|
|
2437
|
-
const buffer =
|
|
2440
|
+
const buffer = readFileSync7(previewPath);
|
|
2438
2441
|
const finalDims = await getDimensions(previewPath);
|
|
2439
2442
|
cleanup(...temps);
|
|
2440
2443
|
return {
|
|
@@ -2504,7 +2507,8 @@ async function processCombined(input, borderColor, opts, logs) {
|
|
|
2504
2507
|
current = out;
|
|
2505
2508
|
}
|
|
2506
2509
|
if (activeTools.indexOf(tool) === activeTools.length - 1) {
|
|
2507
|
-
const
|
|
2510
|
+
const outDir = ensureOutputDir(input);
|
|
2511
|
+
const finalOut = join8(outDir, `${fileInfo.filename}_nobg${outputExt}`);
|
|
2508
2512
|
renameSync(current, finalOut);
|
|
2509
2513
|
temps.splice(temps.indexOf(current), 1);
|
|
2510
2514
|
outputs.push(basename7(finalOut));
|
|
@@ -2536,7 +2540,8 @@ async function processCombined(input, borderColor, opts, logs) {
|
|
|
2536
2540
|
}
|
|
2537
2541
|
current = out;
|
|
2538
2542
|
if (activeTools.indexOf(tool) === activeTools.length - 1) {
|
|
2539
|
-
const
|
|
2543
|
+
const outDir = ensureOutputDir(input);
|
|
2544
|
+
const finalOut = join8(outDir, `${fileInfo.filename}_scaled${outputExt}`);
|
|
2540
2545
|
renameSync(current, finalOut);
|
|
2541
2546
|
temps.splice(temps.indexOf(current), 1);
|
|
2542
2547
|
outputs.push(basename7(finalOut));
|
|
@@ -2580,7 +2585,8 @@ async function processCombined(input, borderColor, opts, logs) {
|
|
|
2580
2585
|
let totalCount = 0;
|
|
2581
2586
|
if (icOpts.ico) {
|
|
2582
2587
|
logs.push({ type: "info", message: "Creating ICO file..." });
|
|
2583
|
-
const
|
|
2588
|
+
const outDir = ensureOutputDir(input);
|
|
2589
|
+
const icoOut = join8(outDir, `${fileInfo.filename}.ico`);
|
|
2584
2590
|
if (await createIco(srcTemp, icoOut)) {
|
|
2585
2591
|
logs.push({ type: "success", message: "ICO: 6 sizes (256, 128, 64, 48, 32, 16)" });
|
|
2586
2592
|
outputs.push(basename7(icoOut));
|
|
@@ -2591,12 +2597,13 @@ async function processCombined(input, borderColor, opts, logs) {
|
|
|
2591
2597
|
}
|
|
2592
2598
|
const needsPacks = icOpts.web || icOpts.android || icOpts.ios;
|
|
2593
2599
|
if (needsPacks) {
|
|
2594
|
-
const
|
|
2595
|
-
|
|
2600
|
+
const outDir = ensureOutputDir(input);
|
|
2601
|
+
const outputDir = join8(outDir, `${fileInfo.filename}_icons`);
|
|
2602
|
+
mkdirSync6(outputDir, { recursive: true });
|
|
2596
2603
|
if (icOpts.web) {
|
|
2597
2604
|
logs.push({ type: "info", message: "Generating Web icons..." });
|
|
2598
2605
|
const webDir = `${outputDir}/web`;
|
|
2599
|
-
|
|
2606
|
+
mkdirSync6(webDir, { recursive: true });
|
|
2600
2607
|
const t16 = `${webDir}/.t16.png`, t32 = `${webDir}/.t32.png`, t48 = `${webDir}/.t48.png`;
|
|
2601
2608
|
await scaleToSize(srcTemp, t16, 16);
|
|
2602
2609
|
await scaleToSize(srcTemp, t32, 32);
|
|
@@ -2631,7 +2638,7 @@ async function processCombined(input, borderColor, opts, logs) {
|
|
|
2631
2638
|
];
|
|
2632
2639
|
for (const i of androidIcons) {
|
|
2633
2640
|
const p = `${androidDir}/${i.name}`;
|
|
2634
|
-
|
|
2641
|
+
mkdirSync6(dirname6(p), { recursive: true });
|
|
2635
2642
|
await scaleToSize(srcTemp, p, i.size);
|
|
2636
2643
|
totalCount++;
|
|
2637
2644
|
}
|
|
@@ -2640,7 +2647,7 @@ async function processCombined(input, borderColor, opts, logs) {
|
|
|
2640
2647
|
if (icOpts.ios) {
|
|
2641
2648
|
logs.push({ type: "info", message: "Generating iOS icons..." });
|
|
2642
2649
|
const iosDir = `${outputDir}/ios`;
|
|
2643
|
-
|
|
2650
|
+
mkdirSync6(iosDir, { recursive: true });
|
|
2644
2651
|
const iosSizes = [20, 29, 40, 58, 60, 76, 80, 87, 120, 152, 167, 180, 1024];
|
|
2645
2652
|
for (const s of iosSizes) {
|
|
2646
2653
|
await scaleToSize(srcTemp, `${iosDir}/AppIcon-${s}.png`, s);
|
|
@@ -2662,12 +2669,13 @@ async function processCombined(input, borderColor, opts, logs) {
|
|
|
2662
2669
|
return { outputs: [] };
|
|
2663
2670
|
}
|
|
2664
2671
|
const folderName = spOpts.presetName || "assets";
|
|
2665
|
-
const
|
|
2666
|
-
|
|
2672
|
+
const outDir = ensureOutputDir(input);
|
|
2673
|
+
const outputDir = join8(outDir, `${fileInfo.filename}_${folderName}`);
|
|
2674
|
+
mkdirSync6(outputDir, { recursive: true });
|
|
2667
2675
|
let count = 0;
|
|
2668
2676
|
for (const dim of spOpts.dimensions) {
|
|
2669
2677
|
const filename = dim.filename || `${dim.width}x${dim.height}.png`;
|
|
2670
|
-
const out =
|
|
2678
|
+
const out = join8(outputDir, filename);
|
|
2671
2679
|
let success2 = false;
|
|
2672
2680
|
switch (spOpts.scaleMode) {
|
|
2673
2681
|
case "fill":
|
|
@@ -2692,7 +2700,7 @@ async function processCombined(input, borderColor, opts, logs) {
|
|
|
2692
2700
|
}
|
|
2693
2701
|
async function runGUI6(inputRaw) {
|
|
2694
2702
|
let currentInput = normalizePath(inputRaw);
|
|
2695
|
-
if (!
|
|
2703
|
+
if (!existsSync10(currentInput)) {
|
|
2696
2704
|
error(`File not found: ${currentInput}`);
|
|
2697
2705
|
return false;
|
|
2698
2706
|
}
|
|
@@ -2706,14 +2714,14 @@ async function runGUI6(inputRaw) {
|
|
|
2706
2714
|
const presets = loadPresets();
|
|
2707
2715
|
async function generateFrameThumbnail(frameIndex) {
|
|
2708
2716
|
const tempDir = tmpdir5();
|
|
2709
|
-
const tempOutput =
|
|
2717
|
+
const tempOutput = join8(tempDir, `piclet-frame-${Date.now()}-${frameIndex}.png`);
|
|
2710
2718
|
try {
|
|
2711
2719
|
if (!await extractFirstFrame(currentInput, tempOutput, frameIndex)) {
|
|
2712
2720
|
return { success: false, error: "Failed to extract frame" };
|
|
2713
2721
|
}
|
|
2714
|
-
const thumbOutput =
|
|
2722
|
+
const thumbOutput = join8(tempDir, `piclet-thumb-${Date.now()}-${frameIndex}.png`);
|
|
2715
2723
|
await scaleToSize(tempOutput, thumbOutput, 96);
|
|
2716
|
-
const buffer =
|
|
2724
|
+
const buffer = readFileSync7(thumbOutput);
|
|
2717
2725
|
cleanup(tempOutput, thumbOutput);
|
|
2718
2726
|
return {
|
|
2719
2727
|
success: true,
|
|
@@ -2727,7 +2735,7 @@ async function runGUI6(inputRaw) {
|
|
|
2727
2735
|
async function generateFramePreview2(frameIndex, opts) {
|
|
2728
2736
|
const tempDir = tmpdir5();
|
|
2729
2737
|
const ts = Date.now();
|
|
2730
|
-
const frameFile =
|
|
2738
|
+
const frameFile = join8(tempDir, `piclet-fp-${ts}-${frameIndex}.png`);
|
|
2731
2739
|
const temps = [frameFile];
|
|
2732
2740
|
try {
|
|
2733
2741
|
if (!await extractFirstFrame(currentInput, frameFile, frameIndex)) {
|
|
@@ -2736,7 +2744,7 @@ async function runGUI6(inputRaw) {
|
|
|
2736
2744
|
let current = frameFile;
|
|
2737
2745
|
const activeTools = ["removebg", "scale", "icons"].filter((t) => opts.tools.includes(t));
|
|
2738
2746
|
for (const tool of activeTools) {
|
|
2739
|
-
const tempOut =
|
|
2747
|
+
const tempOut = join8(tempDir, `piclet-fp-${ts}-${frameIndex}-${tool}.png`);
|
|
2740
2748
|
temps.push(tempOut);
|
|
2741
2749
|
switch (tool) {
|
|
2742
2750
|
case "removebg": {
|
|
@@ -2750,7 +2758,7 @@ async function runGUI6(inputRaw) {
|
|
|
2750
2758
|
}
|
|
2751
2759
|
if (success2) {
|
|
2752
2760
|
if (rbOpts.trim) {
|
|
2753
|
-
const trimOut =
|
|
2761
|
+
const trimOut = join8(tempDir, `piclet-fp-${ts}-${frameIndex}-trim.png`);
|
|
2754
2762
|
temps.push(trimOut);
|
|
2755
2763
|
if (await trim(tempOut, trimOut)) {
|
|
2756
2764
|
current = trimOut;
|
|
@@ -2780,7 +2788,7 @@ async function runGUI6(inputRaw) {
|
|
|
2780
2788
|
case "icons": {
|
|
2781
2789
|
const icOpts = opts.icons;
|
|
2782
2790
|
if (icOpts.trim) {
|
|
2783
|
-
const trimOut =
|
|
2791
|
+
const trimOut = join8(tempDir, `piclet-fp-${ts}-${frameIndex}-ictrim.png`);
|
|
2784
2792
|
temps.push(trimOut);
|
|
2785
2793
|
if (await trim(current, trimOut)) {
|
|
2786
2794
|
current = trimOut;
|
|
@@ -2795,10 +2803,10 @@ async function runGUI6(inputRaw) {
|
|
|
2795
2803
|
}
|
|
2796
2804
|
}
|
|
2797
2805
|
}
|
|
2798
|
-
const thumbOut =
|
|
2806
|
+
const thumbOut = join8(tempDir, `piclet-fp-${ts}-${frameIndex}-thumb.png`);
|
|
2799
2807
|
temps.push(thumbOut);
|
|
2800
2808
|
await scaleToSize(current, thumbOut, 96);
|
|
2801
|
-
const buffer =
|
|
2809
|
+
const buffer = readFileSync7(thumbOut);
|
|
2802
2810
|
cleanup(...temps);
|
|
2803
2811
|
return {
|
|
2804
2812
|
success: true,
|
|
@@ -2837,7 +2845,7 @@ async function runGUI6(inputRaw) {
|
|
|
2837
2845
|
if (isMultiFrame(currentInput) && typeof toolOpts.frameIndex === "number") {
|
|
2838
2846
|
const tempDir = tmpdir5();
|
|
2839
2847
|
const ts = Date.now();
|
|
2840
|
-
const frameFile =
|
|
2848
|
+
const frameFile = join8(tempDir, `piclet-prev-${ts}.png`);
|
|
2841
2849
|
if (!await extractFirstFrame(currentInput, frameFile, toolOpts.frameIndex)) {
|
|
2842
2850
|
return { success: false, error: "Failed to extract frame" };
|
|
2843
2851
|
}
|
|
@@ -2876,8 +2884,8 @@ async function runGUI6(inputRaw) {
|
|
|
2876
2884
|
},
|
|
2877
2885
|
onLoadImage: async (data) => {
|
|
2878
2886
|
try {
|
|
2879
|
-
const ext =
|
|
2880
|
-
const tempPath =
|
|
2887
|
+
const ext = extname3(data.fileName) || ".png";
|
|
2888
|
+
const tempPath = join8(tmpdir5(), `piclet-load-${Date.now()}${ext}`);
|
|
2881
2889
|
const buffer = Buffer.from(data.data, "base64");
|
|
2882
2890
|
writeFileSync2(tempPath, buffer);
|
|
2883
2891
|
const newDims = await getDimensions(tempPath);
|
|
@@ -2911,7 +2919,7 @@ async function runGUI6(inputRaw) {
|
|
|
2911
2919
|
},
|
|
2912
2920
|
onSimplifyGif: async (skipFactor) => {
|
|
2913
2921
|
try {
|
|
2914
|
-
const tempPath =
|
|
2922
|
+
const tempPath = join8(tmpdir5(), `piclet-simplified-${Date.now()}.gif`);
|
|
2915
2923
|
const result = await simplifyGif(currentInput, tempPath, skipFactor);
|
|
2916
2924
|
if (!result.success) {
|
|
2917
2925
|
return { success: false, error: "Failed to simplify GIF" };
|
|
@@ -2937,7 +2945,7 @@ async function runGUI6(inputRaw) {
|
|
|
2937
2945
|
},
|
|
2938
2946
|
onDeleteFrame: async (frameIndex) => {
|
|
2939
2947
|
try {
|
|
2940
|
-
const tempPath =
|
|
2948
|
+
const tempPath = join8(tmpdir5(), `piclet-edited-${Date.now()}.gif`);
|
|
2941
2949
|
const result = await deleteGifFrame(currentInput, tempPath, frameIndex);
|
|
2942
2950
|
if (!result.success) {
|
|
2943
2951
|
return { success: false, error: "Failed to delete frame" };
|
|
@@ -2952,9 +2960,9 @@ async function runGUI6(inputRaw) {
|
|
|
2952
2960
|
onReplaceFrame: async (frameIndex, imageData) => {
|
|
2953
2961
|
try {
|
|
2954
2962
|
const buffer = Buffer.from(imageData, "base64");
|
|
2955
|
-
const tempImagePath =
|
|
2963
|
+
const tempImagePath = join8(tmpdir5(), `piclet-replace-${Date.now()}.png`);
|
|
2956
2964
|
writeFileSync2(tempImagePath, buffer);
|
|
2957
|
-
const tempPath =
|
|
2965
|
+
const tempPath = join8(tmpdir5(), `piclet-edited-${Date.now()}.gif`);
|
|
2958
2966
|
const result = await replaceGifFrame(currentInput, tempPath, frameIndex, tempImagePath);
|
|
2959
2967
|
cleanup(tempImagePath);
|
|
2960
2968
|
if (!result.success) {
|
|
@@ -2984,7 +2992,7 @@ async function processGifExport(input, borderColor, opts, logs) {
|
|
|
2984
2992
|
case "frame": {
|
|
2985
2993
|
const frameIndex = opts.frameIndex ?? 0;
|
|
2986
2994
|
logs.push({ type: "info", message: `Exporting frame ${frameIndex + 1}...` });
|
|
2987
|
-
const frameFile =
|
|
2995
|
+
const frameFile = join8(tempDir, `piclet-export-${ts}.png`);
|
|
2988
2996
|
if (!await extractFirstFrame(input, frameFile, frameIndex)) {
|
|
2989
2997
|
logs.push({ type: "error", message: "Failed to extract frame" });
|
|
2990
2998
|
return { success: false, error: "Failed to extract frame", logs };
|
|
@@ -2999,7 +3007,8 @@ async function processGifExport(input, borderColor, opts, logs) {
|
|
|
2999
3007
|
return { success: false, error: "Processing failed", logs };
|
|
3000
3008
|
}
|
|
3001
3009
|
}
|
|
3002
|
-
const
|
|
3010
|
+
const frameOutDir = ensureOutputDir(input);
|
|
3011
|
+
const finalOutput = join8(frameOutDir, `${fileInfo.filename}_frame${frameIndex + 1}.png`);
|
|
3003
3012
|
if (outputFile === frameFile) {
|
|
3004
3013
|
renameSync(frameFile, finalOutput);
|
|
3005
3014
|
}
|
|
@@ -3008,8 +3017,9 @@ async function processGifExport(input, borderColor, opts, logs) {
|
|
|
3008
3017
|
}
|
|
3009
3018
|
case "all-frames": {
|
|
3010
3019
|
logs.push({ type: "info", message: "Extracting all frames..." });
|
|
3011
|
-
const
|
|
3012
|
-
|
|
3020
|
+
const framesOutDir = ensureOutputDir(input);
|
|
3021
|
+
const outputDir = join8(framesOutDir, `${fileInfo.filename}_frames`);
|
|
3022
|
+
mkdirSync6(outputDir, { recursive: true });
|
|
3013
3023
|
const frames = await extractAllFrames(input, outputDir, "frame");
|
|
3014
3024
|
if (frames.length === 0) {
|
|
3015
3025
|
logs.push({ type: "error", message: "Failed to extract frames" });
|
|
@@ -3046,9 +3056,9 @@ var config6 = {
|
|
|
3046
3056
|
};
|
|
3047
3057
|
|
|
3048
3058
|
// src/tools/recolor.ts
|
|
3049
|
-
import { existsSync as
|
|
3059
|
+
import { existsSync as existsSync11, readFileSync as readFileSync8 } from "fs";
|
|
3050
3060
|
import { tmpdir as tmpdir6 } from "os";
|
|
3051
|
-
import { basename as basename8, join as
|
|
3061
|
+
import { basename as basename8, join as join9 } from "path";
|
|
3052
3062
|
async function processImage3(input, options) {
|
|
3053
3063
|
const fileInfo = getFileInfo(input);
|
|
3054
3064
|
const outputExt = fileInfo.extension.toLowerCase() === ".gif" ? ".gif" : ".png";
|
|
@@ -3111,7 +3121,7 @@ async function run6(inputRaw) {
|
|
|
3111
3121
|
return false;
|
|
3112
3122
|
}
|
|
3113
3123
|
const input = normalizePath(inputRaw);
|
|
3114
|
-
if (!
|
|
3124
|
+
if (!existsSync11(input)) {
|
|
3115
3125
|
error(`File not found: ${input}`);
|
|
3116
3126
|
await pauseOnError();
|
|
3117
3127
|
return false;
|
|
@@ -3134,7 +3144,7 @@ async function run6(inputRaw) {
|
|
|
3134
3144
|
}
|
|
3135
3145
|
async function runGUI7(inputRaw) {
|
|
3136
3146
|
const input = normalizePath(inputRaw);
|
|
3137
|
-
if (!
|
|
3147
|
+
if (!existsSync11(input)) {
|
|
3138
3148
|
error(`File not found: ${input}`);
|
|
3139
3149
|
return false;
|
|
3140
3150
|
}
|
|
@@ -3206,8 +3216,8 @@ async function runGUI7(inputRaw) {
|
|
|
3206
3216
|
async function generatePreview4(input, options) {
|
|
3207
3217
|
const tempDir = tmpdir6();
|
|
3208
3218
|
const timestamp = Date.now();
|
|
3209
|
-
const tempSource =
|
|
3210
|
-
const tempOutput =
|
|
3219
|
+
const tempSource = join9(tempDir, `piclet-preview-${timestamp}-src.png`);
|
|
3220
|
+
const tempOutput = join9(tempDir, `piclet-preview-${timestamp}.png`);
|
|
3211
3221
|
try {
|
|
3212
3222
|
let previewInput = input;
|
|
3213
3223
|
if (isMultiFrame(input)) {
|
|
@@ -3227,7 +3237,7 @@ async function generatePreview4(input, options) {
|
|
|
3227
3237
|
cleanup(tempSource, tempOutput);
|
|
3228
3238
|
return { success: false, error: "Color replacement failed" };
|
|
3229
3239
|
}
|
|
3230
|
-
const buffer =
|
|
3240
|
+
const buffer = readFileSync8(tempOutput);
|
|
3231
3241
|
const base64 = buffer.toString("base64");
|
|
3232
3242
|
const imageData = `data:image/png;base64,${base64}`;
|
|
3233
3243
|
const dims = await getDimensions(tempOutput);
|
|
@@ -3251,13 +3261,13 @@ var config7 = {
|
|
|
3251
3261
|
};
|
|
3252
3262
|
|
|
3253
3263
|
// src/tools/remove-bg.ts
|
|
3254
|
-
import { existsSync as
|
|
3264
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10, renameSync as renameSync2 } from "fs";
|
|
3255
3265
|
import { tmpdir as tmpdir7 } from "os";
|
|
3256
|
-
import { basename as basename9, join as
|
|
3266
|
+
import { basename as basename9, join as join11 } from "path";
|
|
3257
3267
|
|
|
3258
3268
|
// src/lib/config.ts
|
|
3259
|
-
import { existsSync as
|
|
3260
|
-
import { dirname as dirname7, join as
|
|
3269
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync3 } from "fs";
|
|
3270
|
+
import { dirname as dirname7, join as join10 } from "path";
|
|
3261
3271
|
import { homedir as homedir2 } from "os";
|
|
3262
3272
|
var DEFAULT_CONFIG = {
|
|
3263
3273
|
removeBg: {
|
|
@@ -3275,18 +3285,18 @@ var DEFAULT_CONFIG = {
|
|
|
3275
3285
|
}
|
|
3276
3286
|
};
|
|
3277
3287
|
function getConfigDir() {
|
|
3278
|
-
return
|
|
3288
|
+
return join10(homedir2(), ".config", "piclet");
|
|
3279
3289
|
}
|
|
3280
3290
|
function getConfigPath() {
|
|
3281
|
-
return
|
|
3291
|
+
return join10(getConfigDir(), "config.json");
|
|
3282
3292
|
}
|
|
3283
3293
|
function loadConfig() {
|
|
3284
3294
|
const configPath = getConfigPath();
|
|
3285
|
-
if (!
|
|
3295
|
+
if (!existsSync12(configPath)) {
|
|
3286
3296
|
return { ...DEFAULT_CONFIG };
|
|
3287
3297
|
}
|
|
3288
3298
|
try {
|
|
3289
|
-
const content =
|
|
3299
|
+
const content = readFileSync9(configPath, "utf-8");
|
|
3290
3300
|
const loaded = JSON.parse(content);
|
|
3291
3301
|
return {
|
|
3292
3302
|
removeBg: { ...DEFAULT_CONFIG.removeBg, ...loaded.removeBg },
|
|
@@ -3300,8 +3310,8 @@ function loadConfig() {
|
|
|
3300
3310
|
function resetConfig() {
|
|
3301
3311
|
const configPath = getConfigPath();
|
|
3302
3312
|
const configDir = dirname7(configPath);
|
|
3303
|
-
if (!
|
|
3304
|
-
|
|
3313
|
+
if (!existsSync12(configDir)) {
|
|
3314
|
+
mkdirSync7(configDir, { recursive: true });
|
|
3305
3315
|
}
|
|
3306
3316
|
writeFileSync3(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2));
|
|
3307
3317
|
}
|
|
@@ -3404,7 +3414,7 @@ async function run7(inputRaw) {
|
|
|
3404
3414
|
return false;
|
|
3405
3415
|
}
|
|
3406
3416
|
const input = normalizePath(inputRaw);
|
|
3407
|
-
if (!
|
|
3417
|
+
if (!existsSync13(input)) {
|
|
3408
3418
|
error(`File not found: ${input}`);
|
|
3409
3419
|
await pauseOnError();
|
|
3410
3420
|
return false;
|
|
@@ -3427,7 +3437,7 @@ async function run7(inputRaw) {
|
|
|
3427
3437
|
}
|
|
3428
3438
|
async function runGUI8(inputRaw) {
|
|
3429
3439
|
const input = normalizePath(inputRaw);
|
|
3430
|
-
if (!
|
|
3440
|
+
if (!existsSync13(input)) {
|
|
3431
3441
|
error(`File not found: ${input}`);
|
|
3432
3442
|
return false;
|
|
3433
3443
|
}
|
|
@@ -3465,15 +3475,12 @@ async function runGUI8(inputRaw) {
|
|
|
3465
3475
|
return generatePreview5(input, borderColor, options);
|
|
3466
3476
|
},
|
|
3467
3477
|
onProcess: async (opts) => {
|
|
3468
|
-
const logs = [];
|
|
3469
3478
|
if (!await checkImageMagick()) {
|
|
3470
3479
|
return {
|
|
3471
3480
|
success: false,
|
|
3472
|
-
error: "ImageMagick not found"
|
|
3473
|
-
logs: [{ type: "error", message: "ImageMagick not found. Install with: sudo apt install imagemagick" }]
|
|
3481
|
+
error: "ImageMagick not found"
|
|
3474
3482
|
};
|
|
3475
3483
|
}
|
|
3476
|
-
logs.push({ type: "info", message: `Processing ${basename9(input)}...` });
|
|
3477
3484
|
const options = {
|
|
3478
3485
|
fuzz: opts.fuzz ?? defaults.fuzz,
|
|
3479
3486
|
doTrim: opts.trim ?? defaults.trim,
|
|
@@ -3481,22 +3488,25 @@ async function runGUI8(inputRaw) {
|
|
|
3481
3488
|
makeSquare: opts.makeSquare ?? defaults.makeSquare
|
|
3482
3489
|
};
|
|
3483
3490
|
const fileInfo = getFileInfo(input);
|
|
3484
|
-
const
|
|
3485
|
-
|
|
3491
|
+
const outputExt = fileInfo.extension.toLowerCase() === ".gif" ? ".gif" : ".png";
|
|
3492
|
+
const output = `${fileInfo.dirname}/${fileInfo.filename}_nobg${outputExt}`;
|
|
3493
|
+
const logs = [];
|
|
3486
3494
|
const success2 = await processImageSilent(input, borderColor, options, logs);
|
|
3487
|
-
if (success2) {
|
|
3495
|
+
if (success2 && existsSync13(output)) {
|
|
3488
3496
|
const finalDims = await getDimensions(output);
|
|
3489
3497
|
const sizeStr = finalDims ? ` (${finalDims[0]}x${finalDims[1]})` : "";
|
|
3498
|
+
const buffer = readFileSync10(output);
|
|
3499
|
+
const mimeType = outputExt === ".gif" ? "image/gif" : "image/png";
|
|
3500
|
+
const imageData = `data:${mimeType};base64,${buffer.toString("base64")}`;
|
|
3490
3501
|
return {
|
|
3491
3502
|
success: true,
|
|
3492
3503
|
output: `${basename9(output)}${sizeStr}`,
|
|
3493
|
-
|
|
3504
|
+
imageData
|
|
3494
3505
|
};
|
|
3495
3506
|
}
|
|
3496
3507
|
return {
|
|
3497
3508
|
success: false,
|
|
3498
|
-
error: "Processing failed"
|
|
3499
|
-
logs
|
|
3509
|
+
error: "Processing failed"
|
|
3500
3510
|
};
|
|
3501
3511
|
}
|
|
3502
3512
|
});
|
|
@@ -3555,9 +3565,9 @@ async function processImageSilent(input, borderColor, options, logs) {
|
|
|
3555
3565
|
async function generatePreview5(input, borderColor, options) {
|
|
3556
3566
|
const tempDir = tmpdir7();
|
|
3557
3567
|
const timestamp = Date.now();
|
|
3558
|
-
const tempSource =
|
|
3559
|
-
const tempFile =
|
|
3560
|
-
const tempOutput =
|
|
3568
|
+
const tempSource = join11(tempDir, `piclet-preview-${timestamp}-src.png`);
|
|
3569
|
+
const tempFile = join11(tempDir, `piclet-preview-${timestamp}.png`);
|
|
3570
|
+
const tempOutput = join11(tempDir, `piclet-preview-${timestamp}-out.png`);
|
|
3561
3571
|
try {
|
|
3562
3572
|
let previewInput = input;
|
|
3563
3573
|
if (isMultiFrame(input)) {
|
|
@@ -3585,13 +3595,13 @@ async function generatePreview5(input, borderColor, options) {
|
|
|
3585
3595
|
}
|
|
3586
3596
|
}
|
|
3587
3597
|
if (options.makeSquare) {
|
|
3588
|
-
const squareFile =
|
|
3598
|
+
const squareFile = join11(tempDir, `piclet-preview-${timestamp}-sq.png`);
|
|
3589
3599
|
if (await squarify(currentFile, squareFile)) {
|
|
3590
3600
|
cleanup(currentFile);
|
|
3591
3601
|
currentFile = squareFile;
|
|
3592
3602
|
}
|
|
3593
3603
|
}
|
|
3594
|
-
const buffer =
|
|
3604
|
+
const buffer = readFileSync10(currentFile);
|
|
3595
3605
|
const base64 = buffer.toString("base64");
|
|
3596
3606
|
const imageData = `data:image/png;base64,${base64}`;
|
|
3597
3607
|
const dims = await getDimensions(currentFile);
|
|
@@ -3615,9 +3625,9 @@ var config8 = {
|
|
|
3615
3625
|
};
|
|
3616
3626
|
|
|
3617
3627
|
// src/tools/rescale.ts
|
|
3618
|
-
import { existsSync as
|
|
3628
|
+
import { existsSync as existsSync14, readFileSync as readFileSync11 } from "fs";
|
|
3619
3629
|
import { tmpdir as tmpdir8 } from "os";
|
|
3620
|
-
import { basename as basename10, join as
|
|
3630
|
+
import { basename as basename10, join as join12 } from "path";
|
|
3621
3631
|
async function run8(inputRaw) {
|
|
3622
3632
|
if (!await checkImageMagick()) {
|
|
3623
3633
|
error("ImageMagick not found. Please install it:");
|
|
@@ -3626,7 +3636,7 @@ async function run8(inputRaw) {
|
|
|
3626
3636
|
return false;
|
|
3627
3637
|
}
|
|
3628
3638
|
const input = normalizePath(inputRaw);
|
|
3629
|
-
if (!
|
|
3639
|
+
if (!existsSync14(input)) {
|
|
3630
3640
|
error(`File not found: ${input}`);
|
|
3631
3641
|
await pauseOnError();
|
|
3632
3642
|
return false;
|
|
@@ -3687,7 +3697,7 @@ async function run8(inputRaw) {
|
|
|
3687
3697
|
} else {
|
|
3688
3698
|
scaled = await resize(input, output, targetW, targetH);
|
|
3689
3699
|
}
|
|
3690
|
-
if (!scaled || !
|
|
3700
|
+
if (!scaled || !existsSync14(output)) {
|
|
3691
3701
|
wipDone(false, "Scaling failed");
|
|
3692
3702
|
return false;
|
|
3693
3703
|
}
|
|
@@ -3703,7 +3713,7 @@ async function run8(inputRaw) {
|
|
|
3703
3713
|
}
|
|
3704
3714
|
async function runGUI9(inputRaw) {
|
|
3705
3715
|
const input = normalizePath(inputRaw);
|
|
3706
|
-
if (!
|
|
3716
|
+
if (!existsSync14(input)) {
|
|
3707
3717
|
error(`File not found: ${input}`);
|
|
3708
3718
|
return false;
|
|
3709
3719
|
}
|
|
@@ -3757,7 +3767,7 @@ async function runGUI9(inputRaw) {
|
|
|
3757
3767
|
} else {
|
|
3758
3768
|
scaled = await resize(input, output, options.width, options.height);
|
|
3759
3769
|
}
|
|
3760
|
-
if (scaled &&
|
|
3770
|
+
if (scaled && existsSync14(output)) {
|
|
3761
3771
|
const finalDims = await getDimensions(output);
|
|
3762
3772
|
const sizeStr = finalDims ? ` (${finalDims[0]}x${finalDims[1]})` : "";
|
|
3763
3773
|
logs.push({ type: "success", message: "Scaled successfully" });
|
|
@@ -3775,8 +3785,8 @@ async function runGUI9(inputRaw) {
|
|
|
3775
3785
|
async function generatePreview6(input, options) {
|
|
3776
3786
|
const tempDir = tmpdir8();
|
|
3777
3787
|
const timestamp = Date.now();
|
|
3778
|
-
const tempSource =
|
|
3779
|
-
const tempOutput =
|
|
3788
|
+
const tempSource = join12(tempDir, `piclet-preview-${timestamp}-src.png`);
|
|
3789
|
+
const tempOutput = join12(tempDir, `piclet-preview-${timestamp}.png`);
|
|
3780
3790
|
try {
|
|
3781
3791
|
let previewInput = input;
|
|
3782
3792
|
if (isMultiFrame(input)) {
|
|
@@ -3796,11 +3806,11 @@ async function generatePreview6(input, options) {
|
|
|
3796
3806
|
} else {
|
|
3797
3807
|
scaled = await resize(previewInput, tempOutput, targetW, targetH);
|
|
3798
3808
|
}
|
|
3799
|
-
if (!scaled || !
|
|
3809
|
+
if (!scaled || !existsSync14(tempOutput)) {
|
|
3800
3810
|
cleanup(tempSource);
|
|
3801
3811
|
return { success: false, error: "Scaling failed" };
|
|
3802
3812
|
}
|
|
3803
|
-
const buffer =
|
|
3813
|
+
const buffer = readFileSync11(tempOutput);
|
|
3804
3814
|
const base64 = buffer.toString("base64");
|
|
3805
3815
|
const imageData = `data:image/png;base64,${base64}`;
|
|
3806
3816
|
const dims = await getDimensions(tempOutput);
|
|
@@ -3824,8 +3834,8 @@ var config9 = {
|
|
|
3824
3834
|
};
|
|
3825
3835
|
|
|
3826
3836
|
// src/tools/storepack.ts
|
|
3827
|
-
import { existsSync as
|
|
3828
|
-
import { basename as basename11, join as
|
|
3837
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync8 } from "fs";
|
|
3838
|
+
import { basename as basename11, join as join13 } from "path";
|
|
3829
3839
|
async function scaleImage(input, output, width, height, mode) {
|
|
3830
3840
|
switch (mode) {
|
|
3831
3841
|
case "fill":
|
|
@@ -3842,7 +3852,7 @@ async function generatePresetImages(sourceImg, outputDir, preset, scaleMode = "f
|
|
|
3842
3852
|
const total = preset.icons.length;
|
|
3843
3853
|
for (let i = 0; i < total; i++) {
|
|
3844
3854
|
const icon = preset.icons[i];
|
|
3845
|
-
const outputPath =
|
|
3855
|
+
const outputPath = join13(outputDir, icon.filename);
|
|
3846
3856
|
if (logs) {
|
|
3847
3857
|
logs.push({ type: "info", message: `[${i + 1}/${total}] ${icon.filename}` });
|
|
3848
3858
|
} else {
|
|
@@ -3878,7 +3888,7 @@ async function run9(inputRaw) {
|
|
|
3878
3888
|
return false;
|
|
3879
3889
|
}
|
|
3880
3890
|
const input = normalizePath(inputRaw);
|
|
3881
|
-
if (!
|
|
3891
|
+
if (!existsSync15(input)) {
|
|
3882
3892
|
error(`File not found: ${input}`);
|
|
3883
3893
|
await pauseOnError();
|
|
3884
3894
|
return false;
|
|
@@ -3906,11 +3916,11 @@ async function run9(inputRaw) {
|
|
|
3906
3916
|
return false;
|
|
3907
3917
|
}
|
|
3908
3918
|
const outputDir = `${fileInfo.dirname}/${fileInfo.filename}_${preset.id}`;
|
|
3909
|
-
|
|
3919
|
+
mkdirSync8(outputDir, { recursive: true });
|
|
3910
3920
|
info(`Output: ${outputDir}`);
|
|
3911
3921
|
console.log("");
|
|
3912
3922
|
wip("Preparing source...");
|
|
3913
|
-
const tempSource =
|
|
3923
|
+
const tempSource = join13(outputDir, ".source.png");
|
|
3914
3924
|
if (!await squarify(input, tempSource)) {
|
|
3915
3925
|
wipDone(false, "Failed to prepare source");
|
|
3916
3926
|
return false;
|
|
@@ -3931,7 +3941,7 @@ async function run9(inputRaw) {
|
|
|
3931
3941
|
}
|
|
3932
3942
|
async function runGUI10(inputRaw) {
|
|
3933
3943
|
const input = normalizePath(inputRaw);
|
|
3934
|
-
if (!
|
|
3944
|
+
if (!existsSync15(input)) {
|
|
3935
3945
|
error(`File not found: ${input}`);
|
|
3936
3946
|
return false;
|
|
3937
3947
|
}
|
|
@@ -3980,7 +3990,7 @@ async function runGUI10(inputRaw) {
|
|
|
3980
3990
|
};
|
|
3981
3991
|
}
|
|
3982
3992
|
const outputDir = `${fileInfo.dirname}/${fileInfo.filename}_${preset.id}`;
|
|
3983
|
-
|
|
3993
|
+
mkdirSync8(outputDir, { recursive: true });
|
|
3984
3994
|
logs.push({ type: "info", message: `Output: ${outputDir}` });
|
|
3985
3995
|
logs.push({ type: "info", message: `Scale mode: ${scaleMode}` });
|
|
3986
3996
|
logs.push({ type: "info", message: `Generating ${preset.icons.length} images...` });
|
|
@@ -4009,9 +4019,9 @@ var config10 = {
|
|
|
4009
4019
|
};
|
|
4010
4020
|
|
|
4011
4021
|
// src/tools/transform.ts
|
|
4012
|
-
import { existsSync as
|
|
4022
|
+
import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
|
|
4013
4023
|
import { tmpdir as tmpdir9 } from "os";
|
|
4014
|
-
import { basename as basename12, join as
|
|
4024
|
+
import { basename as basename12, join as join14 } from "path";
|
|
4015
4025
|
var TRANSFORM_LABELS = {
|
|
4016
4026
|
"flip-h": "Flip Horizontal",
|
|
4017
4027
|
"flip-v": "Flip Vertical",
|
|
@@ -4087,7 +4097,7 @@ async function run10(inputRaw) {
|
|
|
4087
4097
|
return false;
|
|
4088
4098
|
}
|
|
4089
4099
|
const input = normalizePath(inputRaw);
|
|
4090
|
-
if (!
|
|
4100
|
+
if (!existsSync16(input)) {
|
|
4091
4101
|
error(`File not found: ${input}`);
|
|
4092
4102
|
await pauseOnError();
|
|
4093
4103
|
return false;
|
|
@@ -4106,7 +4116,7 @@ async function run10(inputRaw) {
|
|
|
4106
4116
|
}
|
|
4107
4117
|
async function runGUI11(inputRaw) {
|
|
4108
4118
|
const input = normalizePath(inputRaw);
|
|
4109
|
-
if (!
|
|
4119
|
+
if (!existsSync16(input)) {
|
|
4110
4120
|
error(`File not found: ${input}`);
|
|
4111
4121
|
return false;
|
|
4112
4122
|
}
|
|
@@ -4189,8 +4199,8 @@ async function runGUI11(inputRaw) {
|
|
|
4189
4199
|
async function generatePreview7(input, options) {
|
|
4190
4200
|
const tempDir = tmpdir9();
|
|
4191
4201
|
const timestamp = Date.now();
|
|
4192
|
-
const tempSource =
|
|
4193
|
-
const tempOutput =
|
|
4202
|
+
const tempSource = join14(tempDir, `piclet-preview-${timestamp}-src.png`);
|
|
4203
|
+
const tempOutput = join14(tempDir, `piclet-preview-${timestamp}.png`);
|
|
4194
4204
|
try {
|
|
4195
4205
|
let previewInput = input;
|
|
4196
4206
|
if (isMultiFrame(input)) {
|
|
@@ -4221,7 +4231,7 @@ async function generatePreview7(input, options) {
|
|
|
4221
4231
|
cleanup(tempSource, tempOutput);
|
|
4222
4232
|
return { success: false, error: "Transform failed" };
|
|
4223
4233
|
}
|
|
4224
|
-
const buffer =
|
|
4234
|
+
const buffer = readFileSync12(tempOutput);
|
|
4225
4235
|
const base64 = buffer.toString("base64");
|
|
4226
4236
|
const imageData = `data:image/png;base64,${base64}`;
|
|
4227
4237
|
const dims = await getDimensions(tempOutput);
|
|
@@ -4278,6 +4288,10 @@ function getToolsForExtension(extension) {
|
|
|
4278
4288
|
}
|
|
4279
4289
|
|
|
4280
4290
|
// src/cli/utils.ts
|
|
4291
|
+
import { extname as extname4 } from "path";
|
|
4292
|
+
import { dirname as dirname9 } from "path";
|
|
4293
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4294
|
+
import chalk2 from "chalk";
|
|
4281
4295
|
function getDistDir() {
|
|
4282
4296
|
const currentFile = fileURLToPath2(import.meta.url);
|
|
4283
4297
|
return dirname9(currentFile);
|
|
@@ -4289,7 +4303,7 @@ function validateExtensions(files, allowedExtensions) {
|
|
|
4289
4303
|
const valid = [];
|
|
4290
4304
|
const invalid = [];
|
|
4291
4305
|
for (const file of files) {
|
|
4292
|
-
const ext =
|
|
4306
|
+
const ext = extname4(file).toLowerCase();
|
|
4293
4307
|
if (allowedExtensions.includes(ext)) {
|
|
4294
4308
|
valid.push(file);
|
|
4295
4309
|
} else {
|
|
@@ -4301,17 +4315,17 @@ function validateExtensions(files, allowedExtensions) {
|
|
|
4301
4315
|
async function runToolOnFiles(toolId, files, useYes) {
|
|
4302
4316
|
const tool = getTool(toolId);
|
|
4303
4317
|
if (!tool) {
|
|
4304
|
-
console.error(
|
|
4318
|
+
console.error(chalk2.red(`Tool not found: ${toolId}`));
|
|
4305
4319
|
return false;
|
|
4306
4320
|
}
|
|
4307
4321
|
const { valid, invalid } = validateExtensions(files, tool.config.extensions);
|
|
4308
4322
|
if (invalid.length > 0) {
|
|
4309
|
-
console.error(
|
|
4323
|
+
console.error(chalk2.red("Invalid file types:"));
|
|
4310
4324
|
for (const file of invalid) {
|
|
4311
|
-
console.error(
|
|
4325
|
+
console.error(chalk2.red(` \u2717 ${file}`));
|
|
4312
4326
|
}
|
|
4313
4327
|
console.error(
|
|
4314
|
-
|
|
4328
|
+
chalk2.yellow(
|
|
4315
4329
|
`
|
|
4316
4330
|
Supported extensions: ${tool.config.extensions.join(", ")}`
|
|
4317
4331
|
)
|
|
@@ -4326,7 +4340,7 @@ Supported extensions: ${tool.config.extensions.join(", ")}`
|
|
|
4326
4340
|
for (let i = 0; i < valid.length; i++) {
|
|
4327
4341
|
const file = valid[i];
|
|
4328
4342
|
if (valid.length > 1) {
|
|
4329
|
-
console.log(
|
|
4343
|
+
console.log(chalk2.cyan(`
|
|
4330
4344
|
[${i + 1}/${valid.length}] ${file}`));
|
|
4331
4345
|
}
|
|
4332
4346
|
const success2 = await tool.run(file);
|
|
@@ -4341,15 +4355,15 @@ function registerBorderCommand(program2) {
|
|
|
4341
4355
|
if (options.gui) {
|
|
4342
4356
|
const { valid, invalid } = validateExtensions(files, config.extensions);
|
|
4343
4357
|
if (invalid.length > 0) {
|
|
4344
|
-
console.error(
|
|
4358
|
+
console.error(chalk3.red("Invalid file types:"));
|
|
4345
4359
|
for (const file of invalid) {
|
|
4346
|
-
console.error(
|
|
4360
|
+
console.error(chalk3.red(` - ${file}`));
|
|
4347
4361
|
}
|
|
4348
4362
|
}
|
|
4349
4363
|
if (valid.length === 0) {
|
|
4350
4364
|
process.exit(1);
|
|
4351
4365
|
}
|
|
4352
|
-
const result = await runGUI(valid[0]);
|
|
4366
|
+
const result = await picletTool.runGUI(valid[0]);
|
|
4353
4367
|
process.exit(result ? 0 : 1);
|
|
4354
4368
|
}
|
|
4355
4369
|
const success2 = await runToolOnFiles(
|
|
@@ -4362,38 +4376,38 @@ function registerBorderCommand(program2) {
|
|
|
4362
4376
|
}
|
|
4363
4377
|
|
|
4364
4378
|
// src/cli/commands/config.ts
|
|
4365
|
-
import
|
|
4379
|
+
import chalk4 from "chalk";
|
|
4366
4380
|
function registerConfigCommand(program2) {
|
|
4367
4381
|
const configCmd = program2.command("config").description("Display current settings").action(() => {
|
|
4368
4382
|
const config12 = loadConfig();
|
|
4369
|
-
console.log(
|
|
4370
|
-
console.log(
|
|
4383
|
+
console.log(chalk4.white.bold("\n PicLet Configuration"));
|
|
4384
|
+
console.log(chalk4.gray(` ${getConfigPath()}
|
|
4371
4385
|
`));
|
|
4372
4386
|
console.log(JSON.stringify(config12, null, 2));
|
|
4373
4387
|
console.log();
|
|
4374
4388
|
});
|
|
4375
4389
|
configCmd.command("reset").description("Restore defaults").action(() => {
|
|
4376
4390
|
resetConfig();
|
|
4377
|
-
console.log(
|
|
4391
|
+
console.log(chalk4.green("Configuration reset to defaults."));
|
|
4378
4392
|
});
|
|
4379
4393
|
}
|
|
4380
4394
|
|
|
4381
4395
|
// src/cli/commands/extract-frames.ts
|
|
4382
|
-
import
|
|
4396
|
+
import chalk5 from "chalk";
|
|
4383
4397
|
function registerExtractFramesCommand(program2) {
|
|
4384
|
-
program2.command("extract-frames <files...>").alias("frames").description("Extract frames from animated GIF").option("-y, --yes", "Use defaults, skip prompts").option("-g, --gui", "Use GUI for options").action(async (files, options) => {
|
|
4398
|
+
program2.command("extract-frames <files...>").alias("frames").alias("gif").description("Extract frames from animated GIF").option("-y, --yes", "Use defaults, skip prompts").option("-g, --gui", "Use GUI for options").action(async (files, options) => {
|
|
4385
4399
|
if (options.gui) {
|
|
4386
4400
|
const { valid, invalid } = validateExtensions(files, config2.extensions);
|
|
4387
4401
|
if (invalid.length > 0) {
|
|
4388
|
-
console.error(
|
|
4402
|
+
console.error(chalk5.red("Invalid file types:"));
|
|
4389
4403
|
for (const file of invalid) {
|
|
4390
|
-
console.error(
|
|
4404
|
+
console.error(chalk5.red(` - ${file}`));
|
|
4391
4405
|
}
|
|
4392
4406
|
}
|
|
4393
4407
|
if (valid.length === 0) {
|
|
4394
4408
|
process.exit(1);
|
|
4395
4409
|
}
|
|
4396
|
-
const result = await
|
|
4410
|
+
const result = await picletTool.runGUI(valid[0]);
|
|
4397
4411
|
process.exit(result ? 0 : 1);
|
|
4398
4412
|
}
|
|
4399
4413
|
const success2 = await runToolOnFiles(
|
|
@@ -4406,21 +4420,21 @@ function registerExtractFramesCommand(program2) {
|
|
|
4406
4420
|
}
|
|
4407
4421
|
|
|
4408
4422
|
// src/cli/commands/filter.ts
|
|
4409
|
-
import
|
|
4423
|
+
import chalk6 from "chalk";
|
|
4410
4424
|
function registerFilterCommand(program2) {
|
|
4411
4425
|
program2.command("filter <files...>").description("Apply color filters (grayscale, sepia, etc.)").option("-y, --yes", "Use defaults, skip prompts").option("-g, --gui", "Use GUI for options").action(async (files, options) => {
|
|
4412
4426
|
if (options.gui) {
|
|
4413
4427
|
const { valid, invalid } = validateExtensions(files, config3.extensions);
|
|
4414
4428
|
if (invalid.length > 0) {
|
|
4415
|
-
console.error(
|
|
4429
|
+
console.error(chalk6.red("Invalid file types:"));
|
|
4416
4430
|
for (const file of invalid) {
|
|
4417
|
-
console.error(
|
|
4431
|
+
console.error(chalk6.red(` - ${file}`));
|
|
4418
4432
|
}
|
|
4419
4433
|
}
|
|
4420
4434
|
if (valid.length === 0) {
|
|
4421
4435
|
process.exit(1);
|
|
4422
4436
|
}
|
|
4423
|
-
const result = await
|
|
4437
|
+
const result = await picletTool.runGUI(valid[0]);
|
|
4424
4438
|
process.exit(result ? 0 : 1);
|
|
4425
4439
|
}
|
|
4426
4440
|
const success2 = await runToolOnFiles(
|
|
@@ -4440,21 +4454,21 @@ function registerHelpCommand(program2) {
|
|
|
4440
4454
|
}
|
|
4441
4455
|
|
|
4442
4456
|
// src/cli/commands/iconpack.ts
|
|
4443
|
-
import
|
|
4457
|
+
import chalk7 from "chalk";
|
|
4444
4458
|
function registerIconpackCommand(program2) {
|
|
4445
4459
|
program2.command("iconpack <files...>").description("Generate icon sets for Web, Android, iOS").option("-y, --yes", "Use defaults, skip prompts").option("-g, --gui", "Use GUI for options").action(async (files, options) => {
|
|
4446
4460
|
if (options.gui) {
|
|
4447
4461
|
const { valid, invalid } = validateExtensions(files, config4.extensions);
|
|
4448
4462
|
if (invalid.length > 0) {
|
|
4449
|
-
console.error(
|
|
4463
|
+
console.error(chalk7.red("Invalid file types:"));
|
|
4450
4464
|
for (const file of invalid) {
|
|
4451
|
-
console.error(
|
|
4465
|
+
console.error(chalk7.red(` - ${file}`));
|
|
4452
4466
|
}
|
|
4453
4467
|
}
|
|
4454
4468
|
if (valid.length === 0) {
|
|
4455
4469
|
process.exit(1);
|
|
4456
4470
|
}
|
|
4457
|
-
const result = await
|
|
4471
|
+
const result = await picletTool.runGUI(valid[0]);
|
|
4458
4472
|
process.exit(result ? 0 : 1);
|
|
4459
4473
|
}
|
|
4460
4474
|
const success2 = await runToolOnFiles(
|
|
@@ -4467,11 +4481,11 @@ function registerIconpackCommand(program2) {
|
|
|
4467
4481
|
}
|
|
4468
4482
|
|
|
4469
4483
|
// src/cli/commands/install.ts
|
|
4470
|
-
import
|
|
4484
|
+
import chalk8 from "chalk";
|
|
4471
4485
|
|
|
4472
4486
|
// src/lib/registry.ts
|
|
4473
4487
|
import { exec as exec2 } from "child_process";
|
|
4474
|
-
import { existsSync as
|
|
4488
|
+
import { existsSync as existsSync17 } from "fs";
|
|
4475
4489
|
import { dirname as dirname10 } from "path";
|
|
4476
4490
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4477
4491
|
import { promisify as promisify2 } from "util";
|
|
@@ -4480,7 +4494,7 @@ function isWSL() {
|
|
|
4480
4494
|
return process.platform === "linux" && (process.env.WSL_DISTRO_NAME !== void 0 || process.env.WSLENV !== void 0);
|
|
4481
4495
|
}
|
|
4482
4496
|
function isWSLInteropEnabled() {
|
|
4483
|
-
return
|
|
4497
|
+
return existsSync17("/proc/sys/fs/binfmt_misc/WSLInterop");
|
|
4484
4498
|
}
|
|
4485
4499
|
async function addRegistryKey(keyPath, valueName, value, type = "REG_SZ") {
|
|
4486
4500
|
const valueArg = valueName ? `/v "${valueName}"` : "/ve";
|
|
@@ -4522,7 +4536,7 @@ async function deleteRegistryKey(keyPath) {
|
|
|
4522
4536
|
|
|
4523
4537
|
// src/cli/registry.ts
|
|
4524
4538
|
import { writeFile } from "fs/promises";
|
|
4525
|
-
import { join as
|
|
4539
|
+
import { join as join15 } from "path";
|
|
4526
4540
|
async function registerUnifiedMenu(extension, iconsDir, launcherPath) {
|
|
4527
4541
|
const basePath = `HKCU\\Software\\Classes\\SystemFileAssociations\\${extension}\\shell\\PicLet`;
|
|
4528
4542
|
const iconsDirWin = wslToWindows(iconsDir);
|
|
@@ -4558,8 +4572,8 @@ async function unregisterMenuForExtension(extension) {
|
|
|
4558
4572
|
}
|
|
4559
4573
|
async function registerAllTools() {
|
|
4560
4574
|
const distDir = getDistDir();
|
|
4561
|
-
const iconsDir =
|
|
4562
|
-
const launcherPath =
|
|
4575
|
+
const iconsDir = join15(distDir, "icons");
|
|
4576
|
+
const launcherPath = join15(distDir, "launcher.vbs");
|
|
4563
4577
|
const results = [];
|
|
4564
4578
|
for (const extension of picletTool.config.extensions) {
|
|
4565
4579
|
const result = await registerUnifiedMenu(extension, iconsDir, launcherPath);
|
|
@@ -4635,8 +4649,8 @@ function escapeRegValue(value) {
|
|
|
4635
4649
|
}
|
|
4636
4650
|
function generateRegContent() {
|
|
4637
4651
|
const distDir = getDistDir();
|
|
4638
|
-
const iconsDir =
|
|
4639
|
-
const launcherPath =
|
|
4652
|
+
const iconsDir = join15(distDir, "icons");
|
|
4653
|
+
const launcherPath = join15(distDir, "launcher.vbs");
|
|
4640
4654
|
const iconsDirWin = wslToWindows(iconsDir);
|
|
4641
4655
|
const launcherWin = wslToWindows(launcherPath);
|
|
4642
4656
|
const lines = ["Windows Registry Editor Version 5.00", ""];
|
|
@@ -4673,14 +4687,14 @@ function generateUninstallRegContent() {
|
|
|
4673
4687
|
}
|
|
4674
4688
|
async function generateRegFile() {
|
|
4675
4689
|
const distDir = getDistDir();
|
|
4676
|
-
const regPath =
|
|
4690
|
+
const regPath = join15(distDir, "piclet-install.reg");
|
|
4677
4691
|
const content = generateRegContent();
|
|
4678
4692
|
await writeFile(regPath, content, "utf-8");
|
|
4679
4693
|
return regPath;
|
|
4680
4694
|
}
|
|
4681
4695
|
async function generateUninstallRegFile() {
|
|
4682
4696
|
const distDir = getDistDir();
|
|
4683
|
-
const regPath =
|
|
4697
|
+
const regPath = join15(distDir, "piclet-uninstall.reg");
|
|
4684
4698
|
const content = generateUninstallRegContent();
|
|
4685
4699
|
await writeFile(regPath, content, "utf-8");
|
|
4686
4700
|
return regPath;
|
|
@@ -4689,86 +4703,95 @@ async function generateUninstallRegFile() {
|
|
|
4689
4703
|
// src/cli/commands/install.ts
|
|
4690
4704
|
function registerInstallCommand(program2) {
|
|
4691
4705
|
program2.command("install").description("Install Windows shell context menu integration").action(async () => {
|
|
4706
|
+
console.log(chalk8.bold("Installing...\n"));
|
|
4692
4707
|
showBanner();
|
|
4693
|
-
console.log(chalk7.bold("Installing...\n"));
|
|
4694
4708
|
if (!isWSL()) {
|
|
4695
4709
|
console.log(
|
|
4696
|
-
|
|
4710
|
+
chalk8.yellow("! Not running in WSL. Registry integration skipped.")
|
|
4697
4711
|
);
|
|
4698
4712
|
console.log(
|
|
4699
|
-
|
|
4713
|
+
chalk8.yellow('! Run "piclet install" from WSL to add context menu.')
|
|
4700
4714
|
);
|
|
4701
4715
|
return;
|
|
4702
4716
|
}
|
|
4703
4717
|
if (!isWSLInteropEnabled()) {
|
|
4704
|
-
console.log(
|
|
4718
|
+
console.log(chalk8.yellow("WSL Interop not available. Generating registry file...\n"));
|
|
4705
4719
|
const regPath = await generateRegFile();
|
|
4706
4720
|
const winPath = wslToWindows(regPath);
|
|
4707
|
-
console.log(
|
|
4708
|
-
console.log(
|
|
4721
|
+
console.log(chalk8.green("\u2713 Generated registry file:"));
|
|
4722
|
+
console.log(chalk8.cyan(` ${winPath}
|
|
4709
4723
|
`));
|
|
4710
|
-
console.log(
|
|
4711
|
-
console.log(
|
|
4712
|
-
console.log(
|
|
4713
|
-
console.log();
|
|
4724
|
+
console.log(chalk8.bold("To install, either:"));
|
|
4725
|
+
console.log(chalk8.dim(" 1. Double-click the .reg file in Windows Explorer"));
|
|
4726
|
+
console.log(chalk8.dim(` 2. Run in elevated PowerShell: reg import "${winPath}"`));
|
|
4714
4727
|
return;
|
|
4715
4728
|
}
|
|
4716
|
-
console.log(chalk7.dim("Removing old entries..."));
|
|
4717
4729
|
await unregisterAllTools();
|
|
4718
|
-
|
|
4719
|
-
const
|
|
4720
|
-
const
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
console.log();
|
|
4726
|
-
if (allSuccess) {
|
|
4727
|
-
console.log(
|
|
4728
|
-
chalk7.green(`\u2713 Registered ${tools.length} tools for context menu.`)
|
|
4729
|
-
);
|
|
4730
|
-
} else {
|
|
4731
|
-
const successCount = results.filter((r) => r.success).length;
|
|
4732
|
-
console.log(
|
|
4733
|
-
chalk7.yellow(`! Registered ${successCount}/${results.length} entries.`)
|
|
4734
|
-
);
|
|
4735
|
-
}
|
|
4736
|
-
console.log(chalk7.bold("\nContext Menu Usage:"));
|
|
4730
|
+
await registerAllTools();
|
|
4731
|
+
const dim = chalk8.gray;
|
|
4732
|
+
const cmd = chalk8.cyan;
|
|
4733
|
+
const arg = chalk8.hex("#cc8800");
|
|
4734
|
+
const opt = chalk8.green;
|
|
4735
|
+
const head = chalk8.white.bold;
|
|
4736
|
+
console.log(chalk8.bold("\nContext Menu Usage:"));
|
|
4737
4737
|
console.log(" Right-click any supported image in Windows Explorer.");
|
|
4738
4738
|
console.log(" Multi-select supported for batch processing.");
|
|
4739
|
-
console.log(
|
|
4740
|
-
console.log(
|
|
4741
|
-
console.log(
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
console.log(
|
|
4745
|
-
console.log(
|
|
4746
|
-
console.log(
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
console.log(
|
|
4750
|
-
console.log(
|
|
4751
|
-
console.log(
|
|
4739
|
+
console.log(arg(" Supported image types: [.png, .jpg, .jpeg, .gif, .bmp, .ico]"));
|
|
4740
|
+
console.log(head("\nCLI Usage:"));
|
|
4741
|
+
console.log(
|
|
4742
|
+
` ${head("Usage:")} piclet ${cmd("<command>")} ${arg("<file>")} ${opt("[options]")}`
|
|
4743
|
+
);
|
|
4744
|
+
console.log();
|
|
4745
|
+
console.log(head(" GUI"));
|
|
4746
|
+
console.log(
|
|
4747
|
+
` ${cmd("piclet")} ${arg("<file>")} Opens PicLet GUI window with all tools`
|
|
4748
|
+
);
|
|
4749
|
+
console.log();
|
|
4750
|
+
console.log(head(" Setup"));
|
|
4751
|
+
console.log(` ${cmd("install")} Add Windows right-click menu`);
|
|
4752
|
+
console.log(` ${cmd("uninstall")} Remove right-click menu`);
|
|
4753
|
+
console.log();
|
|
4754
|
+
console.log(head(" Config"));
|
|
4755
|
+
console.log(` ${cmd("config")} Display current settings`);
|
|
4756
|
+
console.log(` ${cmd("config reset")} Restore defaults`);
|
|
4757
|
+
console.log();
|
|
4758
|
+
console.log(head(" Prerequisites"));
|
|
4759
|
+
console.log(" - WSL (Windows Subsystem for Linux)");
|
|
4760
|
+
console.log(" - ImageMagick: sudo apt install imagemagick");
|
|
4761
|
+
console.log();
|
|
4762
|
+
console.log(head(" Examples"));
|
|
4763
|
+
console.log(` ${dim("$")} piclet ${cmd("piclet")} ${arg("image.png")} ${dim("# All tools in one window")}`);
|
|
4764
|
+
console.log(` ${dim("$")} piclet ${cmd("makeicon")} ${arg("logo.png")} ${dim("# Interactive")}`);
|
|
4765
|
+
console.log(` ${dim("$")} piclet ${cmd("makeicon")} ${arg("*.png")} ${opt("-y")} ${dim("# Batch with defaults")}`);
|
|
4766
|
+
console.log(` ${dim("$")} piclet ${cmd("remove-bg")} ${arg("photo.png")} ${dim("# Interactive prompts")}`);
|
|
4767
|
+
console.log(` ${dim("$")} piclet ${cmd("scale")} ${arg("image.jpg")} ${dim("# Interactive resize")}`);
|
|
4768
|
+
console.log(` ${dim("$")} piclet ${cmd("gif")} ${arg("anim.gif")} ${dim("# Extract GIF frames")}`);
|
|
4769
|
+
console.log(` ${dim("$")} piclet ${cmd("iconpack")} ${arg("icon.png")} ${opt("-y")} ${dim("# All platforms")}`);
|
|
4770
|
+
console.log(` ${dim("$")} piclet ${cmd("storepack")} ${arg("image.png")} ${opt("-g")} ${dim("# GUI for store assets")}`);
|
|
4771
|
+
console.log(
|
|
4772
|
+
`
|
|
4773
|
+
Run "piclet ${opt("--help")}" for full documentation.`
|
|
4774
|
+
);
|
|
4752
4775
|
console.log();
|
|
4753
4776
|
});
|
|
4754
4777
|
}
|
|
4755
4778
|
|
|
4756
4779
|
// src/cli/commands/makeicon.ts
|
|
4757
|
-
import
|
|
4780
|
+
import chalk9 from "chalk";
|
|
4758
4781
|
function registerMakeiconCommand(program2) {
|
|
4759
4782
|
program2.command("makeicon <files...>").description("Convert PNG to multi-resolution ICO file").option("-y, --yes", "Use defaults, skip prompts").option("-g, --gui", "Use GUI for confirmation").action(async (files, options) => {
|
|
4760
4783
|
if (options.gui) {
|
|
4761
4784
|
const { valid, invalid } = validateExtensions(files, config5.extensions);
|
|
4762
4785
|
if (invalid.length > 0) {
|
|
4763
|
-
console.error(
|
|
4786
|
+
console.error(chalk9.red("Invalid file types:"));
|
|
4764
4787
|
for (const file of invalid) {
|
|
4765
|
-
console.error(
|
|
4788
|
+
console.error(chalk9.red(` - ${file}`));
|
|
4766
4789
|
}
|
|
4767
4790
|
}
|
|
4768
4791
|
if (valid.length === 0) {
|
|
4769
4792
|
process.exit(1);
|
|
4770
4793
|
}
|
|
4771
|
-
const result = await
|
|
4794
|
+
const result = await picletTool.runGUI(valid[0]);
|
|
4772
4795
|
process.exit(result ? 0 : 1);
|
|
4773
4796
|
}
|
|
4774
4797
|
const success2 = await runToolOnFiles(
|
|
@@ -4781,13 +4804,13 @@ function registerMakeiconCommand(program2) {
|
|
|
4781
4804
|
}
|
|
4782
4805
|
|
|
4783
4806
|
// src/cli/commands/piclet.ts
|
|
4784
|
-
import
|
|
4807
|
+
import chalk10 from "chalk";
|
|
4785
4808
|
function registerPicletCommand(program2) {
|
|
4786
4809
|
program2.command("piclet <file>").description("Open unified PicLet window with all tools").option("-g, --gui", "Use GUI (default)").action(async (file) => {
|
|
4787
4810
|
const { valid, invalid } = validateExtensions([file], picletTool.config.extensions);
|
|
4788
4811
|
if (invalid.length > 0) {
|
|
4789
|
-
console.error(
|
|
4790
|
-
console.error(
|
|
4812
|
+
console.error(chalk10.red(`Invalid file type: ${file}`));
|
|
4813
|
+
console.error(chalk10.yellow(`Supported: ${picletTool.config.extensions.join(", ")}`));
|
|
4791
4814
|
process.exit(1);
|
|
4792
4815
|
}
|
|
4793
4816
|
const result = await picletTool.runGUI(valid[0]);
|
|
@@ -4796,21 +4819,21 @@ function registerPicletCommand(program2) {
|
|
|
4796
4819
|
}
|
|
4797
4820
|
|
|
4798
4821
|
// src/cli/commands/recolor.ts
|
|
4799
|
-
import
|
|
4822
|
+
import chalk11 from "chalk";
|
|
4800
4823
|
function registerRecolorCommand(program2) {
|
|
4801
4824
|
program2.command("recolor <files...>").alias("replace-color").description("Replace one color with another").option("-y, --yes", "Use defaults, skip prompts").option("-g, --gui", "Use GUI for options").action(async (files, options) => {
|
|
4802
4825
|
if (options.gui) {
|
|
4803
4826
|
const { valid, invalid } = validateExtensions(files, config7.extensions);
|
|
4804
4827
|
if (invalid.length > 0) {
|
|
4805
|
-
console.error(
|
|
4828
|
+
console.error(chalk11.red("Invalid file types:"));
|
|
4806
4829
|
for (const file of invalid) {
|
|
4807
|
-
console.error(
|
|
4830
|
+
console.error(chalk11.red(` - ${file}`));
|
|
4808
4831
|
}
|
|
4809
4832
|
}
|
|
4810
4833
|
if (valid.length === 0) {
|
|
4811
4834
|
process.exit(1);
|
|
4812
4835
|
}
|
|
4813
|
-
const result = await
|
|
4836
|
+
const result = await picletTool.runGUI(valid[0]);
|
|
4814
4837
|
process.exit(result ? 0 : 1);
|
|
4815
4838
|
}
|
|
4816
4839
|
const success2 = await runToolOnFiles(
|
|
@@ -4823,21 +4846,21 @@ function registerRecolorCommand(program2) {
|
|
|
4823
4846
|
}
|
|
4824
4847
|
|
|
4825
4848
|
// src/cli/commands/remove-bg.ts
|
|
4826
|
-
import
|
|
4849
|
+
import chalk12 from "chalk";
|
|
4827
4850
|
function registerRemoveBgCommand(program2) {
|
|
4828
4851
|
program2.command("remove-bg <files...>").alias("removebg").description("Remove solid background from image").option("-y, --yes", "Use defaults, skip prompts").option("-g, --gui", "Use TUI (terminal GUI) for options").option("-f, --fuzz <percent>", "Fuzz tolerance 0-100 (default: 10)").option("-t, --trim", "Trim transparent edges (default: true)").option("--no-trim", "Do not trim transparent edges").option("-p, --preserve-inner", "Preserve inner areas of same color").option("-s, --square", "Make output square with padding").action(async (files, options) => {
|
|
4829
4852
|
if (options.gui) {
|
|
4830
4853
|
const { valid, invalid } = validateExtensions(files, config8.extensions);
|
|
4831
4854
|
if (invalid.length > 0) {
|
|
4832
|
-
console.error(
|
|
4855
|
+
console.error(chalk12.red("Invalid file types:"));
|
|
4833
4856
|
for (const file of invalid) {
|
|
4834
|
-
console.error(
|
|
4857
|
+
console.error(chalk12.red(` - ${file}`));
|
|
4835
4858
|
}
|
|
4836
4859
|
}
|
|
4837
4860
|
if (valid.length === 0) {
|
|
4838
4861
|
process.exit(1);
|
|
4839
4862
|
}
|
|
4840
|
-
const result = await
|
|
4863
|
+
const result = await picletTool.runGUI(valid[0]);
|
|
4841
4864
|
process.exit(result ? 0 : 1);
|
|
4842
4865
|
}
|
|
4843
4866
|
if (options.fuzz !== void 0) {
|
|
@@ -4863,21 +4886,21 @@ function registerRemoveBgCommand(program2) {
|
|
|
4863
4886
|
}
|
|
4864
4887
|
|
|
4865
4888
|
// src/cli/commands/scale.ts
|
|
4866
|
-
import
|
|
4889
|
+
import chalk13 from "chalk";
|
|
4867
4890
|
function registerScaleCommand(program2) {
|
|
4868
4891
|
program2.command("scale <files...>").alias("rescale").description("Resize image with optional padding").option("-y, --yes", "Use defaults, skip prompts").option("-g, --gui", "Use GUI for options").action(async (files, options) => {
|
|
4869
4892
|
if (options.gui) {
|
|
4870
4893
|
const { valid, invalid } = validateExtensions(files, config9.extensions);
|
|
4871
4894
|
if (invalid.length > 0) {
|
|
4872
|
-
console.error(
|
|
4895
|
+
console.error(chalk13.red("Invalid file types:"));
|
|
4873
4896
|
for (const file of invalid) {
|
|
4874
|
-
console.error(
|
|
4897
|
+
console.error(chalk13.red(` - ${file}`));
|
|
4875
4898
|
}
|
|
4876
4899
|
}
|
|
4877
4900
|
if (valid.length === 0) {
|
|
4878
4901
|
process.exit(1);
|
|
4879
4902
|
}
|
|
4880
|
-
const result = await
|
|
4903
|
+
const result = await picletTool.runGUI(valid[0]);
|
|
4881
4904
|
process.exit(result ? 0 : 1);
|
|
4882
4905
|
}
|
|
4883
4906
|
const success2 = await runToolOnFiles(
|
|
@@ -4890,21 +4913,21 @@ function registerScaleCommand(program2) {
|
|
|
4890
4913
|
}
|
|
4891
4914
|
|
|
4892
4915
|
// src/cli/commands/storepack.ts
|
|
4893
|
-
import
|
|
4916
|
+
import chalk14 from "chalk";
|
|
4894
4917
|
function registerStorepackCommand(program2) {
|
|
4895
4918
|
program2.command("storepack <files...>").description("Generate assets for app stores (Windows, Unity, Steam, etc.)").option("-y, --yes", "Use defaults, skip prompts").option("-g, --gui", "Use GUI for options").action(async (files, options) => {
|
|
4896
4919
|
if (options.gui) {
|
|
4897
4920
|
const { valid, invalid } = validateExtensions(files, config10.extensions);
|
|
4898
4921
|
if (invalid.length > 0) {
|
|
4899
|
-
console.error(
|
|
4922
|
+
console.error(chalk14.red("Invalid file types:"));
|
|
4900
4923
|
for (const file of invalid) {
|
|
4901
|
-
console.error(
|
|
4924
|
+
console.error(chalk14.red(` - ${file}`));
|
|
4902
4925
|
}
|
|
4903
4926
|
}
|
|
4904
4927
|
if (valid.length === 0) {
|
|
4905
4928
|
process.exit(1);
|
|
4906
4929
|
}
|
|
4907
|
-
const result = await
|
|
4930
|
+
const result = await picletTool.runGUI(valid[0]);
|
|
4908
4931
|
process.exit(result ? 0 : 1);
|
|
4909
4932
|
}
|
|
4910
4933
|
const success2 = await runToolOnFiles(
|
|
@@ -4917,21 +4940,21 @@ function registerStorepackCommand(program2) {
|
|
|
4917
4940
|
}
|
|
4918
4941
|
|
|
4919
4942
|
// src/cli/commands/transform.ts
|
|
4920
|
-
import
|
|
4943
|
+
import chalk15 from "chalk";
|
|
4921
4944
|
function registerTransformCommand(program2) {
|
|
4922
4945
|
program2.command("transform <files...>").alias("flip").description("Flip or rotate images").option("-y, --yes", "Use defaults, skip prompts").option("-g, --gui", "Use GUI for options").action(async (files, options) => {
|
|
4923
4946
|
if (options.gui) {
|
|
4924
4947
|
const { valid, invalid } = validateExtensions(files, config11.extensions);
|
|
4925
4948
|
if (invalid.length > 0) {
|
|
4926
|
-
console.error(
|
|
4949
|
+
console.error(chalk15.red("Invalid file types:"));
|
|
4927
4950
|
for (const file of invalid) {
|
|
4928
|
-
console.error(
|
|
4951
|
+
console.error(chalk15.red(` - ${file}`));
|
|
4929
4952
|
}
|
|
4930
4953
|
}
|
|
4931
4954
|
if (valid.length === 0) {
|
|
4932
4955
|
process.exit(1);
|
|
4933
4956
|
}
|
|
4934
|
-
const result = await
|
|
4957
|
+
const result = await picletTool.runGUI(valid[0]);
|
|
4935
4958
|
process.exit(result ? 0 : 1);
|
|
4936
4959
|
}
|
|
4937
4960
|
const success2 = await runToolOnFiles(
|
|
@@ -4944,41 +4967,41 @@ function registerTransformCommand(program2) {
|
|
|
4944
4967
|
}
|
|
4945
4968
|
|
|
4946
4969
|
// src/cli/commands/uninstall.ts
|
|
4947
|
-
import
|
|
4970
|
+
import chalk16 from "chalk";
|
|
4948
4971
|
function registerUninstallCommand(program2) {
|
|
4949
4972
|
program2.command("uninstall").description("Remove Windows shell context menu integration").action(async () => {
|
|
4950
4973
|
showBanner();
|
|
4951
|
-
console.log(
|
|
4974
|
+
console.log(chalk16.bold("Uninstalling...\n"));
|
|
4952
4975
|
if (!isWSL()) {
|
|
4953
4976
|
console.log(
|
|
4954
|
-
|
|
4977
|
+
chalk16.yellow("! Not running in WSL. Registry cleanup skipped.")
|
|
4955
4978
|
);
|
|
4956
4979
|
console.log(
|
|
4957
|
-
|
|
4980
|
+
chalk16.yellow(
|
|
4958
4981
|
'! Run "piclet uninstall" from WSL to remove context menu.'
|
|
4959
4982
|
)
|
|
4960
4983
|
);
|
|
4961
4984
|
return;
|
|
4962
4985
|
}
|
|
4963
4986
|
if (!isWSLInteropEnabled()) {
|
|
4964
|
-
console.log(
|
|
4987
|
+
console.log(chalk16.yellow("WSL Interop not available. Generating registry file...\n"));
|
|
4965
4988
|
const regPath = await generateUninstallRegFile();
|
|
4966
4989
|
const winPath = wslToWindows(regPath);
|
|
4967
|
-
console.log(
|
|
4968
|
-
console.log(
|
|
4990
|
+
console.log(chalk16.green("\u2713 Generated uninstall registry file:"));
|
|
4991
|
+
console.log(chalk16.cyan(` ${winPath}
|
|
4969
4992
|
`));
|
|
4970
|
-
console.log(
|
|
4971
|
-
console.log(
|
|
4972
|
-
console.log(
|
|
4993
|
+
console.log(chalk16.bold("To uninstall, either:"));
|
|
4994
|
+
console.log(chalk16.dim(" 1. Double-click the .reg file in Windows Explorer"));
|
|
4995
|
+
console.log(chalk16.dim(` 2. Run in elevated PowerShell: reg import "${winPath}"`));
|
|
4973
4996
|
console.log();
|
|
4974
4997
|
return;
|
|
4975
4998
|
}
|
|
4976
|
-
console.log(
|
|
4999
|
+
console.log(chalk16.dim("Cleaning up legacy entries...\n"));
|
|
4977
5000
|
const legacyResult = await cleanupLegacyEntries();
|
|
4978
5001
|
if (legacyResult.removed.length > 0) {
|
|
4979
|
-
console.log(
|
|
5002
|
+
console.log(chalk16.yellow(`Removed ${legacyResult.removed.length} legacy entries:`));
|
|
4980
5003
|
for (const entry of legacyResult.removed) {
|
|
4981
|
-
console.log(` ${
|
|
5004
|
+
console.log(` ${chalk16.green("\u2713")} ${entry}`);
|
|
4982
5005
|
}
|
|
4983
5006
|
console.log();
|
|
4984
5007
|
}
|
|
@@ -4987,40 +5010,40 @@ function registerUninstallCommand(program2) {
|
|
|
4987
5010
|
for (const result of results) {
|
|
4988
5011
|
if (result.success) {
|
|
4989
5012
|
console.log(
|
|
4990
|
-
`${
|
|
5013
|
+
`${chalk16.green("\u2713")} Removed: ${result.extension} \u2192 ${result.toolName}`
|
|
4991
5014
|
);
|
|
4992
5015
|
} else {
|
|
4993
5016
|
console.log(
|
|
4994
|
-
`${
|
|
5017
|
+
`${chalk16.gray("-")} Skipped: ${result.extension} \u2192 ${result.toolName}`
|
|
4995
5018
|
);
|
|
4996
5019
|
}
|
|
4997
5020
|
}
|
|
4998
5021
|
const totalRemoved = removedCount + legacyResult.removed.length;
|
|
4999
5022
|
console.log();
|
|
5000
5023
|
console.log(
|
|
5001
|
-
|
|
5024
|
+
chalk16.green(
|
|
5002
5025
|
`\u2713 Cleanup complete. Removed ${totalRemoved} entries total.`
|
|
5003
5026
|
)
|
|
5004
5027
|
);
|
|
5005
|
-
console.log(
|
|
5028
|
+
console.log(chalk16.dim("\nThanks for using PicLet!\n"));
|
|
5006
5029
|
});
|
|
5007
5030
|
}
|
|
5008
5031
|
|
|
5009
5032
|
// src/cli/index.ts
|
|
5010
5033
|
function showHelp() {
|
|
5011
5034
|
showBanner();
|
|
5012
|
-
const dim =
|
|
5013
|
-
const cmd =
|
|
5014
|
-
const arg =
|
|
5015
|
-
const opt =
|
|
5016
|
-
const head =
|
|
5035
|
+
const dim = chalk17.gray;
|
|
5036
|
+
const cmd = chalk17.cyan;
|
|
5037
|
+
const arg = chalk17.hex("#cc8800");
|
|
5038
|
+
const opt = chalk17.green;
|
|
5039
|
+
const head = chalk17.white.bold;
|
|
5017
5040
|
console.log(
|
|
5018
5041
|
` ${head("Usage:")} piclet ${cmd("<command>")} ${arg("<file>")} ${opt("[options]")}`
|
|
5019
5042
|
);
|
|
5020
5043
|
console.log();
|
|
5021
|
-
console.log(head("
|
|
5044
|
+
console.log(head(" GUI"));
|
|
5022
5045
|
console.log(
|
|
5023
|
-
` ${cmd("piclet")} ${arg("<file>")}
|
|
5046
|
+
` ${cmd("piclet")} ${arg("<file>")} Opens PicLet GUI with all tools in one window`
|
|
5024
5047
|
);
|
|
5025
5048
|
console.log();
|
|
5026
5049
|
console.log(head(" Individual Tools"));
|
|
@@ -5034,19 +5057,7 @@ function showHelp() {
|
|
|
5034
5057
|
` ${cmd("scale")} ${arg("<file>")} Resize image with optional padding`
|
|
5035
5058
|
);
|
|
5036
5059
|
console.log(
|
|
5037
|
-
` ${cmd("
|
|
5038
|
-
);
|
|
5039
|
-
console.log(
|
|
5040
|
-
` ${cmd("filter")} ${arg("<file>")} Apply color filters (grayscale, sepia)`
|
|
5041
|
-
);
|
|
5042
|
-
console.log(
|
|
5043
|
-
` ${cmd("border")} ${arg("<file>")} Add solid color border`
|
|
5044
|
-
);
|
|
5045
|
-
console.log(
|
|
5046
|
-
` ${cmd("recolor")} ${arg("<file>")} Replace one color with another`
|
|
5047
|
-
);
|
|
5048
|
-
console.log(
|
|
5049
|
-
` ${cmd("frames")} ${arg("<file>")} Extract frames from animated GIF`
|
|
5060
|
+
` ${cmd("gif")} ${arg("<file>")} Extract frames from animated GIF`
|
|
5050
5061
|
);
|
|
5051
5062
|
console.log(
|
|
5052
5063
|
` ${cmd("iconpack")} ${arg("<file>")} Generate icon sets for Web/Android/iOS`
|
|
@@ -5071,6 +5082,7 @@ function showHelp() {
|
|
|
5071
5082
|
console.log(` ${dim("$")} piclet ${cmd("makeicon")} ${arg("*.png")} ${opt("-y")} ${dim("# Batch with defaults")}`);
|
|
5072
5083
|
console.log(` ${dim("$")} piclet ${cmd("remove-bg")} ${arg("photo.png")} ${dim("# Interactive prompts")}`);
|
|
5073
5084
|
console.log(` ${dim("$")} piclet ${cmd("scale")} ${arg("image.jpg")} ${dim("# Interactive resize")}`);
|
|
5085
|
+
console.log(` ${dim("$")} piclet ${cmd("gif")} ${arg("anim.gif")} ${dim("# Extract GIF frames")}`);
|
|
5074
5086
|
console.log(` ${dim("$")} piclet ${cmd("iconpack")} ${arg("icon.png")} ${opt("-y")} ${dim("# All platforms")}`);
|
|
5075
5087
|
console.log();
|
|
5076
5088
|
console.log(head(" Requirements"));
|
|
@@ -5082,6 +5094,7 @@ function createProgram() {
|
|
|
5082
5094
|
const program2 = new Command();
|
|
5083
5095
|
program2.helpInformation = () => "";
|
|
5084
5096
|
program2.on("--help", () => {
|
|
5097
|
+
showHelp();
|
|
5085
5098
|
});
|
|
5086
5099
|
program2.name("piclet").description("Image manipulation utility toolkit with Windows shell integration").version("1.0.0").action(() => {
|
|
5087
5100
|
showHelp();
|
|
@@ -5107,7 +5120,7 @@ function createProgram() {
|
|
|
5107
5120
|
// src/cli.ts
|
|
5108
5121
|
var program = createProgram();
|
|
5109
5122
|
program.parseAsync(process.argv).catch((error2) => {
|
|
5110
|
-
console.error(
|
|
5123
|
+
console.error(chalk18.red(`Error: ${error2.message}`));
|
|
5111
5124
|
process.exit(1);
|
|
5112
5125
|
});
|
|
5113
5126
|
//# sourceMappingURL=cli.js.map
|