source: toilet/trunk/src/main.c @ 1099

Last change on this file since 1099 was 1099, checked in by Sam Hocevar, 15 years ago
  • Added -m/--metal flag. Pretty ugly.
  • Property svn:keywords set to Id
File size: 9.1 KB
Line 
1/*
2 *  TOIlet        The Other Implementation’s letters
3 *  Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: main.c 1099 2006-09-23 19:27:19Z sam $
7 *
8 *  This program is free software; you can redistribute it and/or
9 *  modify it under the terms of the Do What The Fuck You Want To
10 *  Public License, Version 2, as published by Sam Hocevar. See
11 *  http://sam.zoy.org/wtfpl/COPYING for more details.
12 */
13
14#include "config.h"
15
16#if defined(HAVE_INTTYPES_H)
17#   include <inttypes.h>
18#endif
19#if defined(HAVE_GETOPT_H)
20#   include <getopt.h>
21#endif
22#include <stdio.h>
23#include <string.h>
24#include <stdlib.h>
25
26#include "cucul.h"
27#include "caca.h"
28
29/* String to canvas transformations */
30static cucul_canvas_t *cuculize_big(uint32_t const *, unsigned int);
31static cucul_canvas_t *cuculize_tiny(uint32_t const *, unsigned int);
32
33/* Canvas special effects */
34static void filter_autocrop(cucul_canvas_t *);
35static void filter_metal(cucul_canvas_t *);
36static void filter_gay(cucul_canvas_t *);
37
38int main(int argc, char *argv[])
39{
40    cucul_canvas_t *cv;
41    cucul_buffer_t *buffer;
42
43    uint32_t *string = NULL;
44    unsigned int length;
45
46    int i;
47
48    char const *export = "utf8";
49    unsigned flag_gay = 0;
50    unsigned flag_metal = 0;
51
52#if defined(HAVE_GETOPT_H)
53    for(;;)
54    {
55#   ifdef HAVE_GETOPT_LONG
56#       define MOREINFO "Try `%s --help' for more information.\n"
57        int option_index = 0;
58        static struct option long_options[] =
59        {
60            /* Long option, needs arg, flag, short option */
61            { "metal", 0, NULL, 'm' },
62            { "gay", 0, NULL, 'g' },
63            { "irc", 0, NULL, 'i' },
64            { "help", 0, NULL, 'h' },
65            { "version", 0, NULL, 'v' },
66            { NULL, 0, NULL, 0 }
67        };
68
69        int c = getopt_long(argc, argv, "gmihv", long_options, &option_index);
70#   else
71#       define MOREINFO "Try `%s -h' for more information.\n"
72        int c = getopt(argc, argv, "gmihv");
73#   endif
74        if(c == -1)
75            break;
76
77        switch(c)
78        {
79        case 'h': /* --help */
80            printf("Usage: %s [ -gmihv ] [ message ]\n", argv[0]);
81#   ifdef HAVE_GETOPT_LONG
82            printf("  -g, --gay        add a rainbow effect to the text\n");
83            printf("  -m, --metal      add a metal effect to the text\n");
84            printf("  -i, --irc        output IRC colour codes\n");
85            printf("  -h, --help       display this help and exit\n");
86            printf("  -v, --version    output version information and exit\n");
87#   else
88            printf("  -g    add a rainbow effect to the text\n");
89            printf("  -m    add a metal effect to the text\n");
90            printf("  -i    output IRC colour codes\n");
91            printf("  -h    display this help and exit\n");
92            printf("  -v    output version information and exit\n");
93#   endif
94            return 0;
95        case 'm': /* --metal */
96            flag_metal = 1;
97            break;
98        case 'g': /* --gay */
99            flag_gay = 1;
100            break;
101        case 'i': /* --irc */
102            export = "irc";
103            break;
104        case 'v': /* --version */
105            printf("TOIlet Copyright 2006 Sam Hocevar %s\n", VERSION);
106            printf("Internet: <sam@zoy.org> Version: 0, date: 21 Sep 2006\n");
107            printf("\n");
108            return 0;
109        case '?':
110            printf(MOREINFO, argv[0]);
111            return 1;
112        default:
113            printf("%s: invalid option -- %i\n", argv[0], c);
114            printf(MOREINFO, argv[0]);
115            return 1;
116        }
117    }
118#else
119#   define MOREINFO "Usage: %s message...\n"
120    int optind = 1;
121#endif
122
123    if(optind >= argc)
124    {
125        printf("%s: too few arguments\n", argv[0]);
126        printf(MOREINFO, argv[0]);
127        return 1;
128    }
129
130    /* Load rest of commandline into a UTF-32 string */
131    for(i = optind, length = 0; i < argc; i++)
132    {
133        unsigned int k, guessed_len, real_len;
134
135        guessed_len = strlen(argv[i]);
136
137        if(i > optind)
138            string[length++] = (uint32_t)' ';
139
140        string = realloc(string, (length + guessed_len + 1) * 4);
141
142        for(k = 0, real_len = 0; k < guessed_len; real_len++)
143        {
144            unsigned int char_len;
145
146            string[length + real_len] =
147                cucul_utf8_to_utf32(argv[i] + k, &char_len);
148
149            k += char_len;
150        }
151
152        length += real_len;
153    }
154
155    /* Do gay stuff with our string (léopard) */
156    cv = cuculize_big(string, length);
157    filter_autocrop(cv);
158    if(flag_metal)
159        filter_metal(cv);
160    if(flag_gay)
161        filter_gay(cv);
162
163    /* Output char */
164    buffer = cucul_export_canvas(cv, export);
165    fwrite(cucul_get_buffer_data(buffer),
166           cucul_get_buffer_size(buffer), 1, stdout);
167    cucul_free_buffer(buffer);
168
169    cucul_free_canvas(cv);
170
171    return 0;
172}
173
174static cucul_canvas_t *cuculize_big(uint32_t const *string,
175                                    unsigned int length)
176{
177    cucul_canvas_t *cv;
178    cucul_font_t *f;
179    char const * const * fonts;
180    unsigned char *buf;
181    unsigned int w, h, x, y, miny, maxy;
182
183    cv = cucul_create_canvas(length, 1);
184    for(x = 0; x < length; x++)
185        cucul_putchar(cv, x, 0, string[x]);
186
187    fonts = cucul_get_font_list();
188    f = cucul_load_font(fonts[0], 0);
189
190    /* Create our bitmap buffer (32-bit ARGB) */
191    w = cucul_get_canvas_width(cv) * cucul_get_font_width(f);
192    h = cucul_get_canvas_height(cv) * cucul_get_font_height(f);
193    buf = malloc(4 * w * h);
194
195    /* Render the canvas onto our image buffer */
196    cucul_render_canvas(cv, f, buf, w, h, 4 * w);
197
198    /* Free our canvas, and allocate a bigger one */
199    cucul_free_font(f);
200    cucul_free_canvas(cv);
201    cv = cucul_create_canvas(w, h);
202
203    /* Render the image buffer on the canvas */
204    cucul_set_color(cv, CUCUL_COLOR_WHITE, CUCUL_COLOR_TRANSPARENT);
205    cucul_clear_canvas(cv);
206
207    miny = h; maxy = 0;
208
209    for(y = 0; y < h; y++)
210       for(x = 0; x < w; x++)
211    {
212        unsigned char c = buf[4 * (x + y * w) + 2];
213
214        if(c >= 0xa0)
215            cucul_putstr(cv, x, y, "█");
216        else if(c >= 0x80)
217            cucul_putstr(cv, x, y, "▓");
218        else if(c >= 0x40)
219            cucul_putstr(cv, x, y, "▒");
220        else if(c >= 0x20)
221            cucul_putstr(cv, x, y, "░");
222    }
223
224    free(buf);
225
226    return cv;
227}
228
229static cucul_canvas_t *cuculize_tiny(uint32_t const *string,
230                                     unsigned int length)
231{
232    unsigned int x;
233    cucul_canvas_t *cv = cucul_create_canvas(length, 1);
234
235    for(x = 0; x < length; x++)
236        cucul_putchar(cv, x, 0, string[x]);
237
238    return cv;
239}
240
241static void filter_autocrop(cucul_canvas_t *cv)
242{
243    unsigned int x, y, w, h;
244    unsigned int xmin, xmax, ymin, ymax;
245
246    xmin = w = cucul_get_canvas_width(cv);
247    xmax = 0;
248    ymin = h = cucul_get_canvas_height(cv);
249    ymax = 0;
250
251    for(y = 0; y < h; y++)
252        for(x = 0; x < w; x++)
253    {
254        unsigned long int ch = cucul_getchar(cv, x, y);
255        if(ch != (unsigned char)' ')
256        {
257            if(x < xmin)
258                xmin = x;
259            if(x > xmax)
260                xmax = x;
261            if(y < ymin)
262                ymin = y;
263            if(y > ymax)
264                ymax = y;
265        }
266    }
267
268    cucul_set_canvas_boundaries(cv, xmin, ymin,
269                                xmax - xmin + 1, ymax - ymin + 1);
270}
271
272static void filter_metal(cucul_canvas_t *cv)
273{
274    static struct
275    {
276        char ch[6];
277        unsigned char fg, bg;
278    }
279    const palette[] =
280    {
281        { " ", CUCUL_COLOR_LIGHTBLUE, CUCUL_COLOR_LIGHTBLUE },
282        { "░", CUCUL_COLOR_BLUE, CUCUL_COLOR_LIGHTBLUE },
283        { "▒", CUCUL_COLOR_BLUE, CUCUL_COLOR_LIGHTBLUE },
284        { "░", CUCUL_COLOR_LIGHTBLUE, CUCUL_COLOR_BLUE },
285        { " ", CUCUL_COLOR_BLUE, CUCUL_COLOR_BLUE },
286        { " ", CUCUL_COLOR_LIGHTGRAY, CUCUL_COLOR_LIGHTGRAY },
287        { "░", CUCUL_COLOR_DARKGRAY, CUCUL_COLOR_LIGHTGRAY },
288        { "▒", CUCUL_COLOR_DARKGRAY, CUCUL_COLOR_LIGHTGRAY },
289        { "░", CUCUL_COLOR_LIGHTGRAY, CUCUL_COLOR_DARKGRAY },
290        { " ", CUCUL_COLOR_DARKGRAY, CUCUL_COLOR_DARKGRAY },
291    };
292
293    unsigned int x, y, w, h;
294
295    w = cucul_get_canvas_width(cv);
296    h = cucul_get_canvas_height(cv);
297
298    for(y = 0; y < h; y++)
299        for(x = 0; x < w; x++)
300    {
301        int i;
302
303        if(cucul_getchar(cv, x, y) == (unsigned char)' ')
304            continue;
305
306        i = y * 10 / h;
307        cucul_set_color(cv, palette[i].fg, palette[i].bg);
308        cucul_putstr(cv, x, y, palette[i].ch);
309    }
310}
311
312static void filter_gay(cucul_canvas_t *cv)
313{
314    static unsigned char const rainbow[] =
315    {
316        CUCUL_COLOR_LIGHTMAGENTA,
317        CUCUL_COLOR_LIGHTRED,
318        CUCUL_COLOR_YELLOW,
319        CUCUL_COLOR_LIGHTGREEN,
320        CUCUL_COLOR_LIGHTCYAN,
321        CUCUL_COLOR_LIGHTBLUE,
322    };
323    unsigned int x, y, w, h;
324
325    w = cucul_get_canvas_width(cv);
326    h = cucul_get_canvas_height(cv);
327
328    for(y = 0; y < h; y++)
329        for(x = 0; x < w; x++)
330    {
331        unsigned long int ch = cucul_getchar(cv, x, y);
332        if(ch != (unsigned char)' ')
333        {
334            cucul_set_color(cv, rainbow[(x / 2 + y) % 6],
335                                CUCUL_COLOR_TRANSPARENT);
336            cucul_putchar(cv, x, y, ch);
337        }
338    }
339}
340
Note: See TracBrowser for help on using the repository browser.