A small tool that creates a textual representation of a PBM file using half and full-height block drawing characters.
#include<stdlib.h>
#include<stdio.h>
#include<wchar.h>
#include<stdint.h>
#include<string.h>
#include<locale.h>
#include<ctype.h>
static const wchar_t full_width_blocks[] = { 0x0020, 0x2580, 0x2584, 0x2588 };
int main(int argc, char **argv)
{
uint64_t width,
height,
width_in_bytes;
uint8_t *top,
*bottom,
white_space;
setlocale(LC_ALL, "");
// Read header.
if (scanf("P4 %d %d%c", &width, &height, &white_space) != 3) {
fprintf(
stderr,
"Unable to read header. "
"Is there a comment in the file? We don't support that, yet.\n"
);
}
if (!isspace(white_space)) {
fprintf(
stderr,
"This almost looks like a netpbm file. "
"But the delimeter was not whitespace?\n"
);
}
// Allocate memory
width_in_bytes = (width >> 3) + (width & 7 ? 1 : 0);
top = malloc(width_in_bytes << 1);
bottom = top + width_in_bytes;
if (top == NULL) {
fprintf(stderr, "Out of memory.\n");
}
while (height) {
// Read first row.
if (fread(top, width_in_bytes, 1, stdin) != 1) {
fprintf(
stderr,
"Tried to read %d bytes for an even line but failed.\n",
width_in_bytes
);
}
if (--height) {
// Read second row
if (fread(bottom, width_in_bytes, 1, stdin) != 1) {
fprintf(
stderr,
"Tried to read %d bytes for an odd line but failed.\n",
width_in_bytes
);
}
--height;
} else {
// There are no more rows, blank the bottom row.
memset(bottom, 0, width_in_bytes);
}
// Write the row.
for (uint64_t bit = 0; bit < width; ++bit) {
uint8_t top_byte = top[bit >> 3],
bottom_byte = bottom[bit >> 3],
mask = 128 >> (bit&7);
printf(
"%lc",
full_width_blocks[
(top_byte & mask ? 1 : 0) |
(bottom_byte & mask ? 2 : 0)
]
);
}
puts("");
}
return 0;
}
This page is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.