科技微讯

手写的 Blog

lobste 看到一个帖子,人们分享了一个全手写的 blog

博主用一个电子墨水屏的设备手写了文章,然后导出为 png,有趣的是添加超链接的方式。作者提到他不是很满意 png 的体积,有人建议他参考这篇文章优化图片体积,文章的代码都在这个 repo

文章提到一个 least significant bits 的概念,一个颜色由 rgb 三色组成,每个颜色都是一个 0-255 的数字,其对应的二进制数字中,最后一个数字就是 LSB。文章提到为了拿到手写扫描图片的背景色的主要颜色值,作者把这些颜色的 rgb 通道的最后两个 bit 统一修改为 0。

修改一个颜色某个通道的 LSB,人眼几乎察觉不出来。把最后两个 bit 都修改为零的方法如下:

const decimal = 128;
const _decimal = decimal >> 2;
const __decimal = _decimal << 2;

下面的代码可以对比修改最后 2 个 bit 后图片颜色的变化,肉眼几乎看不出来:

const { createCanvas, loadImage, createImageData } = require("canvas");
const fs = require("fs");
const sizeOf = require("image-size");

const path = "./image.png";
const size = sizeOf(path);

const canvas = createCanvas(size.width, size.height);
const ctx = canvas.getContext("2d");
loadImage(path).then((image) => {
  ctx.drawImage(
    image,
    0,
    0,
    size.width,
    size.height,
    0,
    0,
    size.width,
    size.height
  );
  const imageData = ctx.getImageData(0, 0, size.width, size.height);
  for (let i = 0; i < imageData.data.length; i++) {
    const decimal = imageData.data[i];
    const _d = decimal >> 2;
    const __d = _d << 2;
    imageData.data[i] = __d;
  }
  const data = createImageData(imageData.data, size.width);
  const canvas2 = createCanvas(size.width, size.height);
  const ctx2 = canvas2.getContext("2d");
  ctx2.putImageData(data, 0, 0);
  const buffer = canvas2.toBuffer();
  fs.writeFileSync(`./out.${size.type}`, buffer, "binary");
});
暂无评论