source: toilet/trunk/src/filter.c @ 1243

Last change on this file since 1243 was 1243, checked in by Sam Hocevar, 13 years ago
  • Make filters line-feed aware.
  • Property svn:keywords set to Id
File size: 4.7 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: filter.c 1243 2006-10-26 13:30:14Z 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/*
15 * This file contains post-processing filter functions.
16 */
17
18#include "config.h"
19
20#if defined(HAVE_INTTYPES_H)
21#   include <inttypes.h>
22#endif
23#include <string.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <cucul.h>
27
28#include "toilet.h"
29#include "filter.h"
30
31static void filter_crop(context_t *);
32static void filter_gay(context_t *);
33static void filter_metal(context_t *);
34static void filter_flip(context_t *);
35static void filter_flop(context_t *);
36static void filter_rotate(context_t *);
37
38struct
39{
40    char const *name;
41    void (*function)(context_t *);
42}
43const lookup[] =
44{
45    { "crop", filter_crop },
46    { "gay", filter_gay },
47    { "metal", filter_metal },
48    { "flip", filter_flip },
49    { "flop", filter_flop },
50    { "rotate", filter_rotate },
51};
52
53int filter_add(context_t *cx, char const *filter)
54{
55    unsigned int n;
56    int i;
57
58    for(;;)
59    {
60        while(*filter == ':')
61            filter++;
62
63        if(*filter == '\0')
64            break;
65
66        for(i = sizeof(lookup) / sizeof(lookup[0]); i--; )
67            if(!strncmp(filter, lookup[i].name, strlen(lookup[i].name)))
68                break;
69
70        n = strlen(lookup[i].name);
71
72        if(i == -1 || (filter[n] != ':' && filter[n] != '\0'))
73        {
74            fprintf(stderr, "unknown filter near `%s'\n", filter);
75            return -1;
76        }
77
78        if((cx->nfilters % 16) == 0)
79            cx->filters = realloc(cx->filters, (cx->nfilters + 16)
80                                                 * sizeof(lookup[0].function));
81        cx->filters[cx->nfilters] = lookup[i].function;
82        cx->nfilters++;
83
84        filter += n;
85    }
86
87    return 0;
88}
89
90int filter_do(context_t *cx)
91{
92    unsigned int i;
93
94    for(i = 0; i < cx->nfilters; i++)
95        cx->filters[i](cx);
96
97    return 0;
98}
99
100int filter_end(context_t *cx)
101{
102    free(cx->filters);
103
104    return 0;
105}
106
107static void filter_crop(context_t *cx)
108{
109    unsigned int x, y, w, h;
110    unsigned int xmin, xmax, ymin, ymax;
111
112    xmin = w = cucul_get_canvas_width(cx->torender);
113    xmax = 0;
114    ymin = h = cucul_get_canvas_height(cx->torender);
115    ymax = 0;
116
117    for(y = 0; y < h; y++)
118        for(x = 0; x < w; x++)
119    {
120        unsigned long int ch = cucul_getchar(cx->torender, x, y);
121        if(ch != (unsigned char)' ')
122        {
123            if(x < xmin)
124                xmin = x;
125            if(x > xmax)
126                xmax = x;
127            if(y < ymin)
128                ymin = y;
129            if(y > ymax)
130                ymax = y;
131        }
132    }
133
134    if(xmax < xmin || ymax < ymin)
135        return;
136
137    cucul_set_canvas_boundaries(cx->torender, xmin, ymin,
138                                xmax - xmin + 1, ymax - ymin + 1);
139}
140
141static void filter_metal(context_t *cx)
142{
143    static unsigned char const palette[] =
144    {
145        CUCUL_COLOR_LIGHTBLUE,
146        CUCUL_COLOR_BLUE,
147        CUCUL_COLOR_LIGHTGRAY,
148        CUCUL_COLOR_DARKGRAY,
149    };
150
151    unsigned int x, y, w, h;
152
153    w = cucul_get_canvas_width(cx->torender);
154    h = cucul_get_canvas_height(cx->torender);
155
156    for(y = 0; y < h; y++)
157        for(x = 0; x < w; x++)
158    {
159        unsigned long int ch = cucul_getchar(cx->torender, x, y);
160        int i;
161
162        if(ch == (unsigned char)' ')
163            continue;
164
165        i = ((cx->lines + y + x / 8) / 2) % 4;
166        cucul_set_color(cx->torender, palette[i], CUCUL_COLOR_TRANSPARENT);
167        cucul_putchar(cx->torender, x, y, ch);
168    }
169}
170
171static void filter_gay(context_t *cx)
172{
173    static unsigned char const rainbow[] =
174    {
175        CUCUL_COLOR_LIGHTMAGENTA,
176        CUCUL_COLOR_LIGHTRED,
177        CUCUL_COLOR_YELLOW,
178        CUCUL_COLOR_LIGHTGREEN,
179        CUCUL_COLOR_LIGHTCYAN,
180        CUCUL_COLOR_LIGHTBLUE,
181    };
182    unsigned int x, y, w, h;
183
184    w = cucul_get_canvas_width(cx->torender);
185    h = cucul_get_canvas_height(cx->torender);
186
187    for(y = 0; y < h; y++)
188        for(x = 0; x < w; x++)
189    {
190        unsigned long int ch = cucul_getchar(cx->torender, x, y);
191        if(ch != (unsigned char)' ')
192        {
193            cucul_set_color(cx->torender, rainbow[(x / 2 + y + cx->lines) % 6],
194                                CUCUL_COLOR_TRANSPARENT);
195            cucul_putchar(cx->torender, x, y, ch);
196        }
197    }
198}
199
200static void filter_flip(context_t *cx)
201{
202    cucul_flip(cx->torender);
203}
204
205static void filter_flop(context_t *cx)
206{
207    cucul_flop(cx->torender);
208}
209
210static void filter_rotate(context_t *cx)
211{
212    cucul_rotate(cx->torender);
213}
214
Note: See TracBrowser for help on using the repository browser.