📁 Add new image information directory
This commit is contained in:
Executable
+109
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env runts -- --runtime-bun
|
||||
|
||||
import {parseArgs} from "util";
|
||||
|
||||
const SUPPORTED_FORMATS = [".heic", ".jpeg", ".jpg", ".png", ".webp", ".gif", ".bmp", ".avif", ".tiff", ".tif"];
|
||||
|
||||
function printUsage() {
|
||||
console.log(`Usage: bun run show-image.ts <image1> [image2] ...
|
||||
|
||||
Display detailed information about image files.
|
||||
|
||||
Arguments:
|
||||
<image> ... Input image file(s)
|
||||
|
||||
Options:
|
||||
--help Show this help message
|
||||
|
||||
Supported formats:
|
||||
${SUPPORTED_FORMATS.join(", ")}
|
||||
|
||||
Examples:
|
||||
bun run show-image.ts photo.jpg
|
||||
bun run show-image.ts a.jpg b.heic c.png`);
|
||||
}
|
||||
|
||||
function formatBytes(bytes: number): string {
|
||||
if (bytes < 1024) return `${bytes} B`;
|
||||
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
||||
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
||||
}
|
||||
|
||||
function getFormat(ext: string): string {
|
||||
switch (ext) {
|
||||
case ".jpg":
|
||||
case ".jpeg":
|
||||
return "JPEG";
|
||||
case ".tif":
|
||||
case ".tiff":
|
||||
return "TIFF";
|
||||
default:
|
||||
return ext.slice(1).toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
async function showImage(path: string) {
|
||||
const file = Bun.file(path);
|
||||
|
||||
if (!(await file.exists())) {
|
||||
console.error(`File not found: ${path}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const ext = "." + file.name?.split(".").pop()?.toLowerCase();
|
||||
if (!SUPPORTED_FORMATS.includes(ext)) {
|
||||
console.error(`Unsupported format: ${ext} (${path})`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const image = file.image();
|
||||
const meta = await image.metadata();
|
||||
const size = file.size;
|
||||
|
||||
console.log(`File: ${path}`);
|
||||
console.log(`Format: ${getFormat(ext)}`);
|
||||
console.log(`Size: ${formatBytes(size)} (${size.toLocaleString()} bytes)`);
|
||||
console.log(`Dimensions: ${meta.width} x ${meta.height}`);
|
||||
console.log(`Aspect ratio: ${(meta.width / meta.height).toFixed(2)}`);
|
||||
console.log(`Megapixels: ${((meta.width * meta.height) / 1_000_000).toFixed(2)} MP`);
|
||||
console.log();
|
||||
return true;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const args = Bun.argv.slice(2);
|
||||
|
||||
if (args.length === 0 || args.includes("--help")) {
|
||||
printUsage();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const {positionals} = parseArgs({args, allowPositionals: true, strict: false});
|
||||
|
||||
if (positionals.length === 0) {
|
||||
console.error("Error: No input files specified.\n");
|
||||
printUsage();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let successCount = 0;
|
||||
for (const path of positionals) {
|
||||
const ok = await showImage(path);
|
||||
if (ok) successCount++;
|
||||
}
|
||||
|
||||
if (positionals.length > 1) {
|
||||
console.log(`Total: ${successCount}/${positionals.length} file(s) processed.`);
|
||||
}
|
||||
|
||||
if (successCount === 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
// @SCRIPT-SIGNATURE-V1: yk-r1.ES256.20260526T004141+08:00.MEQCIBjY8Rshew3TyWpojRAp
|
||||
// /WewTldgEjhANbtyjw8Sn2VBAiARxfPLnmHlfkXZlVnN0lJoQmg1sqMmqouiHEjcxWQf3Q==
|
||||
Reference in New Issue
Block a user