引言

看到酷安上有这样一个活动,萌生了用 C# 生成字符画的想法,先放出原图。

 
酷安手绘牛啤
 
 

§1 黑白

将图像转换成字符画在 C# 中很简单,思路大致如下:

  1. 加载图像,逐像素提取明度。
  2. 根据明度映射到字符列表中对应的字符。
  3. 输出字符。

GetChars函数负责将传入的图像按一定比例导出字符画的字符串。hScale为横向比例,即每次跳过的横向像素数;vScale为纵向比例,在控制台中输出推荐为hScale的 2 倍。

private static string GetChars(Bitmap bmp, int hScale, int vScale)
{
StringBuilder sb = new StringBuilder();
for (int h = 0; h < bmp.Height; h += vScale)
{
for (int w = 0; w < bmp.Width; w += hScale)
{
Color color = bmp.GetPixel(w, h);
float brightness = color.GetBrightness(); // 这里的明度也可以使用 RGB 分量合成
char ch = GetChar(brightness);
sb.Append(ch);
}
sb.AppendLine();
}
return sb.ToString();
}

GetChar负责做明度到字符的映射工作,由于brightness取值范围为 [0, 1],所以需要乘 0.99 防止index越界。listChar是可用的字符列表,自定义只需遵循一条规则,从左往右字符应该越来越复杂。

private static readonly List<char> listChar =
new List<char>() { ' ', '^', '+', '!', '$', '#', '*', '%', '@' };
private static char GetChar(float brightness)
{
int index = (int)(brightness * 0.99 * listChar.Count);
return listChar[index];
}

调用函数,输出结果。初具雏形,黑白样式减少了不少神韵。

 
 

§2 有限彩色

2.1 Console

一开始希望通过改变Console.ForegroundColor属性来改变色彩,但是残酷的事实是这个属性只接受ConsoleColor枚举中的 16 个颜色。将全彩图片映射成 16 色输出,费力不讨好,遂求其他方法。

2.2 Colorful.Console

找到了一个彩色控制台的库 Colorful Console。看网页介绍挺厉害的,RGB、渐变色、多色输出……妥了,这肯定符合我们的需要,通过 nuget 可以直接添加到项目中。

在引用区域加一行,就可以把代码中的ConsoleColorfulConsole替代。

using Console = Colorful.Console;

GetChars函数需要改变一下,因为每个字符的颜色不同,所以要在函数里面增加输出。好简单,输出内容后面加个颜色的参数就可以了。

private static string GetChars(Bitmap bmp, int hScale, int vScale, bool shouldDraw)
{
StringBuilder sb = new StringBuilder();
for (int h = 0; h < bmp.Height; h += vScale)
{
for (int w = 0; w < bmp.Width; w += hScale)
{
Color color = bmp.GetPixel(w, h);
float brightness = color.GetBrightness();
char ch = GetChar(brightness);
if (shouldDraw)
{
Console.Write(ch, color);
}
sb.Append(ch);
}
if (shouldDraw) { Console.WriteLine(); }
sb.AppendLine();
}
return sb.ToString();
}

然而现实再一次残酷起来,输出结果一片黑,使用白色背景看一看。

 
 

可能看不清,不过牛角的位置确实有几个字符不是黑色,那我们换张图片来看。可以看到确实有彩色输出,不过效果尚可的仅限最前面的一些字符,之后白色完全不见了。

 
 

在测试官网上的操作都没有问题后,我陷入了深深的思考,NMD,为什么?直到我看到了官网上最下面的一段话。

Colorful.Console can only write to the console in 16 different colors (including the black that's used as the console's background, by default!) in a single console session. This is a limitation of the Windows console itself (ref: MSDN), and it's one that I wasn't able to work my way around. If you know of a workaround, let me know!

Colorful.Console只能同时输出 16 种颜色,果然原版Console能接受的ConsoleColor枚举也是 16 种颜色是算计好的。可恶,难道只能到此为止了吗?

我不甘心。

§3 全彩

