Last active
November 7, 2020 01:36
-
-
Save CQCumbers/708ac8b55c7441ff18867468cfa26d59 to your computer and use it in GitHub Desktop.
print pixel buffers to stdout using ANSI escapes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef IMGPRINT_H | |
#define IMGPRINT_H | |
#include <stdio.h> | |
// w and h are image width and height in pixels | |
// width must always be a whole number of bytes | |
// print 24bpp RGB888 image | |
// requires true color support | |
void imgprint24(const char *img, int w, int h) { | |
for (int y = 0; y < h - 1; y += 2) { | |
for (int x = 0; x < w; ++x) { | |
const char *hi = img + ((y + 0) * w + x) * 3; | |
const char *lo = img + ((y + 1) * w + x) * 3; | |
printf("\x1b[38;2;%hhu;%hhu;%hhum", hi[0], hi[1], hi[2]); | |
printf("\x1b[48;2;%hhu;%hhu;%hhum", lo[0], lo[1], lo[2]); | |
printf("\xe2\x96\x80"); | |
} | |
printf("\x1b[0m\n"); | |
} | |
} | |
// print 8bpp greyscale image | |
// requires true color support | |
void imgprint8(const char *img, int w, int h) { | |
for (int y = 0; y < h - 1; y += 2) { | |
for (int x = 0; x < w; ++x) { | |
char hi = img[(y + 0) * w + x]; | |
char lo = img[(y + 1) * w + x]; | |
printf("\x1b[38;2;%hhu;%hhu;%hhum", hi, hi, hi); | |
printf("\x1b[48;2;%hhu;%hhu;%hhum", lo, lo, lo); | |
printf("\xe2\x96\x80"); | |
} | |
printf("\x1b[0m\n"); | |
} | |
} | |
// helper for imgprint4 | |
void imgprint4_pix(char hi, char lo) { | |
printf("\x1b[38;5;%hhum", hi & 15); | |
printf("\x1b[48;5;%hhum", lo & 15); | |
printf("\xe2\x96\x80"); | |
} | |
// print 4bpp 16-color image | |
// uses terminal 256-color palette | |
void imgprint4(const char *img, int w, int h) { | |
for (int y = 0; y < h - 1; y += 2) { | |
for (int x = 0; x < w; x += 2) { | |
char hi = img[((y + 0) * w + x) / 2]; | |
char lo = img[((y + 1) * w + x) / 2]; | |
imgprint4_pix(hi >> 4, lo >> 4); | |
imgprint4_pix(hi & 15, lo & 15); | |
} | |
printf("\x1b[0m\n"); | |
} | |
} | |
// helper for imgprint2 | |
void imgprint2_pix(char hi, char lo) { | |
static int codes[] = { 30, 90, 37, 97 }; | |
int chi = codes[hi & 3] + 0; | |
int clo = codes[lo & 3] + 10; | |
printf("\x1b[%d;%dm", chi, clo); | |
printf("\xe2\x96\x80"); | |
} | |
// print 2bpp greyscale image | |
void imgprint2(const char *img, int w, int h) { | |
for (int y = 0; y < h - 1; y += 2) { | |
for (int x = 0; x < w; x += 4) { | |
char hi = img[((y + 0) * w + x) / 4]; | |
char lo = img[((y + 1) * w + x) / 4]; | |
for (int i = 6; i >= 0; i -= 2) { | |
imgprint2_pix(hi >> i, lo >> i); | |
} | |
} | |
printf("\x1b[0m\n"); | |
} | |
} | |
// helper for imgprint1 | |
void imgprint1_pix(char hi, char lo) { | |
int chi = (hi & 1) ? 97 : 30; | |
int clo = (lo & 1) ? 107 : 40; | |
printf("\x1b[%d;%dm", clo, chi); | |
printf("\xe2\x96\x80"); | |
} | |
// print 1bpp black & white image | |
void imgprint1(const char *img, int w, int h) { | |
for (int y = 0; y < h - 1; y += 2) { | |
for (int x = 0; x < w; x += 8) { | |
char hi = img[((y + 0) * w + x) / 8]; | |
char lo = img[((y + 1) * w + x) / 8]; | |
for (int i = 7; i >= 0; --i) { | |
imgprint1_pix(hi >> i, lo >> i); | |
} | |
} | |
printf("\x1b[0m\n"); | |
} | |
} | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "imgprint.h" | |
#include <stdlib.h> | |
typedef unsigned char byte; | |
typedef struct { | |
int width, height; | |
int intensity; | |
char p, type; | |
} image_t; | |
static image_t read_ppm(FILE *fp) { | |
// verify image format is P6 | |
image_t img; | |
fscanf(fp, "%c%c\n", &img.p, &img.type); | |
int p6 = (img.p == 'P' && img.type == '6'); | |
if (!p6) printf("Not P6 PPM file\n"), exit(1); | |
// skip comment lines | |
char line[200]; | |
while (1) { | |
fscanf(fp, "%c", line); | |
if (line[0] != '#') break; | |
fgets(line, 200, fp); | |
} | |
ungetc(line[0], fp); | |
// check image dimensions | |
fscanf(fp, "%d %d\n", &img.width, &img.height); | |
if (img.width & 7) printf("Incompatible width\n"), exit(1); | |
fscanf(fp, "%d\n", &img.intensity); | |
return img; | |
} | |
int main(int argc, char *argv[]) { | |
// open test image in ppm format | |
if (argc != 2) printf("Usage: test image.ppm\n"), exit(1); | |
FILE *fp = fopen(argv[1], "rb"); | |
if (!fp) printf("Can't find file %s\n", argv[1]), exit(1); | |
// allocate and read into buffer | |
image_t img = read_ppm(fp); | |
int size = img.width * img.height; | |
byte *pix = (byte*)malloc(size * 3); | |
fread(pix, 1, size * 3, fp); | |
// test printing 24bpp color image | |
printf("width: %d, height: %d\n", img.width, img.height); | |
imgprint24(pix, img.width, img.height); | |
// test printing 8bpp greyscale image | |
for (int i = 0; i < size; ++i) { | |
float r = pix[i * 3 + 0] * 0.21; | |
float g = pix[i * 3 + 1] * 0.71; | |
float b = pix[i * 3 + 2] * 0.07; | |
pix[i] = (byte)(r + g + b); | |
} | |
imgprint8(pix, img.width, img.height); | |
// test printing 4bpp paletted image | |
for (int i = 0; i < size; i += 2) { | |
byte left = pix[i + 0] >> 4; | |
byte right = pix[i + 1] >> 4; | |
pix[i / 2] = (left << 4) | right; | |
} | |
imgprint4(pix, img.width, img.height); | |
// test printing 2bpp greyscale image | |
for (int i = 0; i < size / 2; ++i) { | |
byte left = (pix[i] >> 6) & 3; | |
byte right = (pix[i] >> 2) & 3; | |
byte val = (left << 2) | right; | |
if (i & 1) pix[i / 2] |= val; | |
else pix[i / 2] = val << 4; | |
} | |
imgprint2(pix, img.width, img.height); | |
// test printing 1bpp black & white image | |
for (int i = 0; i < size / 4; ++i) { | |
byte val = (pix[i] >> 4) & 8; | |
val |= (pix[i] >> 3) & 4; | |
val |= (pix[i] >> 2) & 2; | |
val |= (pix[i] >> 1) & 1; | |
if (i & 1) pix[i / 2] |= val; | |
else pix[i / 2] = val << 4; | |
} | |
imgprint1(pix, img.width, img.height); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment