使用Linux或FreeDOS从单个C程序生成丰富多彩的ASCII艺术。利用扩展ASCII字符集及其绘图元素集合的全彩ASCII艺术曾经在DOS上非常流行。您可以将ASCII艺术添加到您的下一个FreeDOS程序中,作为一个很酷的“欢迎”屏幕,或者作为一个带有更多程序信息的彩色“退出”屏幕,以获得更多的视觉兴趣。然而,这种ASCII艺术风格并不仅限于FreeDOS程序。您可以在Linux终端模式程序中使用相同的方法。虽然Linux使用ncurses来控制屏幕,而不是DOS的conio,但是相关概念同样适用于Linux程序。本文探讨了如何从C程序生成彩色ASCII艺术作品。ASCII艺术文件您可以使用各种工具来绘制您的ASCII艺术作品。在此示例中,我使用的是名为TheDraw的旧DOS应用程序,但您可以在Linux上找到现代开源ASCII艺术程序,如Moebius(Apache许可证)或PabloDraw(MIT许可证)。只要您知道保存的数据是什么样子,使用什么工具并不重要。下面是一个示例ASCII艺术文件的一部分,保存在C源代码中。请注意,此代码片段定义了几个值。IMAGEDATA_WIDTH和IMAGEDATA_DEPTH定义屏幕上的列数和行数。在本例中,它是一个80x25ASCII艺术“图像”。IMAGEDATA_LENGTH定义IMAGEDATA数组中的条目数。ASCII艺术图片中的每个字符可以用两个字节的数据表示。要显示的字符和包含该字符的前景色和背景色的颜色属性。对于80x25屏幕,每个字符都与一个属性配对,该数组包含4000个条目(即80*25*2=4000)。#defineIMAGEDATA_WIDTH80#defineIMAGEDATA_DEPTH25#defineIMAGEDATA_LENGTH4000unsignedcharIMAGEDATA[]={'.',0x08,'',0x08,'',0x08,'',0x08,'',0x08,'08','0',0x08,'',0x08,'.',0x0F,'',0x08,'',0x08,'',0x08,'',0x08,'',0x08,'',0x08,'',0x08,'',0x08,'.',0x0F,'',0x08,'',0x08,'',0x08,'',0x08,'',0x08,'',0x08,'',0x08,'',0x08,'',0x08,'',0x08,'',0x08,'',0x08,等等数组的其他部分。为了在屏幕上显示这种ASCII艺术,您需要编写一个小程序来读取数组并以正确的颜色打印每个字符。设置颜色属性这个ASCII艺术文件中的颜色属性定义了一个字节中的背景和前景色,用十六进制值表示,例如0x08或0x6E。十六进制是表达这种颜色“对”的一种紧凑方式。Linux上的ncurses或DOS上的conio等字符模式系统只能显示16种颜色。那是十六种可能的文本颜色和八种背景颜色。用二进制计算十六个值(从0到15)只需要四个二进制位。1111在二进制中是15,方便的话,十六进制可以用一个字符表示0到15:0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F.所以F的值在十六进制中是数字15,或者在二进制中是1111。使用颜色对,您可以将背景和前景颜色编码为一个八位字节。这是文本颜色的四位(十六进制的0到15或0到F)和背景颜色的三位(十六进制的0到7或0到E)。字节中剩余的位在这里没有用到,所以我们可以忽略它。为了将颜色对或属性转换为您的程序可以使用的颜色值,您需要使用位掩码,仅指定用于文本颜色或背景颜色的位。在FreeDOS上使用OpenWatcomC编译器,您可以编写此函数以从颜色属性适当地设置颜色。voidtextattr(intnewattr){_settextcolor(newattr&15);/*0000xxxx*/_setbkcolor((newattr>>4)&7);/*0xxx0000*/}_settextcolor函数只设置文本颜色,_setbkcolor函数设置背景颜色。两者都在graph.h中定义。请注意,由于颜色属性在一个字节值中包含背景色和前景色,因此textattr函数使用&(二进制与)来设置位掩码,仅隔离属性中的最后四位。这是颜色对存储前景色的值0到15的地方。为了获得背景颜色,该函数首先执行位移,将位“推”到右边。这会将“高位”位放入“低位”位范围,因此0xxx0000之类的任何位都变成00000xxx。我们可以使用另一个位掩码7(二进制0111)来挑选背景颜色值。显示ASCII艺术IMAGEDATA数组包含整个ASCII艺术屏幕和每个字符的颜色值。要在屏幕上显示ASCII艺术字,您的程序需要扫描此数组,设置颜色属性,并在屏幕上一次显示一个字符。让我们在屏幕底部留出空间以向用户提供个人信息或提示。也就是说,我不想显示一个80列ASCII屏幕的所有25行,而只显示前24行。/*打印小于其中80x25的一行:80x24x2=3840*/for(pos=0;pos<3840;pos+=2){...}在for循环中,我们需要设置颜色,然后打印字符。OpenWatcomC编译器提供了一个函数_outtext来显示带有当前颜色值的文本。然而,这需要传递一个字符串,如果我们需要一个一个地处理每个字符,在一行中的每个字符需要不同的颜色的情况下,这将是低效的。相反,OpenWatcom有一个名为_outmem的类似函数,它允许您指示要显示的字符数。对于一次一个字符,我们可以提供一个指向IMAGEDATA数组中字符值的指针,并告诉_outtext只显示一个字符。这将使用我们需要的当前颜色属性显示字符。对于(pos=0;pos<3840;pos+=2){ch=&IMAGEDATA[pos];/*指针赋值*/attr=IMAGEDATA[pos+1];文本属性(属性);_outmem(ch,1);}这个更新的for循环通过分配一个指向IMAGEDATA数组的指针来设置字符ch。接下来,循环设置文本属性,然后使用_outmem显示字符。将textattr函数和处理数组的for循环放在一起,我们可以编写一个完整的程序来显示ASCII艺术文件的内容。对于此示例,将ASCII艺术文件保存为imgdata.inc并使用#include语句将其包含在源文件中。#include
