From 622e8deeed727e2ab64d38808fc87671d6f66fcb Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Fri, 22 Sep 2006 23:36:35 +0000 Subject: [PATCH] * Import toilet source code from libcaca's repository. --- configure.ac | 12 +- src/Makefile.am | 2 +- src/main.c | 293 +++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 289 insertions(+), 18 deletions(-) diff --git a/configure.ac b/configure.ac index 675b17a..ec4f78c 100644 --- a/configure.ac +++ b/configure.ac @@ -25,11 +25,19 @@ if test "$build" != "$host" -a "${PKG_CONFIG_LIBDIR}" = ""; then export PKG_CONFIG_LIBDIR=/dev/null fi +AC_CHECK_HEADERS(getopt.h) +AC_CHECK_FUNCS(getopt_long, + [AC_DEFINE(HAVE_GETOPT_LONG, 1, Define to 1 if you have the `getopt_long' function.)], + [AC_CHECK_LIB(gnugetopt, getopt_long, + [AC_DEFINE(HAVE_GETOPT_LONG, 1, Define to 1 if you have the `getopt_long' function.) + GETOPT_LIBS="${GETOPT_LIBS} -lgnugetopt"])]) +AC_SUBST(GETOPT_LIBS) + CUCUL="no" -PKG_CHECK_MODULES(cucul, cucul, +PKG_CHECK_MODULES(cucul, cucul >= 0.99.beta5, [CUCUL="yes"], [AC_MSG_RESULT(no) - AC_MSG_ERROR([you need libcucul version 0.99 or later])]) + AC_MSG_ERROR([you need libcucul version 0.99.beta5 or later])]) # Optimizations CFLAGS="${CFLAGS} -g -O2 -fno-strength-reduce -fomit-frame-pointer" diff --git a/src/Makefile.am b/src/Makefile.am index d9e51f1..74d9057 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,5 +3,5 @@ bin_PROGRAMS = toilet toilet_SOURCES = main.c toilet_CFLAGS = `pkg-config --cflags cucul` -toilet_LDFLAGS = `pkg-config --libs cucul` +toilet_LDFLAGS = `pkg-config --libs cucul` @GETOPT_LIBS@ diff --git a/src/main.c b/src/main.c index e30cbda..d707db8 100644 --- a/src/main.c +++ b/src/main.c @@ -1,27 +1,290 @@ /* - * $Id$ + * TOIlet The Other Implementation’s letters + * Copyright (c) 2006 Sam Hocevar + * All Rights Reserved * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * $Id$ * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Do What The Fuck You Want To + * Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. */ #include "config.h" -#include +#if defined(HAVE_INTTYPES_H) +# include +#endif +#if defined(HAVE_GETOPT_H) +# include +#endif +#include +#include +#include -int main (int argc, char **argv) +#include "cucul.h" +#include "caca.h" + +/* String to canvas transformations */ +static cucul_canvas_t *cuculize_big(uint32_t const *, unsigned int); +static cucul_canvas_t *cuculize_tiny(uint32_t const *, unsigned int); + +/* Canvas special effects */ +static void filter_autocrop(cucul_canvas_t *); +static void filter_gay(cucul_canvas_t *); + +int main(int argc, char *argv[]) { + cucul_canvas_t *cv; + cucul_buffer_t *buffer; + + uint32_t *string = NULL; + unsigned int length; + + int i; + + char const *export = "utf8"; + unsigned flag_gay = 0; + +#if defined(HAVE_GETOPT_H) + for(;;) + { +# ifdef HAVE_GETOPT_LONG +# define MOREINFO "Try `%s --help' for more information.\n" + int option_index = 0; + static struct option long_options[] = + { + /* Long option, needs arg, flag, short option */ + { "gay", 0, NULL, 'g' }, + { "irc", 0, NULL, 'i' }, + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'v' }, + { NULL, 0, NULL, 0 } + }; + + int c = getopt_long(argc, argv, "gihv", long_options, &option_index); +# else +# define MOREINFO "Try `%s -h' for more information.\n" + int c = getopt(argc, argv, "gihv"); +# endif + if(c == -1) + break; + + switch(c) + { + case 'h': /* --help */ + printf("Usage: %s [ -gihv ] [ message ]\n", argv[0]); +# ifdef HAVE_GETOPT_LONG + printf(" -g, --gay add a rainbow effect to the text\n"); + printf(" -i, --irc output IRC colour codes\n"); + printf(" -h, --help display this help and exit\n"); + printf(" -v, --version output version information and exit\n"); +# else + printf(" -g add a rainbow effect to the text\n"); + printf(" -i output IRC colour codes\n"); + printf(" -h display this help and exit\n"); + printf(" -v output version information and exit\n"); +# endif + return 0; + case 'g': /* --gay */ + flag_gay = 1; + break; + case 'i': /* --irc */ + export = "irc"; + break; + case 'v': /* --version */ + printf("TOIlet Copyright 2006 Sam Hocevar %s\n", VERSION); + printf("Internet: Version: 0, date: 21 Sep 2006\n"); + printf("\n"); + return 0; + case '?': + printf(MOREINFO, argv[0]); + return 1; + default: + printf("%s: invalid option -- %i\n", argv[0], c); + printf(MOREINFO, argv[0]); + return 1; + } + } +#else +# define MOREINFO "Usage: %s message...\n" + int optind = 1; +#endif + + if(optind >= argc) + { + printf("%s: too few arguments\n", argv[0]); + printf(MOREINFO, argv[0]); + return 1; + } + + /* Load rest of commandline into a UTF-32 string */ + for(i = optind, length = 0; i < argc; i++) + { + unsigned int k, guessed_len, real_len; + + guessed_len = strlen(argv[i]); + + if(i > optind) + string[length++] = (uint32_t)' '; + + string = realloc(string, (length + guessed_len + 1) * 4); + + for(k = 0, real_len = 0; k < guessed_len; real_len++) + { + unsigned int char_len; + + string[length + real_len] = + cucul_utf8_to_utf32(argv[i] + k, &char_len); + + k += char_len; + } + + length += real_len; + } + + /* Do gay stuff with our string (léopard) */ + cv = cuculize_big(string, length); + filter_autocrop(cv); + if(flag_gay) + filter_gay(cv); + + /* Output char */ + buffer = cucul_export_canvas(cv, export); + fwrite(cucul_get_buffer_data(buffer), + cucul_get_buffer_size(buffer), 1, stdout); + cucul_free_buffer(buffer); + + cucul_free_canvas(cv); + return 0; } +static cucul_canvas_t *cuculize_big(uint32_t const *string, + unsigned int length) +{ + cucul_canvas_t *cv; + cucul_font_t *f; + char const * const * fonts; + unsigned char *buf; + unsigned int w, h, x, y, miny, maxy; + + cv = cucul_create_canvas(length, 1); + for(x = 0; x < length; x++) + cucul_putchar(cv, x, 0, string[x]); + + fonts = cucul_get_font_list(); + f = cucul_load_font(fonts[0], 0); + + /* Create our bitmap buffer (32-bit ARGB) */ + w = cucul_get_canvas_width(cv) * cucul_get_font_width(f); + h = cucul_get_canvas_height(cv) * cucul_get_font_height(f); + buf = malloc(4 * w * h); + + /* Render the canvas onto our image buffer */ + cucul_render_canvas(cv, f, buf, w, h, 4 * w); + + /* Free our canvas, and allocate a bigger one */ + cucul_free_font(f); + cucul_free_canvas(cv); + cv = cucul_create_canvas(w, h); + + /* Render the image buffer on the canvas */ + cucul_set_color(cv, CUCUL_COLOR_WHITE, CUCUL_COLOR_TRANSPARENT); + cucul_clear_canvas(cv); + + miny = h; maxy = 0; + + for(y = 0; y < h; y++) + for(x = 0; x < w; x++) + { + unsigned char c = buf[4 * (x + y * w) + 2]; + + if(c >= 0xa0) + cucul_putstr(cv, x, y, "█"); + else if(c >= 0x80) + cucul_putstr(cv, x, y, "▓"); + else if(c >= 0x40) + cucul_putstr(cv, x, y, "▒"); + else if(c >= 0x20) + cucul_putstr(cv, x, y, "░"); + } + + free(buf); + + return cv; +} + +static cucul_canvas_t *cuculize_tiny(uint32_t const *string, + unsigned int length) +{ + unsigned int x; + cucul_canvas_t *cv = cucul_create_canvas(length, 1); + + for(x = 0; x < length; x++) + cucul_putchar(cv, x, 0, string[x]); + + return cv; +} + +static void filter_autocrop(cucul_canvas_t *cv) +{ + unsigned int x, y, w, h; + unsigned int xmin, xmax, ymin, ymax; + + xmin = w = cucul_get_canvas_width(cv); + xmax = 0; + ymin = h = cucul_get_canvas_height(cv); + ymax = 0; + + for(y = 0; y < h; y++) + for(x = 0; x < w; x++) + { + unsigned long int ch = cucul_getchar(cv, x, y); + if(ch != (unsigned char)' ') + { + if(x < xmin) + xmin = x; + if(x > xmax) + xmax = x; + if(y < ymin) + ymin = y; + if(y > ymax) + ymax = y; + } + } + + cucul_set_canvas_boundaries(cv, xmin, ymin, + xmax - xmin + 1, ymax - ymin + 1); +} + +static void filter_gay(cucul_canvas_t *cv) +{ + static unsigned char const rainbow[] = + { + CUCUL_COLOR_LIGHTMAGENTA, + CUCUL_COLOR_LIGHTRED, + CUCUL_COLOR_YELLOW, + CUCUL_COLOR_LIGHTGREEN, + CUCUL_COLOR_LIGHTCYAN, + CUCUL_COLOR_LIGHTBLUE, + }; + unsigned int x, y, w, h; + + w = cucul_get_canvas_width(cv); + h = cucul_get_canvas_height(cv); + + for(y = 0; y < h; y++) + for(x = 0; x < w; x++) + { + unsigned long int ch = cucul_getchar(cv, x, y); + if(ch != (unsigned char)' ') + { + cucul_set_color(cv, rainbow[(x / 2 + y) % 6], + CUCUL_COLOR_TRANSPARENT); + cucul_putchar(cv, x, y, ch); + } + } +} +