XXIIVV
Nasu on Plan 9
Nasu on Plan 9

Character Memory format of Famicom roms spritesheets.

The .chr file format contains a series of bits equivalent to pixels for each tile in the spreadsheet of a rom. A chr tile is 8x8 pixels, the data for each tile is made up of 128 bits, where the first 64 bits are the first color, the next 64 bits the second color, and where the colors overlap result in the third color, for a total of 4 colors including the background.

0000 1e3f 3f3f 3f1e 78fc fcfc fc78 0000

If you're looking for a simple editor and ANSI C implementation, see Nasu and Dexe. To convert an image into sprites, see Dito. You will find this filetype in most of the famicom and Uxn ecosystems.

C Integration

Drawing a 2-bit sprite

Uint8 icon[16] = {
	0x38, 0x7c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x00,
	0x38, 0x7c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x00
};

Chrs are 8x8 bitmaps with a maximum of 4 colors.

void
drawchr(Uint32 *dst, int x, int y, Uint8 *sprite)
{
	int v, h;
	for(v = 0; v < 8; v++)
		for(h = 0; h < 8; h++) {
			int ch1 = ((sprite[v] >> h) & 0x1);
			int ch2 = (((sprite[v + 8] >> h) & 0x1) << 1);
			putpixel(dst, x + 7 - h, y + v, ch1 + ch2);
		}
}

Drawing a 1-bit sprite

Uint8 icon[8] = {0x38, 0x7c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x00};

Icns are 8x8 monochromatic bitmaps, or half of a chr.

void
draw_icn(Uint32 *dst, int x, int y, Uint8 *sprite, int fg, int bg)
{
	int v, h;
	for(v = 0; v < 8; v++)
		for(h = 0; h < 8; h++) {
			int ch1 = (sprite[v] >> (7 - h)) & 0x1;
			putpixel(dst, x + h, y + v, ch1 ? fg : bg);
		}
}

To convert non-black pixels of an image to an icn file:

void
export_icn(Uint32 *src, int width, int height, char *filename)
{
	int i, x, y;
	Uint8 icnbuf[SZ];
	FILE *f = fopen(filename, "wb");
	/* clean memory */
	for(i = 0; i < SZ; ++i)
		icnbuf[i] = 0;
	/* write pixels */
	for(y = 0; y < height; ++y) {
		for(x = 0; x < width; ++x) {
			int color = pixels[y * width + x];
			if(color) {
				int col = x & 7, row = y & 7;
				int byte = (x & ~7) + (y & ~7) * width / 8 + row;
				icnbuf[byte] |= 1 << (7 - col);
			}
		}
	}
	/* save file */
	if(!fwrite(icnbuf, sizeof(icnbuf), 1, f))
		fprintf(stderr, "Failed: %s!\n", filename);
	fclose(f);
	fprintf(stderr, "Export: %s\n", filename);
}