Skip to content

Instantly share code, notes, and snippets.

@Cairnarvon
Created August 20, 2012 01:55
Show Gist options
  • Save Cairnarvon/3399268 to your computer and use it in GitHub Desktop.
Save Cairnarvon/3399268 to your computer and use it in GitHub Desktop.
Variations on a theme.
$ wget -q http://www.secretareaofvipquality.net/maiddog.png
$ ./imgcat maiddog.png
▓▒█▓█▓▓█▓█▓▓▓▒▒▒
▒▒▓█▓▒░▓▓▓▒▒▓▒▒▒▒
▓▓▒▓██████▓██▓▓░░░
▓▓▓▓▓▒▒▒▒▒▒▒▓▓▓▓▓▓▓░
▓▓▓ ▓▒▓▓▒█▓▓██▓▒▒▒▒▓▓▒▓▓▓
▓▓▓ ▓▓▓▒▓░▓▓▓ ▒▓▒▒▒▓▓▓▓▓█
█▓▓▓▒▓██████▓▓▓▓▓▓▓▓██▓▓
▓██▓▓▒░░▓██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
█████ ▓▓█▓█▓▓█░▓▓▒ ░▒▒▓▒▓▓▒▒▒▒▒▓▓▓▓▓▓▓
▒█░ ██▒░▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▓▒▒▓▓▓▓▒
▒▒░ ▒█░░░▒▒▓▓████████████▓ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▒
▒ █░ ░▒███████████ ▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▒ ░░░
▒▒▓▓█▓ ░████████░ ▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓░▒░▒ ░░░
▓▒▓▒▓▒▓▓▓▓▓▒ ▒▓▓██▓▒ ░▒▒ ░░░░▒▒░ ▓░ █▓▒▒▒▒
▒▓▓█▓▓▓▓▓▓▓▓▓▓▓▓▒ ▒▓█ ░▓▒▒░ ▒▓ ▒▓▓░▒▓▓▓▒▒▒▒
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░ ▓░ ░▓▓▓▓▒▒▒▒▒ ▒▒▓▓▓▓▓▒▓▓▒▒▒▒▒▒
▓▓▓▓▓▓▓▓▓▓▓▒▒▓▓▓▓▓█▓▓▒ ▒▒ ░ ▓▒▒▒▒▒▓▓▒░░░░░▒▒▒▒▓██▓▒█▓▓▒▒▒
░▒▓▓▓▓▓▓▓▓▓▒░▓████▓▓▓▓▓░ ▒▓████▓▒▒▒▒▒▒▒▒ █ ▓▓▓ ░░░▒▓▓▓██▓██▒▓
▒▒▒▒▒▓▒▓▒▒ ▓▓▓▓▓▓▓▓▓▓▓▓▒░ ▒█▒▓▓▓▓████▓▓▓▓▓▓▒░█░░░░░░░ ░ ░▒▓▓▓▓▓▓▓▓
▒▒▒ ░▒▓▓▓█▓▓▒░▓▓▓▓▓▓░█ ░░ █▒▒▒▓▓▓███▓█▒ ▒▒ ░░░▒ ░▒░░░░▒▓
░░░░░░▒▒▓▓▓▓▓▒▓░▒▓▒░▒▓▓▓▒ ▒▒▒▒▒▒░▒ ░▓▓█▓▓▓▓▒▒ ▒▒░░▒ ▒▒▒
▒▒▒▒░▒▓▓▓█░▒▒░▒░░░░▒▒▒ ▒▒▒▒▒▒▒▓░▒░▓▓▓██▓▓▒ ▒▒▒
▒▒▒ ▒░▒▓▒▓▒▒▒▒ █▓ ▒▒▒▒▒▒▒▒ ░▒▒░▓▓▓▓▓▒
▒▒▒ ▒▒▒▒▒▒░ ░ ▒▒▒▒ ▒▒▒
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <wand/magick_wand.h>
void usage(char *argv_0) {
fprintf(
stderr,
"Usage: %s [OPTIONS] FILENAME\n"
"\n"
"Options:\n"
"\t--width, -w N|auto\n"
"\t\tSpecify width of the output, or `auto' for terminal width.\n"
"\t\tPreserves aspect ratio if unspecified. Defaults to 80 if both\n"
"\t\t-w and -h are omitted.\n"
"\n"
"\t--height, -h N|auto\n"
"\t\tSpecify height of the output, or `auto' for terminal height.\n"
"\t\tPreserves aspect ratio if unspecified.\n"
"\n"
"\t--mode, -m no-white|monochrome\n"
"\t\tOutput control.\n"
"\t--normalise, -n\n"
"\t\tNormalise image.\n"
"\n"
"\t--invert, -i\n"
"\t\tInvert colours.\n"
"\n",
argv_0);
exit(1);
}
int main(int argc, char **argv)
{
int width = 0, height = 0, mode = 0, normalise = 0, invert = 0;
char **shades;
char *sh[3][5] = {
{" ", "░", "▒", "▓", "█"},
{"░", "▒", "▓", "█", "."},
{" ", "█", ".", ".", "."}
};
/* Parse options. */
enum { NURUPO, WIDTH, HEIGHT, MODE, NORMALISE, INVERT };
static struct option long_options[] = {
{"width", 1, NULL, WIDTH},
{"height", 1, NULL, HEIGHT},
{"mode", 1, NULL, MODE},
{"normalise", 0, NULL, NORMALISE},
{"invert", 0, NULL, INVERT},
{0, 0, 0, NURUPO}
};
int c = 0;
extern int optind;
while ((c = getopt_long(argc, argv, "w:h:m:ni", long_options, NULL)) != -1) {
switch (c) {
case WIDTH:
case 'w':
if (strcmp(optarg, "auto") == 0) {
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
width = w.ws_col;
} else
width = atoi(optarg);
if (width < 0)
usage(argv[0]);
break;
case HEIGHT:
case 'h':
if (strcmp(optarg, "auto") == 0) {
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
height = w.ws_row;
} else
height = atoi(optarg);
if (height < 0)
usage(argv[0]);
break;
case MODE:
case 'm':
if (strcmp(optarg, "no-white") == 0)
mode = 1;
else if (strncmp(optarg, "mono", 4) == 0)
mode = 2;
else
usage(argv[0]);
break;
case NORMALISE:
case 'n':
normalise = 1;
break;
case INVERT:
case 'i':
invert = 1;
break;
default:
usage(argv[0]);
}
}
shades = sh[mode];
if (optind == argc)
usage(argv[0]);
/* Try to load image. */
MagickWand *m_wand;
MagickWandGenesis();
m_wand = NewMagickWand();
if (MagickReadImage(m_wand, argv[optind]) == MagickFalse) {
perror("Can't into file");
return 1;
}
/* Resize and optionally normalise and invert image. */
size_t w = MagickGetImageWidth(m_wand),
h = MagickGetImageHeight(m_wand);
if (!height) {
if (!width)
width = 80;
height = h * width / w / 2;
}
if (!width)
width = w * height * 2 / h;
MagickResizeImage(m_wand, width, height, LanczosFilter, 0.5);
if (normalise) {
MagickSetImageType(m_wand, GrayscaleType);
MagickNormalizeImage(m_wand);
}
if (invert)
MagickNegateImage(m_wand, MagickFalse);
/* Output. */
if (mode == 0)
mode = 5;
else if (mode == 1)
mode = 4;
else
mode = 2;
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
PixelWand *p_wand = NewPixelWand();
double h, s, l;
int level;
MagickGetImagePixelColor(m_wand, j, i, p_wand);
PixelGetHSL(p_wand, &h, &s, &l);
level = (int)(l * mode);
if (level == mode)
--level;
printf("%s", shades[level]);
DestroyPixelWand(p_wand);
}
puts("");
}
return 0;
}
MW = `MagickWand-config --cflags --ldflags --libs`
WARNS = -Wall -Wextra -pedantic -std=c99
.PHONY: all
all: imgcat
imgcat: imgcat.c
$(CC) -o $@ $(MW) $(WARNS) $(CFLAGS) $^
.PHONY: clean
clean:
rm -rf imgcat
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment