自学内容网 自学内容网

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

我一直很喜欢 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 艺术。我试图使其简单明了,以便于理解。
编码真的很有趣,所以玩得开心吧!!


原文地址:https://blog.csdn.net/ljygood2/article/details/144322290

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!