{"id":8053,"date":"2024-10-31T03:00:00","date_gmt":"2024-10-31T07:00:00","guid":{"rendered":"https:\/\/www.both.org\/?p=8053"},"modified":"2024-10-13T12:25:15","modified_gmt":"2024-10-13T16:25:15","slug":"print-a-spooky-greeting-in-ascii-art","status":"publish","type":"post","link":"https:\/\/www.both.org\/?p=8053","title":{"rendered":"Print a spooky greeting in ASCII art"},"content":{"rendered":"<div class=\"pld-like-dislike-wrap pld-template-1\">\r\n    <div class=\"pld-like-wrap  pld-common-wrap\">\r\n    <a href=\"javascript:void(0)\" class=\"pld-like-trigger pld-like-dislike-trigger  \" title=\"\" data-post-id=\"8053\" data-trigger-type=\"like\" data-restriction=\"cookie\" data-already-liked=\"0\">\r\n                        <i class=\"fas fa-thumbs-up\"><\/i>\r\n                <\/a>\r\n    <span class=\"pld-like-count-wrap pld-count-wrap\">    <\/span>\r\n<\/div><\/div>\n<p>Full-color ASCII art used to be quite popular on DOS, which could leverage the extended ASCII character set and its collection of drawing elements. You can add a little visual interest to your next FreeDOS program by adding ASCII art as a cool \u201cwelcome\u201d screen or as a colorful \u201cexit\u201d screen with more information about the program.<\/p>\n\n\n\n<p>But this style of ASCII art isn\u2019t limited just to FreeDOS applications. You can use the same method in a Linux terminal-mode program. While Linux uses <strong>ncurses<\/strong> to control the screen instead of DOS\u2019s <strong>conio<\/strong>, the related concepts apply well to Linux programs. This article looks at how to generate colorful ASCII art from a C program.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"an-ascii-art-file\">An ASCII art file<\/h2>\n\n\n\n<p>You can use a variety of tools to draw your ASCII art. For this example, I used an old DOS application called TheDraw, but you can find modern open source ASCII art programs on Linux, such as Moebius (Apache license) or PabloDraw (MIT license). It doesn\u2019t matter what tool you use as long as you know what the saved data looks like.<\/p>\n\n\n\n<p>Here\u2019s part of a sample ASCII art file, saved as C source code. Note that the code snippet defines a few values: <code>IMAGEDATA_WIDTH<\/code> and <code>IMAGEDATA_DEPTH<\/code> define the number of columns and rows on the screen. In this case, it\u2019s an 80&#215;25 ASCII art \u201cimage.\u201d <code>IMAGEDATA_LENGTH<\/code> defines the number of entries in the <code>IMAGEDATA<\/code> array. Each character in the ASCII art screen can be represented by two bytes of data: The character to display and a color attribute containing both the foreground and background colors for the character. For an 80&#215;25 screen, where each character is paired with an attribute, the array contains 4000 entries (that\u2019s 80 x 25 x 2 = 4000).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#define IMAGEDATA_WIDTH 80\n#define IMAGEDATA_DEPTH 25\n#define IMAGEDATA_LENGTH 4000\nunsigned char IMAGEDATA &#91;] = {\n    '.', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,\n    ' ', 0x08,  ' ', 0x08,  '.', 0x0F,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,\n    ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  '.', 0x0F,\n    ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,\n    ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,<\/code><\/pre>\n\n\n\n<p>\u2026 and so on for the rest of the array.<\/p>\n\n\n\n<p>To display this ASCII art to the screen, you need to write a small program to read the array and print each character with the right colors.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"setting-a-color-attribute\">Setting a color attribute<\/h2>\n\n\n\n<p>The color attribute in this ASCII art file defines both the background and foreground color in a single byte, represented by hexadecimal values like <code>0x08<\/code> or <code>0x6E<\/code>. Hexadecimal turns out to be a compact way to express a color \u201cpair\u201d like this.<\/p>\n\n\n\n<p>Character mode systems like ncurses on Linux or conio on DOS can display only sixteen colors. That\u2019s sixteen possible text colors and eight background colors. Counting sixteen values (from 0 to 15) in binary requires only four bits: <code>1111<\/code> in binary is 16 in decimal.<\/p>\n\n\n\n<p>And conveniently, hexadecimal can represent 0 to 15 with a single character: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, and F. So the value <code>F<\/code> in hexadecimal is the number 15, or <code>1111<\/code> in binary.<\/p>\n\n\n\n<p>With color pairs, you can encode both the background and foreground colors in a single byte of eight bits. That\u2019s four bits for the text color (0 to 15 or 0 to F in hexadecimal) and three bits for the background color (0 to 7 or 0 to E in hexadecimal). The leftover bit in the byte is not used here, so we can ignore it.<\/p>\n\n\n\n<p>To convert the color pair or attribute into color values that your program can use, you\u2019ll need to use a bit mask to specify only the bits used for the text color or background color. Using the OpenWatcom C Compiler on FreeDOS, you can write this function to set the colors appropriately from the color attribute:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void\ntextattr(int newattr)\n{\n  _settextcolor(newattr &amp; 15);         \/* 0000xxxx *\/\n  _setbkcolor((newattr &gt;&gt; 4) &amp; 7);     \/* 0xxx0000 *\/\n}<\/code><\/pre>\n\n\n\n<p>The <code>_settextcolor<\/code> function sets just the text color, and the <code>_setbkcolor<\/code> function sets the background color. Both are defined in <code>graph.h<\/code>. Note that because the color attribute included both the background color and the foreground color in a single byte value, the textattr function uses &amp; (binary AND) to set a bit mask that isolates only the last four bits in the attribute. That\u2019s where the color pair stores the values 0 to 15 for the foreground color.<\/p>\n\n\n\n<p>To get the background color, the function first performs a bit shift to \u201cpush\u201d the bits to the right. This puts the \u201cupper\u201d bits into the \u201clower\u201d bit range, so any bits like <code>0xxx0000<\/code> become <code>00000xxx<\/code> instead. We can use another bit mask with 7 (binary <code>0111<\/code>) to pick out the background color value.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"displaying-ascii-art\">Displaying ASCII art<\/h2>\n\n\n\n<p>The <code>IMAGEDATA<\/code> array contains the entire ASCII art screen and the color values for each character. To display the ASCII art to the screen, your program needs to scan the array, set the color attribute, then show the screen one character at a time.<\/p>\n\n\n\n<p>Let\u2019s leave room at the bottom of the screen for a separate message or prompt to the user. That means instead of displaying all 25 lines of an 80-column ASCII screen, I only want to show the first 24 lines.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  \/* print one line less than the 80x25 that's in there:\n     80 x 24 x 2 = 3840 *\/\n\n  for (pos = 0; pos &lt; 3840; pos += 2) {\n...\n  }<\/code><\/pre>\n\n\n\n<p>Inside the <code>for<\/code> loop, we need to set the colors, then print the character. The OpenWatcom C Compiler provides a function <code>_outtext<\/code> to display text with the current color values. However, this requires passing a string and would be inefficient if we need to process each character one at a time, in case each character on a line requires a different color.<\/p>\n\n\n\n<p>Instead, OpenWatcom has a similar function called <code>_outmem<\/code> that allows you to indicate how many characters to display. For one character at a time, we can provide a pointer to a character value in the <code>IMAGEDATA<\/code> array and tell <code>_outtext<\/code> to show just one character. That will display the character using the current color attributes, which is what we need.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  for (pos = 0; pos &lt; 3840; pos += 2) {\n    ch = &amp;IMAGEDATA&#91;pos];              \/* pointer assignment *\/\n    attr = IMAGEDATA&#91;pos + 1];\n \n    textattr(attr);\n    _outmem(ch, 1);\n  }<\/code><\/pre>\n\n\n\n<p>This updated loop sets the character <code>ch<\/code> by assigning a pointer into the <code>IMAGEDATA<\/code> array. Next, the loop sets the text attributes, and then displays the character with <code>_outmem<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"putting-it-all-together\">Putting it all together<\/h2>\n\n\n\n<p>With the <code>textattr<\/code> function and the <code>for<\/code> loop to process the array, we can write a full program to display the contents of an ASCII art file. For this example, save the ASCII art as <code>imgdata.inc<\/code> and include it in the source file with an <code>#include<\/code> statement.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;\n#include &lt;conio.h&gt;\n#include &lt;graph.h&gt;\n\n#include \"imgdata.inc\"\n\nvoid\ntextattr(int newattr)\n{\n  _settextcolor(newattr &amp; 15);         \/* 0000xxxx *\/\n  _setbkcolor((newattr &gt;&gt; 4) &amp; 7);     \/* 0xxx0000 *\/\n}\n\nint\nmain()\n{\n  char *ch;\n  int attr;\n  int pos;\n\n  if (_setvideomode(_TEXTC80) == 0) {\n    fputs(\"Error setting video mode\", stderr);\n    return 1;\n  }\n\n  \/* draw the array *\/\n\n  _settextposition(1, 1);              \/* top left *\/\n\n  \/* print one line less than the 80x25 that's in there:\n     80 x 24 x 2 = 3840 *\/\n\n  for (pos = 0; pos &lt; 3840; pos += 2) {\n    ch = &amp;IMAGEDATA&#91;pos];              \/* pointer assignment *\/\n    attr = IMAGEDATA&#91;pos + 1];\n\n    textattr(attr);\n    _outmem(ch, 1);\n  }\n\n  \/* done *\/\n\n  _settextposition(25, 1);             \/* bottom left *\/\n\n  textattr(0x0f);\n  _outtext(\"Press any key to quit\");\n\n  getch();\n\n  textattr(0x00);\n  return 0;\n}<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"533\" height=\"400\" src=\"https:\/\/www.both.org\/wp-content\/uploads\/2024\/10\/halloween.png\" alt=\"\" class=\"wp-image-8054\"\/><\/figure>\n\n\n\n<p>Happy Halloween, everyone!<\/p>\n\n\n\n<p><em>This article is adapted from <a href=\"https:\/\/opensource.com\/article\/21\/10\/ascii-linux-halloween\">Print a Halloween greeting with ASCII art on Linux<\/a> by Jim Hall, and is republished with the author&#8217;s permission.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Generate colorful ASCII art from a C program using FreeDOS.<\/p>\n","protected":false},"author":33,"featured_media":8054,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","footnotes":""},"categories":[340,69,150],"tags":[267,147,152],"class_list":["post-8053","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-freedos","category-fun","category-programming","tag-freedos","tag-fun","tag-programming"],"modified_by":"Jim Hall","_links":{"self":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/8053","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/users\/33"}],"replies":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=8053"}],"version-history":[{"count":3,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/8053\/revisions"}],"predecessor-version":[{"id":8058,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/8053\/revisions\/8058"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/media\/8054"}],"wp:attachment":[{"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=8053"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=8053"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=8053"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}