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

推荐订阅源

有赞技术团队
有赞技术团队
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
P
Palo Alto Networks Blog
C
Cisco Blogs
The Hacker News
The Hacker News
T
Threatpost
S
Schneier on Security
K
Kaspersky official blog
Spread Privacy
Spread Privacy
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
NISL@THU
NISL@THU
量子位
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Google DeepMind News
Google DeepMind News
Security Latest
Security Latest
博客园 - 司徒正美
云风的 BLOG
云风的 BLOG
博客园 - 叶小钗
H
Hackread – Cybersecurity News, Data Breaches, AI and More
N
News and Events Feed by Topic
爱范儿
爱范儿
P
Proofpoint News Feed
C
CERT Recently Published Vulnerability Notes
Project Zero
Project Zero
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Cisco Talos Blog
Cisco Talos Blog
GbyAI
GbyAI
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Apple Machine Learning Research
Apple Machine Learning Research
T
Tenable Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
Vulnerabilities – Threatpost
Forbes - Security
Forbes - Security
博客园 - 三生石上(FineUI控件)
C
Cyber Attacks, Cyber Crime and Cyber Security
N
News and Events Feed by Topic
V
V2EX
Webroot Blog
Webroot Blog
The Register - Security
The Register - Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Blog — PlanetScale
Blog — PlanetScale
M
MIT News - Artificial intelligence
Scott Helme
Scott Helme
Simon Willison's Weblog
Simon Willison's Weblog
L
LangChain Blog
W
WeLiveSecurity
Cloudbric
Cloudbric

云游君的小站

开源项目的「死与新生」 没有红包封面,但是 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.