惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
LINUX DO - 最新话题
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Forbes - Security
Forbes - Security
博客园 - 司徒正美
Hugging Face - Blog
Hugging Face - Blog
W
WeLiveSecurity
Jina AI
Jina AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
N
News and Events Feed by Topic
V
V2EX
Stack Overflow Blog
Stack Overflow Blog
Engineering at Meta
Engineering at Meta
PCI Perspectives
PCI Perspectives
Martin Fowler
Martin Fowler
T
The Exploit Database - CXSecurity.com
F
Full Disclosure
WordPress大学
WordPress大学
S
Security Affairs
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
S
SegmentFault 最新的问题
P
Privacy International News Feed
IT之家
IT之家
M
MIT News - Artificial intelligence
G
GRAHAM CLULEY
Hacker News: Ask HN
Hacker News: Ask HN
D
DataBreaches.Net
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
C
Check Point Blog
美团技术团队
Security Latest
Security Latest
Cyberwarzone
Cyberwarzone
N
News and Events Feed by Topic
MyScale Blog
MyScale Blog
H
Help Net Security
宝玉的分享
宝玉的分享
The Hacker News
The Hacker News
The Last Watchdog
The Last Watchdog
The Cloudflare Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
爱范儿
爱范儿
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
I
Intezer
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
AI
AI
I
InfoQ
N
News | PayPal Newsroom
TaoSecurity Blog
TaoSecurity Blog

云游君的小站

开源项目的「死与新生」 没有红包封面,但是 AI 春联…… 家·烟花·红包封面 云乐坊工作室的成立与缘起与有关的话 聊聊四元数与万向锁及其实际意义 从零开始写一个 Web Component - GitHub Corners 旋转吧!徽章! 又拍云—年轻人的第一个 CDN 云空调,便携小空调 nnrm - 一个极简的 npm/yarn registry 切换管理器 做猪呢,最重要的是开心 从 Vite 与 Vue 开始的 D3 数据可视化之旅 如何找到你朋友的社交账号 写写高斯模糊——从 CSS 模糊滤镜的白边说起 如何从 Valine 迁移至 Disqus ADV 游戏引擎计划 关于我打算当老师并报考教师资格证这件事 Strato - Hexo 主题「Yun」版本宣传 PV 我与小镇与家 el-bot & mirai-ts 制作笔记 第三方评论系统之我见 人生不是一场马拉松 👴就是二次元,故尝试证明。 教你如何从零开始搭建一个属于自己的网站 使用 CDN 加速你的 GitHub Pages 网站 使用 CCDIK 或 FABRIK 实现逆向动力学 【转】三维文件格式知多少 【译】30 分钟学会 LaTeX LaTeX 使用笔记 在 macOS 下配置 OpenGL 路漫漫其修远兮 CSS 陷阱 Blender 学习笔记 Everyday Auto Xuexiqiangguo 酷 Q 使用笔记 Deepin 使用笔记 塞翁失马焉知非福 hexo-theme-yun 制作笔记 写给可爱的学弟学妹们 北线无战事 让百度收录你的 GitHub Pages 博客 搭建自己的 Minecraft 服务器 导出「你的日记」与导入「一本日记」 从来如此 卷土重来未可知 恋爱证明记 微信与象棋 关于部落冲突的二三事儿(番外)-端午事变 Travis-CI 持续集成部署 Vue 中 canvas 的自适应 大家一起吃火锅吧 Parcel.js + Vue 搭建笔记 Vue 学习笔记 【动画电影】《声之形》观后感 VS Code 配置笔记 仓生 YunYouJun/give-me-money 永远相信美好的事情即将发生 鱼与熊掌 人生本该如此。 Discourse 新一代开源论坛 Hexo 静态博客搭建笔记 Coding WebIDE 云端开发实验室 npm & yarn 常用包与命令 像夏花一样绚烂 【番剧】《月色真美》(老夫的少女心啊) 临摹一只智障女神∠( ᐛ 」∠)_ 南京之旅-记10th计算机设计大赛 Git 学习笔记 Laravel 使用笔记 Wordpress 的实用插件与主题推荐 【定格动画】交换/EXchange 我与幻星的故事 来自某夏令营的回忆 水彩原创头像尝试 云游君表情包制作计划 小说连载初尝试-《阿庫娅的星球》 仓鼠 回声 【分享】网页背景效果插件 Canvas-Nest.js 【花开物语|MAD】幹物女(WeiWei)-Bonboru! 太空 关于部落冲突的二三事儿-2 关于部落冲突的二三事儿-1 关于部落冲突的二三事儿-序
char-dust 一个图片转字符画的 npm 包与示例站点
☁️ · 2021-03-13 · via 云游君的小站
夹心酱

如题,它的全部作用就是将图片变成字符画(又称 ASCII 艺术)。

似乎有些老生常谈,那么为什么会有它的诞生呢?

npm

有一部电影叫做「星尘 Stardust」,名字挺酷。

  • 星尘龙(游戏王) Stardust Dragon
  • 星尘斗士(JOJO) Stardust Crusaders
  • 「与星尘握手」 命运石之门

字符(char)+ 尘埃(dust)= 字尘(char-dust)

「星尘」是恒星死亡时在太空中形成微小颗粒般的固体物质,它们飘散在宇宙中,继续碰撞、凝结,甚至会因此诞生出新的恒星。

是死亡,也是新生。既渺小,又伟大。

我相当喜欢这个名字,也因此将其命名为 char-dust

那么乍看似乎已经有些被玩烂的东西,为啥又要重复造轮子呢?(当然其实最重要的原因在后话里。)

