feat: rename old -> v1 folder

This commit is contained in:
2026-09-10 20:23:45 +05:00
parent 1e5e096d5d
commit 33e3f3c4f0
60 changed files with 60 additions and 69 deletions
+354
View File
@@ -0,0 +1,354 @@
import type { ToolEntry } from "../registry";
import { clonePixelImage } from "../../core/types";
import { flattenOntoColor } from "../../core/alpha";
import { toBase64, toDataUrl, decodeSvgText, encode } from "../../core/io";
import { pixelsToHex, hexToPixels } from "../../core/text";
import {
imageToByteRows,
bytesToImage,
imageToRgbValues,
rgbValuesToImage,
} from "../../core/textio";
import {
COMPRESSION_LEVELS,
findMaxColorsWithin,
type CompressionLevel,
} from "../../core/compress";
import { quantizeImage } from "../../core/quantize";
import { num, str } from "../registry-helpers";
function decodeToPng(
id: string,
title: string,
description: string,
): ToolEntry {
return {
id,
title,
description,
category: "convert",
params: [],
run: (img) => clonePixelImage(img),
};
}
export function convertEntries(): ToolEntry[] {
return [
decodeToPng(
"jpg-to-png",
"Convert JPG to PNG",
"Opens a JPEG and saves it as lossless PNG. Transparency, if present, is preserved.",
),
decodeToPng(
"webp-to-png",
"Convert WebP to PNG",
"Re-encodes a WebP image into universal PNG.",
),
decodeToPng(
"gif-to-png",
"Convert GIF to PNG",
"Extracts the first frame of a GIF animation and saves it as PNG.",
),
decodeToPng(
"bmp-to-png",
"Convert BMP to PNG",
"Re-encodes BMP into compact lossless PNG.",
),
decodeToPng(
"ico-to-png",
"Convert ICO to PNG",
"Turns an .ico icon into a regular PNG of the chosen size.",
),
{
id: "png-to-bmp",
title: "Convert PNG to BMP",
description:
"Saves the image as 24-bit BMP without an alpha channel: transparency is replaced with a black background.",
category: "convert",
params: [],
run: (img) => flattenOntoColor(img, "#000000"),
output: { mime: "image/bmp", ext: "bmp" },
},
{
id: "png-to-base64",
title: "PNG to Base64",
description:
"Encodes the image into a base64 string for embedding in code or styles.",
category: "convert",
params: [],
resultType: "text",
toText: (img) => toBase64(img),
},
{
id: "base64-to-png",
title: "Base64 to PNG",
description:
"Decodes a base64 string or data-uri back into an image. Paste the string on the left.",
category: "convert",
sourceMode: "text",
params: [],
run: (img) => clonePixelImage(img),
},
{
id: "png-to-data-uri",
title: "PNG to Data URI",
description:
"Builds a full data-uri (data:image/png;base64,…) for embedding in HTML/CSS.",
category: "convert",
params: [],
resultType: "text",
toText: (img) => toDataUrl(img),
},
{
id: "data-uri-to-png",
title: "Data URI to PNG",
description: "Decodes data:image/…;base64,… back into an image file.",
category: "convert",
sourceMode: "text",
params: [],
run: (img) => clonePixelImage(img),
},
{
id: "png-to-hex",
title: "PNG to HEX pixels",
description:
"Shows all pixels as rrggbbaa hex values — row by row, space separated.",
category: "convert",
params: [],
resultType: "text",
toText: (img) => pixelsToHex(img),
},
{
id: "hex-to-png",
title: "HEX pixels to PNG",
description:
"Assembles an image from rrggbbaa hex values (space separated). Set the width — the height is computed automatically.",
category: "convert",
sourceMode: "text",
params: [
{
id: "width",
label: "Image width",
type: "number",
min: 1,
max: 10000,
step: 1,
default: 1,
},
],
runFromText: (text, p) =>
hexToPixels(text, Math.trunc(Number(p["width"]))),
run: (img) => clonePixelImage(img),
},
{
id: "png-to-bytes",
title: "PNG to Bytes",
description:
"Lists every pixel as four decimal bytes (R G B A), one image row per line.",
category: "convert",
params: [],
resultType: "text",
toText: (img) => imageToByteRows(img),
},
{
id: "bytes-to-png",
title: "Bytes to PNG",
description:
"Assembles an image from decimal RGBA byte numbers (any separators). Set the width — height is computed automatically.",
category: "convert",
sourceMode: "text",
params: [
{
id: "width",
label: "Image width",
type: "number",
min: 1,
max: 10000,
step: 1,
default: 32,
},
],
runFromText: (text, p) =>
bytesToImage(
text,
Math.trunc(num(p as Record<string, unknown>, "width")),
),
run: (img) => clonePixelImage(img),
},
{
id: "png-to-rgb-values",
title: "PNG to RGB Values",
description:
"Lists every pixel as rgba(r, g, b, a), one image row per line.",
category: "convert",
params: [],
resultType: "text",
toText: (img) => imageToRgbValues(img),
},
{
id: "rgb-values-to-png",
title: "RGB Values to PNG",
description:
"Assembles an image from rgba(r, g, b, a) numbers. Set the width — height is computed automatically.",
category: "convert",
sourceMode: "text",
params: [
{
id: "width",
label: "Image width",
type: "number",
min: 1,
max: 10000,
step: 1,
default: 32,
},
],
runFromText: (text, p) =>
rgbValuesToImage(
text,
Math.trunc(num(p as Record<string, unknown>, "width")),
),
run: (img) => clonePixelImage(img),
},
{
id: "convert-png-to-jpg",
title: "Convert PNG to JPG",
description:
"Transparency is composited over the chosen backdrop color (white by default) and saved as JPEG.",
category: "convert",
params: [
{
id: "background",
label: "Backdrop color",
type: "color",
default: "#ffffff",
},
{
id: "quality",
label: "JPEG quality",
type: "slider",
min: 1,
max: 100,
step: 1,
default: 90,
},
],
output: {
mime: "image/jpeg",
ext: "jpg",
qualityParamId: "quality",
},
run: (img, p) => flattenOntoColor(img, str(p, "background")),
},
{
id: "convert-png-to-webp",
title: "Convert PNG to WebP",
description:
"Re-encodes the image into WebP with adjustable quality. Transparency is preserved.",
category: "convert",
params: [
{
id: "quality",
label: "WebP quality",
type: "slider",
min: 1,
max: 100,
step: 1,
default: 90,
},
],
output: {
mime: "image/webp",
ext: "webp",
qualityParamId: "quality",
},
run: (img) => clonePixelImage(img),
},
{
id: "compress-png",
title: "Compress PNG",
description:
"Shrinks the PNG by reducing its palette to a preset level. Honest trade-off: fewer colors = smaller file.",
category: "convert",
params: [
{
id: "level",
label: "Compression level",
type: "select",
default: "balanced",
options: [
{ value: "light", label: "Light (192 colors)" },
{ value: "balanced", label: "Balanced (96 colors)" },
{ value: "strong", label: "Strong (44 colors)" },
{ value: "extreme", label: "Extreme (16 colors)" },
],
},
],
run: (img, p) => {
const level = str(p, "level") as CompressionLevel;
const k = COMPRESSION_LEVELS[level] ?? COMPRESSION_LEVELS.balanced;
return quantizeImage(img, k).image;
},
},
{
id: "reduce-to-size-png",
title: "Reduce PNG to Size",
description:
"Binary-searches the palette size until the encoded PNG fits the target KB. Best effort: if even 2 colors exceed the target, returns the 2-color version.",
category: "convert",
domOnly: true,
params: [
{
id: "targetKB",
label: "Target size, KB",
type: "slider",
min: 5,
max: 2000,
step: 5,
default: 100,
},
{
id: "maxColors",
label: "Max colors to try",
type: "slider",
min: 2,
max: 256,
step: 1,
default: 256,
},
],
run: async (img, p) => {
const targetBytes = num(p, "targetKB") * 1024;
const maxK = num(p, "maxColors");
const encodeSize = async (k: number): Promise<number | null> => {
const blob = await encode(quantizeImage(img, k).image, "image/png");
return blob.size;
};
const k = await findMaxColorsWithin(targetBytes, maxK, encodeSize);
return quantizeImage(img, k).image;
},
},
{
id: "svg-to-png",
title: "SVG to PNG",
description:
"Decodes SVG markup into a raster image. Paste the SVG code on the left.",
category: "convert",
sourceMode: "text",
params: [
{
id: "width",
label: "Result width, px",
type: "number",
min: 1,
max: 10000,
step: 1,
default: 512,
},
],
runFromText: (text, p) =>
decodeSvgText(text, Math.trunc(num(p, "width"))),
run: (img) => clonePixelImage(img),
},
];
}