终于,我找到了这个 visual studio - Custom text color in C# console application? - Stack Overflow。在下面 Alexei Shcherbakov 和 Olivier Jacot-Descombes 的回答中,我看到了希望。

Since Windows 10 Anniversary Update, console can use ANSI/VT100 color codes

You need set flag ENABLE_VIRTUAL_TERMINAL_PROCESSING(0x4) by SetConsoleMode

Use sequences:

"\x1b[48;5;" + s + "m" - set background color by index in table (0-255)

"\x1b[38;5;" + s + "m" - set foreground color by index in table (0-255)

"\x1b[48;2;" + r + ";" + g + ";" + b + "m" - set background by r,g,b values

"\x1b[38;2;" + r + ";" + g + ";" + b + "m" - set foreground by r,g,b values

Important notice: Internally Windows have only 256 (or 88) colors in table and Windows will used nearest to (r,g,b) value from table.

有了这个神奇的ENABLE_VIRTUAL_TERMINAL_PROCESSING(0x4),就可以随意修改前后景颜色了。说干就干,首先需要增加一个NativeMethods类,用来 Call kernel32.dll里的 3 个函数。

using System;
using System.Runtime.InteropServices; namespace Img2ColorfulChars
{
internal class NativeMethods
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetConsoleMode(IntPtr hConsoleHandle, int mode); [DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetConsoleMode(IntPtr handle, out int mode); [DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetStdHandle(int handle);
}
}

然后在主程序Main函数里一开始增加以下三行,-11代表STD_OUTPUT_HANDLE(GetStdHandle function - Windows Console | Microsoft Docs), 0x4就是上面所说的ENABLE_VIRTUAL_TERMINAL_PROCESSING

var handle = NativeMethods.GetStdHandle(-11);
NativeMethods.GetConsoleMode(handle, out int mode);
NativeMethods.SetConsoleMode(handle, mode | 0x4);

因为我们要修改的是字符的前景色,所以把上一节中GetChars函数里的

Console.Write(ch, color);

替换为

Console.Write($"\x1b[38;2;{color.R};{color.G};{color.B}m{ch}");

输出结果如下,完美。

 
 

尾声

多彩的细节,巧妙的象征,这就是青春啊(不是)。

而这个项目真正的用法:

 
 

项目链接

推荐阅读

作者:Kabuto_W
链接:https://www.jianshu.com/p/8a083421c11d
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

来自多彩世界的控制台——C#控制台输出彩色字符画的更多相关文章

  1. [笔记]Go语言在Linux环境下输出彩色字符

    Go语言要打印彩色字符与Linux终端输出彩色字符类似,以黑色背景高亮绿色字体为例: fmt.Printf("\n %c[1;40;32m%s%c[0m\n\n", 0x1B, & ...

  2. c++ 在控制台用 wcout输出宽字符的问题

    在我的电脑上要想通过 std::wcout输出 宽字符 需加入以下代码 #include <io.h> #include <fcntl.h> void main() { _se ...

  3. echo 输出彩色字符

    借助echo的-e选项来实现,语法格式为 echo -e "\033[3xmsome things you want to print out.\033[0m" \033[3xm为 ...

  4. 如何在浏览器控制台(console)里输出彩色样式调试信息

    console.log(XX,XX,XX) log 的第一个参数声明第二.第三个参数的作用,第二个参数就是样式,第三个参数是要输出的字符串 console.log("%c%s", ...

  5. Python同时向控制台和文件输出日志logging的方法 Python logging模块详解

    Python同时向控制台和文件输出日志logging的方法http://www.jb51.net/article/66756.htm 1 #-*- coding:utf-8 -*- 2 import ...

  6. Java 控制台输入数字 输出乘法表(代码练习)

    最近,回忆了一些刚学习Java时经常练习的一些小练习题.感觉还是蛮有趣的,在回顾时想起好多学习时的经历和坎坷,一道小小的练习题要研究半天,珍重过往,直面未来.下面贡献代码,Java 控制台输入数字 输 ...

  7. 双缓冲解决控制台应用程序输出“闪屏”(C/C++,Windows)

    使用 C 语言编写游戏的小伙伴们想必起初都要遇到这样的问题,在不断清屏输出数据的过程中,控制台中的输出内容会不断地闪屏.出现这个问题的原因是程序对数据处理花掉的时间影响到了数据显示,或许你可以使用局部 ...

  8. 改变 C/C++ 控制台程序的输出颜色和样式

    我们经常可以看见Linux自带终端下的许多程序都输出了不同颜色和底纹的字体.最近也想要自己实现一下这种效果,方法是在输出流中插入占位符\033[***. 我从网上收集了一些常用的控制语句,并用以下代码 ...

  9. VC printf输出彩色字体

    在VC下使用SetConsoleTextAttribute()函数可以改变当前控制台的前景色和背景色,从而达到输出彩色字体的效果. 使用的方法也很简单,具体代码如下: #include <win ...

  10. 有趣的console.log(console.log输出彩色字,图片等)

    亲们支持我的新博客哦==>原文地址 ) 逛网站的时候经常发现很多网站控制台打印了很好玩的内容 比如我的网站 →calamus 或者知乎→ 平时是不是只用console调试或者打印别的信息了,没有 ...

随机推荐

  1. HarmonyOS:Neural Network Runtime对接AI推理框架开发指导

      场景介绍 Neural Network Runtime作为AI推理引擎和加速芯片的桥梁,为AI推理引擎提供精简的Native接口,满足推理引擎通过加速芯片执行端到端推理的需求. 本文以图1展示的A ...

  2. CentOS-6.4启动盘制作过程

    目标机器:ThinkPad X230 (i5-3210, 4G DDR3, 500G 7200转),预装win 8 目标系统:CentOS-6.4-x86_64-bin-DVD1.iso 主要参考文章 ...

  3. CentOS+Django+uWSGI+Celery+Supervisor配置

    目录 背景 目录 安装 配置Supervisor 1.生成配置文件 2. 修改配置文件 3. 创建进程文件 创建 uwsgi.conf 进程文件 创建celery进程文件 启动supervisor 启 ...

  4. 不常用的技能-【手动编译java类】

    jdk版本:1.7 冒号分割jar包,1.8 分号分割jar包 javac -classpath fastjson-1.2.24.jar:jedis-2.9.0.jar Test.javajava - ...

  5. 使用 Docker 部署 Draw.io 在线流程图系统

    1)介绍 Draw.io GitHub:https://github.com/jgraph/drawio Draw.io 是一款开源的绘制流程图的工具,拥有大量免费素材和模板.程序本身支持中文在内的多 ...

  6. PTA前三次题目集总结

    以下内容是我对PTA三次习题作业最后一题的思路,源码以及总结 学到的java知识大多都来自写题目集 这些题目对我对java的认知与学习起到了不小的帮助 答题判题程序-1 题目内容 设计实现答题程序,模 ...

  7. Flink 助力美团数仓增量生产

    简介: 本文由美团研究员.实时计算负责人鞠大升分享,主要介绍 Flink 助力美团数仓增量生产的应用实践.内容包括:1.数仓增量生产:2.流式数据集成:3.流式数据处理:4.流式 OLAP 应用:5. ...

  8. OpenKruise v0.9.0 版本发布:新增 Pod 重启、删除防护等重磅功能

    简介: OpenKruise 是阿里云开源的云原生应用自动化管理套件,也是当前托管在 Cloud Native Computing Foundation (CNCF) 下的 Sandbox 项目.它来 ...

  9. 让容器跑得更快:CPU Burst 技术实践

    ​简介:让人讨厌的 CPU 限流影响容器运行,有时人们不得不牺牲容器部署密度来避免 CPU 限流出现.我们设计的 CPU Burst 技术既能保证容器运行服务质量,又不降低容器部署密度.CPU Bur ...

  10. 数据智能构建管理平台Dataphin V2.9.4.3版本发布

    简介: Dataphin发布V2.9.4.3版本升级多项产品能力,该版本在产品功能和用户体验上都进行了优化和提升,旨在为用户提供更完善的产品能力和体验,以加速企业数据中台建设进程. -更多关于数智化转 ...