Science and technology

Print a Halloween greeting with ASCII artwork on Linux

Full-color ASCII artwork was fairly well-liked on DOS, which may leverage the prolonged ASCII character set and its assortment of drawing parts. You can add slightly visible curiosity to your subsequent FreeDOS program by including ASCII artwork as a cool “welcome” display or as a colourful “exit” display with extra details about this system.

But this model of ASCII artwork isn’t restricted simply to FreeDOS purposes. You can use the identical technique in a Linux terminal-mode program. While Linux makes use of ncurses to manage the display as a substitute of DOS’s conio, the associated ideas apply effectively to Linux applications. This article seems at how you can generate colourful ASCII artwork from a C program.

An ASCII artwork file

You can use a wide range of instruments to attract your ASCII artwork. For this instance, I used an outdated DOS software known as TheDraw, however you’ll find trendy open supply ASCII artwork applications on Linux, comparable to Moebius (Apache license) or PabloDraw (MIT license). It doesn’t matter what device you employ so long as you already know what the saved information seems like.

Here’s a part of a pattern ASCII artwork file, saved as C supply code. Note that the code snippet defines a couple of values: IMAGEDATA_WIDTH and IMAGEDATA_DEPTH outline the variety of columns and rows on the display. In this case, it’s an 80×25 ASCII artwork “image.” IMAGEDATA_LENGTH defines the variety of entries within the IMAGEDATA array. Each character within the ASCII artwork display will be represented by two bytes of knowledge: The character to show and a coloration attribute containing each the foreground and background colours for the character. For an 80×25 display, the place every character is paired with an attribute, the array accommodates 4000 entries (that’s 80 * 25 * 2 = 4000).

#outline IMAGEDATA_WIDTH 80
#outline IMAGEDATA_DEPTH 25
#outline IMAGEDATA_LENGTH 4000
unsigned char IMAGEDATA [] = {
    '.', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,
    ' ', 0x08,  ' ', 0x08,  '.', 0x0F,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,
    ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  '.', 0x0F,
    ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,
    ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,  ' ', 0x08,

and so forth for the remainder of the array.

To show this ASCII artwork to the display, it’s essential to write a small program to learn the array and print every character with the precise colours.

Setting a coloration attribute

The coloration attribute on this ASCII artwork file defines each the background and foreground coloration in a single byte, represented by hexadecimal values like 0x08 or 0x6E. Hexadecimal seems to be a compact approach to categorical a coloration “pair” like this.

Character mode techniques like ncurses on Linux or conio on DOS can display only sixteen colors. That’s sixteen doable textual content colours and eight background colours. Counting sixteen values (from 0 to fifteen) in binary requires solely 4 bits:

And conveniently, hexadecimal can characterize 0 to fifteen with a single character: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, and F. So the worth F in hexadecimal is the quantity 15, or 1111 in binary.

With coloration pairs, you may encode each the background and foreground colours in a single byte of eight bits. That’s 4 bits for the textual content coloration (0 to fifteen or 0 to F in hexadecimal) and three bits for the background coloration (0 to 7 or 0 to E in hexadecimal). The leftover bit within the byte isn’t used right here, so we are able to ignore it.

To convert the colour pair or attribute into coloration values that your program can use, you’ll must use a bit mask to specify solely the bits used for the textual content coloration or background coloration. Using the OpenWatcom C Compiler on FreeDOS, you may write this perform to set the colours appropriately from the colour attribute:

void
textattr(int newattr)
{
  _settextcolor(newattr & 15);         /* 0000xxxx */
  _setbkcolor((newattr >> 4) & 7);     /* 0xxx0000 */
}

The _settextcolor perform units simply the textual content coloration, and the _setbkcolor perform units the background coloration. Both are outlined in graph.h. Note that as a result of the colour attribute included each the background coloration and the foreground coloration in a single byte worth, the textattr perform makes use of & (binary AND) to set a bit masks that isolates solely the final 4 bits within the attribute. That’s the place the colour pair shops the values 0 to fifteen for the foreground coloration.

To get the background coloration, the perform first performs a bit shift to “push” the bits to the precise. This places the “upper” bits into the “lower” bit vary, so any bits like 0xxx0000 develop into 00000xxx as a substitute. We can use one other bit masks with 7 (binary 0111) to pick the background coloration worth.

Displaying ASCII artwork

The IMAGEDATA array accommodates all the ASCII artwork display and the colour values for every character. To show the ASCII artwork to the display, your program must scan the array, set the colour attribute, then present the display one character at a time.

Let’s depart room on the backside of the display for a separate message or immediate to the consumer. That means as a substitute of displaying all 25 strains of an 80-column ASCII display, I solely need to present the primary 24 strains.

  /* print one line lower than the 80x25 that is in there:
     80 x 24 x 2 = 3840 */

  for (pos = 0; pos < 3840; pos += 2) {
...
  }

Inside the for loop, we have to set the colours, then print the character. The OpenWatcom C Compiler gives a perform _outtext to show textual content with the present coloration values. However, this requires passing a string and can be inefficient if we have to course of every character separately, in case every character on a line requires a distinct coloration.

Instead, OpenWatcom has an identical perform known as _outmem that lets you point out what number of characters to show. For one character at a time, we are able to present a pointer to a personality worth within the IMAGEDATA array and inform _outtext to point out only one character. That will show the character utilizing the present coloration attributes, which is what we want.

  for (pos = 0; pos < 3840; pos += 2) {
    ch = &IMAGEDATA[pos];              /* pointer task */
    attr = IMAGEDATA[pos + 1];
 
    textattr(attr);
    _outmem(ch, 1);
  }

This up to date for loop units the character ch by assigning a pointer into the IMAGEDATA array. Next, the loop units the textual content attributes, after which shows the character with _outmem.

Putting all of it collectively

With the textattr perform and the for loop to course of the array, we are able to write a full program to show the contents of an ASCII artwork file. For this instance, save the ASCII artwork as imgdata.inc and embody it within the supply file with an #embody assertion.

#embody
#embody
#embody

#embody "imgdata.inc"

void
textattr(int newattr)
{
  _settextcolor(newattr & 15);         /* 0000xxxx */
  _setbkcolor((newattr >> 4) & 7);     /* 0xxx0000 */
}

int
primary()
{
  char *ch;
  int attr;
  int pos;

  if (_setvideomode(_TEXTC80) == 0) {
    fputs("Error setting video mode", stderr);
    return 1;
  }

  /* draw the array */

  _settextposition(1, 1);              /* prime left */

  /* print one line lower than the 80x25 that is in there:
     80 x 24 x 2 = 3840 */

  for (pos = 0; pos < 3840; pos += 2) {
    ch = &IMAGEDATA[pos];              /* pointer task */
    attr = IMAGEDATA[pos + 1];

    textattr(attr);
    _outmem(ch, 1);
  }

  /* achieved */

  _settextposition(25, 1);             /* backside left */

  textattr(0x0f);
  _outtext("Press any key to quit");

  getch();

  textattr(0x00);
  return 0;
}

Compile this system utilizing the OpenWatcom C Compiler on FreeDOS, and also you’ll get a brand new program that shows this vacation message:

Happy Halloween, everybody!

Download the INC code file here.
Download the C code file here.

Most Popular

To Top