UNPKG

lsb-steganography

Version:

A coomand-line tool for encoding/decoding data via image.

67 lines (65 loc) 2.1 kB
import { writeFile } from "node:fs/promises"; import { Jimp } from "jimp"; //#region src/lib.ts const MASK_0F = 15; const MASK_F0 = 240; const MASK_FF = 255; async function encode(str, { input }) { const textEncoder = new TextEncoder(); const buffer = textEncoder.encode(str); let image; let width = 0; let height = 0; async function getJimpInstance() { if (typeof input === "string") return await Jimp.read(input); if (input instanceof ArrayBuffer) return Jimp.fromBuffer(input); } if (input) { const jimp = await getJimpInstance(); if (!jimp) throw new Error("Invalid input"); const size = jimp.width * jimp.height * 4; const pixelApset = Math.sqrt(size / (buffer.length * 2)); width = Math.ceil(jimp.width / pixelApset); height = Math.ceil(jimp.height / pixelApset); image = jimp.resize({ w: width, h: height }); } else { const Sqrt3Div2 = Math.sqrt(3 / 2); width = Math.ceil(Math.sqrt(buffer.length) / Sqrt3Div2); height = width; image = new Jimp({ color: 4042322160, width, height }); } for (let i = 0; i < buffer.length; i++) { image.bitmap.data[i * 2] = ((image.bitmap.data[i * 2] ?? MASK_FF) & MASK_F0) + (buffer[i] >> 4 & MASK_0F); image.bitmap.data[i * 2 + 1] = ((image.bitmap.data[i * 2 + 1] ?? MASK_FF) & MASK_F0) + (buffer[i] & MASK_0F); } for (let i = 2 * buffer.length; i < width * height * 4; i++) image.bitmap.data[i] = (image.bitmap.data[i] ?? MASK_FF) & MASK_F0; return { data: image.bitmap.data, async writeFile(path) { return image.write(`${path}.png`); } }; } async function decode(input) { const textDecoder = new TextDecoder("utf-8"); const jimpInput = typeof input === "string" ? await Jimp.read(input) : await Jimp.fromBuffer(input); const buffer = jimpInput.bitmap.data; const array = new Uint8Array(buffer.length); for (let i = 0; i < buffer.length; i += 2) array[i] = ((buffer[i] & MASK_0F) << 4) + (buffer[i + 1] & MASK_0F); const data = textDecoder.decode(array); return { data, writeFile(output) { return writeFile(data, output); } }; } //#endregion export { decode, encode };