mirror of
https://github.com/Ku6epXBOCTuK/easy-png-tools.git
synced 2026-09-14 13:36:36 +00:00
feat: add text tools
This commit is contained in:
@@ -85,7 +85,7 @@ export function stripDataUri(text: string): string {
|
|||||||
return m ? text.slice(m[0].length) : text.trim();
|
return m ? text.slice(m[0].length) : text.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function base64ToBytes(text: string): Uint8Array {
|
export function base64ToBytes(text: string): Uint8Array<ArrayBuffer> {
|
||||||
const clean = text.replace(/\s+/g, "");
|
const clean = text.replace(/\s+/g, "");
|
||||||
const binary = atob(clean);
|
const binary = atob(clean);
|
||||||
const bytes = new Uint8Array(binary.length);
|
const bytes = new Uint8Array(binary.length);
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import {
|
|||||||
rarityPredicate,
|
rarityPredicate,
|
||||||
renderPredicateMask,
|
renderPredicateMask,
|
||||||
} from "../core/masks";
|
} from "../core/masks";
|
||||||
|
import { hasTransparency, isGrayscale, orientationOf } from "../core/analyze";
|
||||||
|
import { encode } from "../core/io";
|
||||||
|
import { base64ToBytes, looksLikePng, stripDataUri } from "../core/textio";
|
||||||
|
|
||||||
interface ExtractColorParams {
|
interface ExtractColorParams {
|
||||||
color: string;
|
color: string;
|
||||||
@@ -176,6 +179,83 @@ const uniqueColorMask: ToolEntry<UniqueColorParams> = {
|
|||||||
run: (img, p) => renderMask(img, p, rarityPredicate(img, p.rarity)),
|
run: (img, p) => renderMask(img, p, rarityPredicate(img, p.rarity)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface NoParams {}
|
||||||
|
|
||||||
|
const emptySchema = toolSchema<NoParams>({});
|
||||||
|
|
||||||
|
const verifyIsPng: ToolEntry<NoParams> = {
|
||||||
|
id: "verify-is-png",
|
||||||
|
title: "Verify If Image Is a PNG",
|
||||||
|
description:
|
||||||
|
"Checks the signature of pasted base64 / data-uri content and reports whether it is a real PNG.",
|
||||||
|
category: "analyze",
|
||||||
|
schema: emptySchema,
|
||||||
|
input: "text",
|
||||||
|
result: "verdict",
|
||||||
|
textToText: (text) =>
|
||||||
|
looksLikePng(base64ToBytes(stripDataUri(text)))
|
||||||
|
? "Yes — valid PNG signature."
|
||||||
|
: "No — the content is not a PNG.",
|
||||||
|
};
|
||||||
|
|
||||||
|
const pngIsGrayscale: ToolEntry<NoParams> = {
|
||||||
|
id: "png-is-grayscale",
|
||||||
|
title: "Check: is PNG grayscale?",
|
||||||
|
description: "Reports whether the image consists only of shades of gray.",
|
||||||
|
category: "analyze",
|
||||||
|
schema: emptySchema,
|
||||||
|
result: "verdict",
|
||||||
|
toText: (img) =>
|
||||||
|
isGrayscale(img) ? "Yes — grayscale." : "No — contains colors.",
|
||||||
|
};
|
||||||
|
|
||||||
|
const pngFileSize: ToolEntry<NoParams> = {
|
||||||
|
id: "png-file-size",
|
||||||
|
title: "PNG File Size",
|
||||||
|
description: "Encodes the image as PNG and reports the resulting file size.",
|
||||||
|
category: "analyze",
|
||||||
|
schema: emptySchema,
|
||||||
|
domOnly: true,
|
||||||
|
result: "verdict",
|
||||||
|
toText: async (img) => {
|
||||||
|
const blob = await encode(img, "image/png");
|
||||||
|
const kb = blob.size / 1024;
|
||||||
|
const kbText = kb >= 100 ? Math.round(kb).toString() : kb.toFixed(1);
|
||||||
|
return `${kbText} KB`;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const pngIsTransparent: ToolEntry<NoParams> = {
|
||||||
|
id: "png-is-transparent",
|
||||||
|
title: "Check: is PNG transparent?",
|
||||||
|
description:
|
||||||
|
"Reports whether the image contains transparent or semi-transparent pixels.",
|
||||||
|
category: "analyze",
|
||||||
|
schema: emptySchema,
|
||||||
|
result: "verdict",
|
||||||
|
toText: (img) =>
|
||||||
|
hasTransparency(img) ? "Yes — has transparency." : "No — fully opaque.",
|
||||||
|
};
|
||||||
|
|
||||||
|
const pngOrientation: ToolEntry<NoParams> = {
|
||||||
|
id: "png-orientation",
|
||||||
|
title: "PNG orientation",
|
||||||
|
description: "Reports whether it is portrait, landscape or square.",
|
||||||
|
category: "analyze",
|
||||||
|
schema: emptySchema,
|
||||||
|
result: "verdict",
|
||||||
|
toText: (img) => {
|
||||||
|
switch (orientationOf(img)) {
|
||||||
|
case "portrait":
|
||||||
|
return "Portrait";
|
||||||
|
case "landscape":
|
||||||
|
return "Landscape";
|
||||||
|
default:
|
||||||
|
return "Square";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const analyzeEntries = [
|
export const analyzeEntries = [
|
||||||
extractColor,
|
extractColor,
|
||||||
showTransparent,
|
showTransparent,
|
||||||
@@ -184,4 +264,9 @@ export const analyzeEntries = [
|
|||||||
lightPixelMask,
|
lightPixelMask,
|
||||||
darkPixelMask,
|
darkPixelMask,
|
||||||
uniqueColorMask,
|
uniqueColorMask,
|
||||||
|
verifyIsPng,
|
||||||
|
pngIsGrayscale,
|
||||||
|
pngFileSize,
|
||||||
|
pngIsTransparent,
|
||||||
|
pngOrientation,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,7 +1,20 @@
|
|||||||
import type { ToolEntry } from "./types";
|
import type { ToolEntry } from "./types";
|
||||||
import { field, toolSchema } from "../registry-schema";
|
import { field, toolSchema } from "../registry-schema";
|
||||||
import { flattenOntoColor } from "../core/alpha";
|
import { flattenOntoColor } from "../core/alpha";
|
||||||
|
import {
|
||||||
|
base64ToBytes,
|
||||||
|
bytesToImage,
|
||||||
|
imageToByteRows,
|
||||||
|
imageToRgbValues,
|
||||||
|
rgbValuesToImage,
|
||||||
|
stripDataUri,
|
||||||
|
} from "../core/textio";
|
||||||
|
import { hexToPixels, pixelsToHex } from "../core/text";
|
||||||
import { clonePixelImage } from "../core/types";
|
import { clonePixelImage } from "../core/types";
|
||||||
|
import { decodeBytes, decodeSvgText, toBase64, toDataUrl } from "../core/io";
|
||||||
|
|
||||||
|
const widthProps = (defaultValue: number) =>
|
||||||
|
field.number({ min: 1, max: 10000, step: 1, default: defaultValue });
|
||||||
|
|
||||||
interface ConvertToJpgParams {
|
interface ConvertToJpgParams {
|
||||||
background: string;
|
background: string;
|
||||||
@@ -58,4 +71,175 @@ const convertToBmp: ToolEntry<ConvertToBmpParams> = {
|
|||||||
output: { mime: "image/bmp", ext: "bmp" },
|
output: { mime: "image/bmp", ext: "bmp" },
|
||||||
};
|
};
|
||||||
|
|
||||||
export const convertEntries = [convertToJpg, convertToWebp, convertToBmp];
|
interface NoParams {}
|
||||||
|
|
||||||
|
const emptySchema = toolSchema<NoParams>({});
|
||||||
|
|
||||||
|
const pngToBase64: ToolEntry<NoParams> = {
|
||||||
|
id: "png-to-base64",
|
||||||
|
title: "PNG to Base64",
|
||||||
|
description:
|
||||||
|
"Encodes the image into a base64 string for embedding in code or styles.",
|
||||||
|
category: "convert",
|
||||||
|
schema: emptySchema,
|
||||||
|
result: "text",
|
||||||
|
toText: (img) => toBase64(img),
|
||||||
|
};
|
||||||
|
|
||||||
|
const pngToDataUri: ToolEntry<NoParams> = {
|
||||||
|
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",
|
||||||
|
schema: emptySchema,
|
||||||
|
result: "text",
|
||||||
|
toText: (img) => toDataUrl(img),
|
||||||
|
};
|
||||||
|
|
||||||
|
const pngToHex: ToolEntry<NoParams> = {
|
||||||
|
id: "png-to-hex",
|
||||||
|
title: "PNG to HEX pixels",
|
||||||
|
description:
|
||||||
|
"Shows all pixels as rrggbbaa hex values — row by row, space separated.",
|
||||||
|
category: "convert",
|
||||||
|
schema: emptySchema,
|
||||||
|
result: "text",
|
||||||
|
toText: (img) => pixelsToHex(img),
|
||||||
|
};
|
||||||
|
|
||||||
|
const pngToBytes: ToolEntry<NoParams> = {
|
||||||
|
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",
|
||||||
|
schema: emptySchema,
|
||||||
|
result: "text",
|
||||||
|
toText: (img) => imageToByteRows(img),
|
||||||
|
};
|
||||||
|
|
||||||
|
const pngToRgbValues: ToolEntry<NoParams> = {
|
||||||
|
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",
|
||||||
|
schema: emptySchema,
|
||||||
|
result: "text",
|
||||||
|
toText: (img) => imageToRgbValues(img),
|
||||||
|
};
|
||||||
|
|
||||||
|
const base64ToPng: ToolEntry<NoParams> = {
|
||||||
|
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",
|
||||||
|
schema: emptySchema,
|
||||||
|
input: "text",
|
||||||
|
runFromText: async (text) => decodeBytes(base64ToBytes(stripDataUri(text))),
|
||||||
|
};
|
||||||
|
|
||||||
|
const dataUriToPng: ToolEntry<NoParams> = {
|
||||||
|
id: "data-uri-to-png",
|
||||||
|
title: "Data URI to PNG",
|
||||||
|
description: "Decodes data:image/…;base64,… back into an image file.",
|
||||||
|
category: "convert",
|
||||||
|
schema: emptySchema,
|
||||||
|
input: "text",
|
||||||
|
runFromText: async (text) => decodeBytes(base64ToBytes(stripDataUri(text))),
|
||||||
|
};
|
||||||
|
|
||||||
|
interface HexToPngParams {
|
||||||
|
width: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hexToPngSchema = toolSchema<HexToPngParams>({
|
||||||
|
width: widthProps(1),
|
||||||
|
});
|
||||||
|
|
||||||
|
const hexToPng: ToolEntry<HexToPngParams> = {
|
||||||
|
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",
|
||||||
|
schema: hexToPngSchema,
|
||||||
|
input: "text",
|
||||||
|
runFromText: (text, p) => hexToPixels(text, Math.trunc(p.width)),
|
||||||
|
};
|
||||||
|
|
||||||
|
interface BytesToPngParams {
|
||||||
|
width: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const bytesToPngSchema = toolSchema<BytesToPngParams>({
|
||||||
|
width: widthProps(32),
|
||||||
|
});
|
||||||
|
|
||||||
|
const bytesToPng: ToolEntry<BytesToPngParams> = {
|
||||||
|
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",
|
||||||
|
schema: bytesToPngSchema,
|
||||||
|
input: "text",
|
||||||
|
runFromText: (text, p) => bytesToImage(text, Math.trunc(p.width)),
|
||||||
|
};
|
||||||
|
|
||||||
|
interface RgbValuesToPngParams {
|
||||||
|
width: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const rgbValuesToPngSchema = toolSchema<RgbValuesToPngParams>({
|
||||||
|
width: widthProps(32),
|
||||||
|
});
|
||||||
|
|
||||||
|
const rgbValuesToPng: ToolEntry<RgbValuesToPngParams> = {
|
||||||
|
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",
|
||||||
|
schema: rgbValuesToPngSchema,
|
||||||
|
input: "text",
|
||||||
|
runFromText: (text, p) => rgbValuesToImage(text, Math.trunc(p.width)),
|
||||||
|
};
|
||||||
|
|
||||||
|
interface SvgToPngParams {
|
||||||
|
width: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const svgToPngSchema = toolSchema<SvgToPngParams>({
|
||||||
|
width: widthProps(512),
|
||||||
|
});
|
||||||
|
|
||||||
|
const svgToPng: ToolEntry<SvgToPngParams> = {
|
||||||
|
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",
|
||||||
|
schema: svgToPngSchema,
|
||||||
|
input: "text",
|
||||||
|
domOnly: true,
|
||||||
|
runFromText: (text, p) => decodeSvgText(text, Math.trunc(p.width)),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const convertEntries = [
|
||||||
|
convertToJpg,
|
||||||
|
convertToWebp,
|
||||||
|
convertToBmp,
|
||||||
|
pngToBase64,
|
||||||
|
pngToDataUri,
|
||||||
|
pngToHex,
|
||||||
|
pngToBytes,
|
||||||
|
pngToRgbValues,
|
||||||
|
base64ToPng,
|
||||||
|
dataUriToPng,
|
||||||
|
hexToPng,
|
||||||
|
bytesToPng,
|
||||||
|
rgbValuesToPng,
|
||||||
|
svgToPng,
|
||||||
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user