文件与图片互转

最近有个想法,将文本转换成图片像素,会是个什么样子的。

为什么会有这样的想法?因为很久之前就发现像素图片是由 rgb 或者 rgba 构成像素组成的。每一个色素的范围是 $[0,255]$,刚好是$2^8=256$。而 unicode 恰好又是 6 位 16 进制表示的,那么’0xff’刚好又是 255。

1
parseInt('ff',16) // 255

所以我们可以将文字转为 unicode 后,平分为三分,分别就是 r,g,b。构成一个像素。

理论可行,开始操作。

将文字转为 16 进制

1
2
'中'.charCodeAt(0).toString(16).padStart(6, "0");
// '004e2d'

这样子我们就能切割出 rgb 了。

1
const [Red, Green, Blue] = [parseInt(bit16.slice(0, 2), 16), parseInt(bit16.slice(2, 4), 16), parseInt(bit16.slice(4, 6), 16)];

保存为 png 文件

这里使用现成的 pngjs,新建实例化对象时,需要传入长宽数据。

最简单的方法是获取到所有字符的个数,开方后,向上取整得到宽和高

1
const size = Math.ceil(Math.sqrt(book.length));

初始化

1
2
3
4
5
const png = new PNG({
filterType: -1,
width: size,
height: size
});

因为使用的 png,有 Alpha 通道,即透明度,所以一个像素占用 4 个 byte。

1
2
3
4
5
6
7
8
9
10
11
for (let x = 0; x < size; x++) {
for (let y = 0; y < size; y++) {
const bit16 = book[x * size + y] ? book[x * size + y].charCodeAt(0).toString(16).padStart(6, "0") : "000000";
const [Red, Green, Blue] = [parseInt(bit16.slice(0, 2), parseInt(bit16.slice(2, 4), 16), parseInt(bit16.slice(4, 6), 16)];
const idx = (size * x + y) << 2;
png.data[idx] = Red;
png.data[idx + 1] = Green;
png.data[idx + 2] = Blue;
png.data[idx + 3] = (Green === 0 && Blue === 0) ? 0 : 255;
}
}

最后保存图片

1
png.pack().pipe(fs.createWriteStream(pngPath));

png 转 txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
fs.createReadStream(pngPath)
.pipe(
new PNG({
filterType: -1
})
)
.on("parsed", function() {
let bookData = "";
for (let x = 0; x < this.height; x++) {
for (let y = 0; y < this.width; y++) {
const idx = (this.width * x + y) << 2;
if (this.data[idx + 3] === 0) {
fs.writeFile(textPath, bookData, (err, data) => {
if (err) {
console.log(err);
}
resolve(bookData);
});
return;
}
const unicode = `00${(this.data[idx + 1]).toString(16).padStart(2, 0)}${(this.data[idx + 2]).toString(16).padStart(2, 0)}`;
bookData += String.fromCharCode(parseInt(unicode, 16));
}
}
});
});

优化

查一下常用的中文 unicode 编码,高 2 位其实都是”00”,如果确定是存中文和英文,其实一个像素能存下两个字符。

高 4 位一个字符,低 4 位一个字符。这样图片的宽高就会缩小一倍。不过这样的话,png 转 txt 的模块代码也要做相应的修改。


文件与图片互转
https://bubao.github.io/posts/7819d140.html
作者
一念
发布于
2021年11月1日
许可协议