/* Terminality - a portable terminal handling library * Copyright (C) 1999-2001, Emil Mikulic. * This is LGPL - look at COPYING.LIB */ /* Project: Terminality * File: demoansi.c * Author: Emil Mikulic * Description: ANSI artifier */ /* See the notes on CP437 in precalc.c */ /* This program loads a 160x100x24-bit .RAW image file and tries * to create a text-based representation of it (like those old * ANSI art things - those were cool) * * I guess this program was really inspired by my failed ambition to * become a great ANSI artist. I was never good enough with ACIDDraw * or TheDraw (anyone still remember those days?) so I tried to make * up for it with programming. */ #include "tn.h" #include "precalc.h" #include #include #include const char demoansi_rcsid[] = "$Id: demoansi.c,v 1.10 2002/07/26 02:12:13 darkmoon Exp $"; /* Rendering methods */ #define RENDER_MONOCHROME 1 #define RENDER_SHAPE 2 #define RENDER_COLOR 3 /* Global settings */ int width, height; int level_low, level_high, brightness, render_method, aspect; /* Signal handlers */ void catchterm_init(int i) { /* Uhh... we have a problem */ printw("\nError during initialisation!\n"); update(); donecons(); /* Now die */ exit(1); } /* Image buffer */ unsigned char image[100][160][3]; /* Load image data from file to buffer */ void loadraw(char *fn) { FILE *fp; int width, height, i; unsigned char *ch; /* Reset options */ level_low = 256; level_high = 0; brightness = 0; /* Make sure file exists */ fp = fopen(fn, "rb"); if (!fp) { printw("Error: cannot open %s\n", fn); raise(SIGTERM); } /* Load file */ width = 160; height = fread(image, width*3, 100, fp); printw("Assuming that image is 24-bit RAW (RGB)\nSize: %dx%d\n", width, height); fclose(fp); /* Go through image */ ch = &(image[0][0][0]); for (i=0; i<100*160*3; i++, ch++) { if (*ch > level_high) level_high = *ch; if (*ch < level_low) level_low = *ch; } printw("Levels: %d -> %d\n\n", level_low, level_high); } /* Get gray value for a pixel */ int graypixel(int x, int y) { #define r_weight 0.2 #define g_weight 0.5 #define b_weight 0.3 unsigned char r, g, b; r = image[y][x][0]; g = image[y][x][1]; b = image[y][x][2]; return (int)( (double)(r)*r_weight + (double)(g)*g_weight + (double)(b)*b_weight); } /* Grayscale image */ unsigned char img[50][80]; /* Levelise */ unsigned char levelise(unsigned char x) { int c; c = (int)(x) - level_low; c = (c << 8) / (level_high - level_low); c = (c << 8) / (level_high - brightness) + brightness; if (c < 0) c = 0; if (c > 255) c = 255; return (unsigned char)(c); } /* Calculate grayscale image */ void recalc_grayscale(void) { int x, y, c; /* Calculate gray image */ for (y = 0; y < 50; y++) for (x = 0; x < 80; x++) { /* Average 4 pixels */ c = graypixel(x*2, y*2) + graypixel(x*2+1, y*2) + graypixel(x*2, y*2+1) + graypixel(x*2+1, y*2+1); c = c >> 2; /* Levelise */ img[y][x] = levelise((unsigned char)c); } /* Do we need to reinterpolate? */ if (aspect == 16) for (y = 0; y < 25; y++) for (x = 0; x < 80; x++) { img[y][x] = (unsigned char)( ((int)(img[y*2][x]) + (int)(img[y*2+1][x])) >> 1); } } /* Render full monochrome (blend backgrounds) */ void render_monochrome(void) { int x, y; recalc_grayscale(); /* Render image */ for (y = 0; y> 2; g = (image[y*2][x*2][1] + image[y*2+1][x*2][1] + image[y*2][x*2+1][1] + image[y*2+1][x*2+1][1]) >> 2; b = (image[y*2][x*2][2] + image[y*2+1][x*2][2] + image[y*2][x*2+1][2] + image[y*2+1][x*2+1][2]) >> 2; } else { r = (image[y*4][x*2][0] + image[y*4+1][x*2][0] + image[y*4][x*2+1][0] + image[y*4+1][x*2+1][0] + image[y*4+2][x*2][0] + image[y*4+2+1][x*2][0] + image[y*4+2][x*2+1][0] + image[y*4+2+1][x*2+1][0]) >> 3; g = (image[y*4][x*2][1] + image[y*4+1][x*2][1] + image[y*4][x*2+1][1] + image[y*4+1][x*2+1][1] + image[y*4+2][x*2][1] + image[y*4+2+1][x*2][1] + image[y*4+2][x*2+1][1] + image[y*4+2+1][x*2+1][1]) >> 3; b = (image[y*4][x*2][2] + image[y*4+1][x*2][2] + image[y*4][x*2+1][2] + image[y*4+1][x*2+1][2] + image[y*4+2][x*2][2] + image[y*4+2+1][x*2][2] + image[y*4+2][x*2+1][2] + image[y*4+2+1][x*2+1][2]) >> 3; } /* Levelise */ r = levelise(r); g = levelise(g); b = levelise(b); putsc( get_rgb_block( r,g,b ) ); } } } /* Render with shapes */ void render_shape(void) { int x, y, c; unsigned char pUL, pUR, pLL, pLR; unsigned char simg[100][160]; /* Recalculate grayscale image */ for (y = 0; y < 100; y++) for (x = 0; x < 160; x++) { /* Get from original image */ c = (int)levelise((unsigned char)graypixel(x,y)); /* Put into temporary s_image */ simg[y][x] = (unsigned char)c; } /* Do we need to reinterpolate? */ if (aspect == 16) for (y = 0; y < 50; y++) for (x = 0; x < 160; x++) { simg[y][x] = (unsigned char)( (int)(simg[y*2][x] + simg[y*2+1][x]) >> 1); } /* Draw image to screen now */ for (y=0; y 80) width = 80; height = CON_ROWS-1; if (height > 50) height = 50; /* In case anything goes wrong during init phase */ signal(SIGTERM, catchterm_init); /* Precalcs */ printw("Precalculating..."); precalc(); /* Were we run with a parameter? */ if (argv > 1) filename = argc[1]; else { printw("usage: demoansi \n"); update(); donecons(); exit(1); } /* Load image */ printw("Loading image...\n\n"); loadraw(filename); /* Fire it up */ printw("Press any key to ansify!"); update(); readkey(); /* Set up for main loop */ render_method = RENDER_MONOCHROME; /* Check terminal size and see if we want to use the * extra-tall 80x25 aspect or normal 80x50 aspect */ if ((CON_COLS == 80) && (CON_ROWS == 25)) aspect = 16; else aspect = 8; /* --- Main loop --- */ while (1) { redraw(); k = readkey(); switch (k) { case KEY_ESC: clrscr(); printw("Bye!\n"); update(); donecons(); exit(0); break; case '1': render_method = RENDER_MONOCHROME; break; case '2': render_method = RENDER_SHAPE; break; case '3': render_method = RENDER_COLOR; break; case 'q': level_low++; break; case 'a': level_low--; break; case 'w': brightness++; break; case 's': brightness--; break; case 'e': level_high++; break; case 'd': level_high--; break; } if (level_low < 0) level_low = 0; if (level_high < 1) level_high = 1; if (level_high > 256) level_high = 256; if (level_low >= level_high) level_low = level_high - 1; if (brightness < -255) brightness = -255; if (brightness > 255) brightness = 255; }; /* We should never actually get here */ return 0; }