用C#开发程序进行ASCII艺术制作

news2025/1/16 8:10:31

我一直很喜欢 ASCII 艺术,而我对制作 ASCII 艺术的热情促使我探索 .NET 框架中的 GDI+。在本文中,
我将向您展示如何通过三个简单的步骤从 JPEG/Bitmap 图像生成 ASCII 艺术。

1、加载并调整图像大小。
2、读取每个像素,获取其颜色并将其转换为等效的灰度。
3、根据计算的灰度值为每个像素分配适当的字符。 

让我们开始编写代码

首先使用图像路径初始化 System.Drawing.Bitmap 类。此类用于处理由像素数据定义的图像。
将图像调整为较低的分辨率,同时保持其纵横比。此步骤至关重要,因为图像的每个像素都代表
最终 ASCII 输出中的一个字符。例如,如果您要转换的 JPEG 图像的分辨率为 2592x1944,
则生成的文本将有 1944 行,每行 2592 个字符,您肯定不希望文本那么大。接下来,
定义 ASCII 图像的宽度,并通过按比例缩小来确定高度。

scalingFactor = asciiWidth / imageWidth
asciiHeight = imageHeight * scalingFactor

private void btnConvertToAscii_Click(object sender, EventArgs e)
{
    btnConvertToAscii.Enabled = false;
    //Load the Image from the specified path
    Bitmap image = new Bitmap(txtPath.Text, true);
    //Resize the image...
    //I've used a trackBar to emulate Zoom In / Zoom Out feature
    //This value sets the WIDTH, number of characters, of the text image
    image = GetReSizedImage(image,this.trackBar.Value);
    //Convert the resized image into ASCII
    _Content = ConvertToAscii(image);
    //Enclose the final string between <pre> tags to preserve its formatting
    //and load it in the browser control
    browserMain.DocumentText = "<pre>" + _Content + "</pre>";
    btnConvertToAscii.Enabled = true;
}

通过指定新的宽度和高度初始化位图图像对象。从新图像对象创建图形对象。
将与图形对象关联的插值模式设置为 HighQualityBicubic。此模式可生成最高质量的转换图像(请参阅MSDN)。
您还可以尝试在代码中将插值模式更改为 HighQualityBilinear 或 NearestNeighbor,然后检查输出。

private Bitmap GetReSizedImage(Bitmap inputBitmap, int asciiWidth )
{
    int asciiHeight=0;
    //Calculate the new Height of the image from its width
    asciiHeight = (int)Math.Ceiling((double)inputBitmap.Height * asciiWidth / inputBitmap.Width);
    //Create a new Bitmap and define its resolution
    Bitmap result = new Bitmap(asciiWidth, asciiHeight);
    Graphics g = Graphics.FromImage((Image)result);
    //The interpolation mode produces high quality images
    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
    g.DrawImage(inputBitmap, 0, 0, asciiWidth, asciiHeight);
    g.Dispose();
    return result;
}

ConvertToAscii() 方法接受调整大小的图像作为其输入,执行实际的转换过程。
从位图对象读取每个像素,规范其颜色以找到等效灰度,并根据其灰度因子分配字符。
这也可以实现为图像的亮度。颜色的红色、蓝色和绿色成分的平均值给出其灰度因子。
黑色的 (R, G, B) 值为 (0, 0, 0),白色为 (255,255,255),而银色为 (192,192,192)。


private string ConvertToAscii(Bitmap image)
{
    Boolean toggle = false;
    StringBuilder sb = new StringBuilder();
    for (int h = 0; h < image.Height; h++)
    {
        for (int w = 0; w < image.Width; w++)
        {
            Color pixelColor = image.GetPixel(w, h);
            //Average out the RGB components to find the Gray Color
            int red = (pixelColor.R + pixelColor.G + pixelColor.B) / 3;
            int green = (pixelColor.R + pixelColor.G + pixelColor.B) / 3;
            int blue = (pixelColor.R + pixelColor.G + pixelColor.B) / 3;
            Color grayColor = Color.FromArgb(red,green,blue);
            //Use the toggle flag to minimize height-wise stretch
            if (!toggle)
            {
                int index = (grayColor.R * 10) / 255;
                sb.Append(_AsciiChars[index]);
            }
        }
        if (!toggle)
        {
            sb.Append("<BR>");
            toggle = true;
        }
        else
        {
            toggle = false;
        }
    }
    return sb.ToString();
}

字符数组包含预先确定的 ASCII 字符列表,该列表根据字符的亮度和重量进行排序。

private string[] _AsciiChars = { "#", "#", "@", "%", "=", "+", "*", ":", "-", ".", "&nbsp;" };

一串“#”字符看起来比一串“+”或“*”更暗、更突出。此外,这些字符与字体有关,
只有当字体类型设置为“Courier New”时,此应用程序生成的 ASCII 艺术图才会好看。
此外,两个相邻行的相对间距显然大于两个相邻字符。这会导致 ASCII 图像在高度上拉伸。
为了消除这种情况,我从图像的高度中抽取行,并通过交替设置切换标志插入换行符。
最后,将用 <pre></pre> 标记括起来以保留格式的字符串加载到浏览器控件中。
如果用户想要将其保存为纯文本文件,则所有出现的   
都将被空格替换,所有换行符“<BR>”都将被“\n”替换。


private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
{
    saveFileDialog1.Filter = "Text File (*.txt)|.txt|HTML (*.htm)|.htm";
    DialogResult diag = saveFileDialog1.ShowDialog();
    if (diag == DialogResult.OK)
    {
        if (saveFileDialog1.FilterIndex == 1)
        {
            _Content = _Content.Replace("&nbsp;", " ").Replace("<BR>","\n");
        }
        else
        {
            _Content = "<pre>" + _Content + "</pre>";
        }
        StreamWriter sw = new StreamWriter(saveFileDialog1.FileName);
        sw.Write(_Content);
        sw.Flush();
        sw.Close();
    }
}

结论

这是 .NET 中 GDI+ 可以实现的众多有趣功能之一。代码可以进一步增强,
以生成彩色或动画 ASCII 艺术。我试图使其简单明了,以便于理解。
编码真的很有趣,所以玩得开心吧!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2256540.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第23周:机器学习及文献阅读

目录 摘要 Abstract 一、理论知识 1、逻辑提升 2、分类任务 3、10倍交叉验证法 二、文献阅读 1、模型方法——MLT &#xff08;1&#xff09;特征选择 &#xff08;2&#xff09;决策树剪枝 2、分类任务——逻辑回归 3、实验部分 数据集的选取 代码实践 模型…

2020年国赛高教杯数学建模E题校园供水系统智能管理解题全过程文档及程序

2020年国赛高教杯数学建模 E题 校园供水系统智能管理 原题再现 校园供水系统是校园公用设施的重要组成部分&#xff0c;学校为了保障校园供水系统的正常运行需要投入大量的人力、物力和财力。随着科学技术的发展&#xff0c;校园内已经普遍使用了智能水表&#xff0c;从而可以…

React开发高级篇 - React Hooks以及自定义Hooks实现思路

Hooks介绍 Hooks是react16.8以后新增的钩子API&#xff1b; 目的&#xff1a;增加代码的可复用性&#xff0c;逻辑性&#xff0c;弥补无状态组件没有生命周期&#xff0c;没有数据管理状态state的缺陷。 为什么要使用Hooks&#xff1f; 开发友好&#xff0c;可扩展性强&#…

摩尔线程 国产显卡 MUSA 并行编程 学习笔记-2024/12/03

Learning Roadmap&#xff1a; Section 1: Intro to Parallel Programming & MUSA Deep Learning Ecosystem&#xff08;摩尔线程 国产显卡 MUSA 并行编程 学习笔记-2024/11/30-CSDN博客&#xff09;UbuntuDriverToolkitcondapytorchtorch_musa环境安装(2024/11/24-Ubunt…

如何使用Docker轻松搭建高颜值无广告音乐播放器SPlayer随时随地听歌

前言 在快节奏的生活环境中&#xff0c;音乐成为了许多人放松和享受的重要方式。本文将介绍如何在Linux Ubuntu系统中使用Docker快速部署一款高颜值无广告的某抑云音乐播放器——SPlayer&#xff0c;并结合Cpolar内网穿透工具实现出门在外也能远程访问本地服务&#xff0c;随时…

C# Decimal

文章目录 前言1. Decimal 的基本特性2. 基本用法示例3. 特殊值与转换4. 数学运算示例5. 精度处理示例6. 比较操作示例7. 货币计算示例8. Decimal 的保留小数位数9. 处理 Decimal 的溢出和下溢10. 避免浮点数计算误差总结 前言 decimal 是 C# 中一种用于表示高精度十进制数的关键…

【理论·专业课】第三次作业

第1题&#xff08;存储管理_内存碎片&#xff09; 请指出内部碎片与外部碎片的区别&#xff61; ANS&#xff1a; 内部碎片是分配给进程但未被进程使用且无法被其他进程利用的内存空间 外部碎片是内存中因进程分配释放内存形成的不连续小块&#xff0c;虽总和够但因不连续无…

最新的springboot 3.x的支持s3协议的2.x方法的minio上传文件方法

拉取镜像 docker pull registry.cn-hangzhou.aliyuncs.com/qiluo-images/minio:latest运行命令 docker run -d \--name minio \-p 10087:9000 \-p 10088:9001 \-e MINIO_ROOT_USERminioadmin \-e MINIO_ROOT_PASSWORDY6HYraaphfZ9k8Lv \-v /data/minio/data:/data \-v /data/…

cocos creator接入字节跳动抖音小游戏JSAPI敏感词检测(进行文字输入,但输入敏感词后没有替换为*号)

今天更新了某个抖音小游戏的版本&#xff0c;增加了部分剧情&#xff0c;半天过后一条短信审核未通过&#xff0c;emmm…抖音总是能给开发者惊喜…打开电脑看看这次又整什么幺蛾子… 首先是一脸懵逼&#xff0c;后端早已接入了官方的内容安全检测能力了&#xff08;https://de…

Origin快速拟合荧光寿命、PL Decay (TRPL)数据分析处理-方法二

1.先导入数据到origin 2.导入文件的时候注意&#xff1a;名字短的这个是&#xff0c;或者你打开后看哪个里面有800&#xff0c;因为我的激光重频是1.25Hz&#xff08;应该是&#xff0c;不太确定单位是KHz还是MHz&#xff09;&#xff0c;所以对应的时间是800s。 3.选中两列直接…

17. 面向对象的特征

一、面向对象的三大特征 面向对象的三大特征指的是 封装、继承、多态。 封装&#xff08;encapsulation&#xff0c;有时称为数据隐藏&#xff09;是处理对象的一个重要概念。从形式上看&#xff0c;封装就是将数据和行为组合在一个包中&#xff0c;并对对象的使用者隐藏具体的…

Apache Dolphinscheduler可视化 DAG 工作流任务调度系统

Apache Dolphinscheduler 关于 一个分布式易扩展的可视化 DAG 工作流任务调度系统。致力于解决数据处理流程中错综复杂的依赖关系&#xff0c;使调度系统在数据处理流程中开箱即用。 DolphinScheduler 的主要特性如下&#xff1a; 易于部署&#xff0c;提供四种部署方式&am…

第二部分:基础知识 6.函数 --[JavaScript 新手村:开启编程之旅的第一步]

JavaScript 函数是可重用的代码块&#xff0c;用于执行特定任务。函数可以接受参数&#xff08;输入数据&#xff09;&#xff0c;并且可以返回一个值。JavaScript 提供了多种定义函数的方式&#xff0c;下面将详细介绍这些方式&#xff0c;并给出一些示例。 1. 函数声明 下面…

我眼中的“懂重构”(一)

初识重构 2017年的时候&#xff0c;领导让我看公司的一本书《重构——改善代码的既有设计》&#xff0c;这是一本JAVA版本的&#xff0c;前后看了2遍。那时候看书因为不懂看的格外仔细。我只是那时候不懂&#xff0c;然而多年后的今天我仍然发现很多人对重构充满误解。在刚进入…

机器学习详解(3):线性回归之代码详解

文章目录 1 数据预处理2 构建线性回归模型并绘制回归线初始化方法前向传播&#xff1a;forward_propagation代价函数&#xff1a;cost_function反向传播&#xff1a;backward_propagation参数更新&#xff1a;update_parameters训练方法&#xff1a;train代码运行结果 3 使用Py…

基于openzeppelin插件的智能合约升级

一、作用以及优点 部署可升级合约&#xff0c;插件自动部署proxy和proxyAdmin合约&#xff0c;帮助管理合约升级和交互&#xff1b;升级已部署合约&#xff0c;通过插件快速升级合约&#xff0c;脚本开发方便快捷&#xff1b;管理代理管理员的权限&#xff0c;只有proxyAdmin的…

游戏引擎学习第36天

仓库 :https://gitee.com/mrxiao_com/2d_game 回顾之前的内容 在这个程序中&#xff0c;目标是通过手动编写代码来从头开始制作一个完整的游戏。整个过程不使用任何库或现成的游戏引擎&#xff0c;这样做的目的是为了能够全面了解游戏执行的每一个细节。开发过程中&#xff0…

试题转excel;pdf转excel;试卷转Excel,word试题转excel

一、问题描述 一名教师朋友&#xff0c;偶尔会需要整理一些高质量的题目到excel中 以往都是手动复制搬运&#xff0c;几百道题几乎需要一个下午的时间 关键这些事&#xff0c;枯燥无聊费眼睛&#xff0c;实在是看起来就很蠢的工作 就想着做一个工具&#xff0c;可以自动处理…

16-01、JVM系列之:内存与垃圾回收篇(一)

JVM系列之&#xff1a;内存与垃圾回收篇&#xff08;一&#xff09; ##本篇内容概述&#xff1a; 1、JVM结构 2、类加载子系统 3、运行时数据区之&#xff1a;PC寄存器、Java栈、本地方法栈一、JVM与JAVA体系结构 JAVA虚拟机与JAVA语言并没有必然的联系&#xff0c;它只是与特…

2030. gitLab A仓同步到B仓

文章目录 1 A 仓库备份 到 B 仓库2 B 仓库修改main分支的权限 1 A 仓库备份 到 B 仓库 #!/bin/bash# 定义变量 REPO_DIR"/home/xhome/opt/git_sync/zz_xx_xx" # 替换为你的本地库A的实际路径 REMOTE_ORIGIN"http://192.168.1.66:8181/zzkj_software/zz_xx_xx.…