Features ​

  • 可自定义的图片大小
  • 可自定义的字符串
  • 线上方便快捷
    • 可自定义缩放 textarea
    • 方便全选复制
  • 兼容 node 与 browser 的 npm 包
  • TypeScript 类型

bash

npm install char-dust

首先,虽然各类语言都能实现类似的效果,但是想要拿到前端展示,那么必须得用万能的 JavaScript,其次想要使其变成方便使用且带声明的包,就得用无敌的 TypeScript。

Google 甚至还有一个专门的 repo gif-for-cli

思路 ​

虽然有把过程步骤详细介绍讲解的想法,但苦于杂务繁多,不妨鸽到日后再说(没错,我就是懒)。

思路其实很简单,将图片读到 canvas 上,获取 ImageData,读取像素,通过 RGB 计算出灰度(亮度)。

RGB 转灰度有一个专门的心理学公式(至于为什么就只能请您移步 Grayscale 了)

R⋅0.299+G⋅0.587+B⋅0.114=BrightnessR \cdot 0.299 + G \cdot 0.587 + B \cdot 0.114 = Brightness

代码写久了,会有一种想要将各功能都抽象的强迫症。专门处理色彩的类库也必然是有的,于是我改为使用 tinycolor 获取亮度。

拿到亮度后,我们再定义一串字符串来分配给不同的亮度。譬如从暗到亮分别为 @#&$%863!i1uazvno~;*^+-. 。(当然其他也完全可以)

均分亮度,得到不同等级,根据每个像素分配对于亮度级别的字符即可。

此外,图片很大的时候,对每个像素处理无疑是很慢的,我们可以设置一个字符宽度来跳着处理,间隔的像素则可以忽略,毕竟已经转成字符了,精度早就下降没了。(高度同理)

但我的目的并不是仅仅放到前端展示,我希望它在 node 端也能即时地读取图片并转换。

为什么呢,因为我最近打算整一个终端的文字冒险游戏,可能会成为 ADV 游戏引擎计划 的一些试水,而在终端回车显示对话,选项,偶尔用字符串来展示图片应该也会是比较酷的事情,当然这就是他话了。

对于 Node 来说,并没有 document 的存在,当然也就没有 canvasImageData,但是我们可以通过 node-canvas 来实现。

node-canvas 是使用 C++ 原生编写,再打包交由 Node 调用,因此需要安装 node-pre-gyp,而这家伙可以说是「臭名昭著」了,国内的安装速度极为缓慢,还未必成功。

面向用户的产物,不能期望每个人都能成功安装使用它,所以我们应该寻求其他更方便可靠的方式。

我最后找到的方案则是 jimp + @canvas/image-data

jimp 是纯粹使用 JavaScript 编写的图片处理库,与原生性能的差距也完全可以容忍。

当我们想要在 Node 端运行时,只需要再安装 jimp@canvas/image-data 便可。 在国内镜像的加持下,也无需担心。

既然说到这了,就顺带再打个 nnrm 的广告。nnrm - 一个极简的 npm/yarn registry 切换管理器

jimp 读取图像数据,@canvas/image-data 负责将其转化为标准的 ImageData,再交给 char-dust

bash

yarn add jimp @canvas/image-data

typescript

import { resolve } from 'node:path'
import ImageData from '@canvas/image-data'
import { imageToText } from 'char-dust'
import jimp from 'jimp'

jimp.read(resolve(__dirname, './cat-of-the-rebellion.jpg')).then((image) => {
  image.scale(5)
  const imageData = new ImageData(
    Uint8ClampedArray.from(image.bitmap.data),
    image.bitmap.width,
    image.bitmap.height
  )

  const text = imageToText(imageData)
  console.log(text)
})

万事大吉。

其他则是细节的处理,效率优化,UI 样式,图片缩放,打包,node 端的兼容之类的。

实现 ​

five-year

这其实是我三年前开的坑,🐦,咕咕咕,没错我就是鸽子,但我还是好好地填上了。

准备迎接夸奖

所以重构的时候,直接将原先的 vue2 + @vue/cli + webpack + element-ui(2) 换成了 vue3 + vite + element-plus(3)

看起来好像和 element 还有点不一样?

那是因为我用了独家的极简主题 element-theme-ink

也是三年前开的坑,没想到换成 Vue3 + Element3 也还能用,最近用 Vuepress 重写了遍文档,以前的网站还是用 Webpack 搭的。那时 Vuepress 还没诞生,现在却连 Vuepress 都要用 TypeScript 重构了,有种物是人非的感觉。

后话 ​

在动工前,我也检索了是否已有满足上述需求的类似产物存在,但很遗憾我并没有发现。

相关性最大且 Star 最多的一个项目是 jscii

早在三年前我提了一个 Issue: Suggestion: How about packaging it into a library?

作者则告诉我这是他六年前写的项目,那时候 npm 还不算个东西。(我的蹩脚翻译)不过他答应说会在关闭 Issue 前 publish 一个包。(但是直到三年后的今天,它还是 Open 的。)

three-years-ago.jpg

三年前的某一天我也曾决定自己尝试实现一下这样的程序,只是最后也和 JSCII 作者一样因鸽子的天性而就此遗忘了。

而直到前几日,我才终于再次将其捡起,并下定决心完成它。

那么这个原因到底是什么呢?大致可以类比于雄性织巢鸟需要建造精美的巢穴用以吸引异性。

所以三年后的我终于完成了它,因为「这是计划的一部分」。


只是当我在 VSCode 里勤勤恳恳时,几小时前我尝试安装的 VSCode 彩虹屁插件 突然蹦出了一句话,「你这么喜欢写代码,一定没有女朋友吧」。

让人不禁潸然泪下。

别骂了别骂了再骂人要傻了

Q.E.D.