Constructing text with astericks

Adam D. Ruppe destructionator at gmail.com
Thu May 31 16:49:00 UTC 2018


On Thursday, 31 May 2018 at 16:05:40 UTC, aberba wrote:
> That doesn't sound like a trivial thing to do. Ha ha

Oh, it isn't that bad if you can get a font as an image file (and 
have the code to load such image files... but I do!)

Take a look at my little answer (SPOILERS THOUGH! Maybe skip to 
bottom of this message if you don't want to actually see the 
working answer just to get more help):

---

class Font {
	import arsd.png;
	enum charWidth = 8;
	enum charHeight = 8;

	TrueColorImage image;

	// font.png is just a screenshot of monospaced font written out 
in 8x8 cells
	// (that's where the charWidth and charHeight things above come 
from), one after
	// another in the image
	this() {
		image = readPng("font.png").getAsTrueColorImage();
	}

	char[charWidth][charHeight] getChar(char c) {
		// just finding the character offset in the image
		auto entriesPerLine = image.width / charWidth;
		auto charX = c % entriesPerLine;
		auto charY = c / entriesPerLine;
		auto xOffset = charX * charWidth;
		auto yOffset = charY * charHeight;

		char[charWidth][charHeight] buffer;

		// then drawing it to the buffer
		foreach(y; 0 .. charHeight) {
			foreach(x; 0 .. charWidth) {
				// if it is not transparent, use *, otherwise, use space.
				buffer[y][x] = (image.getPixel(xOffset + x, yOffset + y).a > 
0 ? '*' : ' ');
			}
		}

		return buffer;
	}
}

// this represents the screen. It is buffered so we can jump 
around x and y to make
// lines of stars instead of trying to just do one line of font 
"pixels" at a time...
char[70][24] screenBuffer;
int bufferCursorX;
int bufferCursorY;

// to draw an individual character, we loop through the character 
and copy its pixels
// line by line...
void writeCharToBuffer(int x, int y, 
char[Font.charWidth][Font.charHeight] ch) {
	foreach(a; 0 .. Font.charHeight)
		screenBuffer[y + a][x .. x + Font.charWidth] = ch[a][];
}

// and to write a string, we do the same for each char. This also 
just keeps track
// of the cursor position so subsequent calls will add the chars 
after the last ones.
//
// Note this may throw a RangeError when it runs out of space!!
void writeStringToBuffer(Font font, string str) {
	foreach(char ch; str) {
		writeCharToBuffer(bufferCursorX, bufferCursorY, 
font.getChar(ch));
		bufferCursorX += Font.charWidth;
		if(bufferCursorX + Font.charWidth > 
screenBuffer[bufferCursorY].length) {
			// the next character would go off the screen, so wrap this 
char
			// to the next line
			bufferCursorY += Font.charHeight;
			bufferCursorX = 0;
		}
	}
}

// then once everything is buffered, writing it to the actual 
screen
// is as simple as looping over the buffered lines and outputting 
them!
void writeBufferToScreen() {
	import std.stdio;
	foreach(line; screenBuffer)
		writeln(line);

}

void main() {
	// clear the screen...
	foreach(ref line; screenBuffer)
		line[] = ' ';

	// load the font
	auto font = new Font();

	// write our string to the buffer
	writeStringToBuffer(font, "Hello, world!");

	// and the buffer to the screen
	writeBufferToScreen();
}

---




Should be fairly simple to follow, just realize that the image is 
a 2d block for each char and that's why there's all those 
multiplies and divides.

You can grab the font.png I used from here:
http://arsdnet.net/font.png

(it is the old IBM PC font)


And the dependencies to load that png are:

https://github.com/adamdruppe/arsd/blob/master/color.d
https://github.com/adamdruppe/arsd/blob/master/png.d


then pretty simple compile and run should get you the hello world.


More information about the Digitalmars-d-learn mailing list