source: libcaca/trunk/cucul/transform.c @ 1414

Last change on this file since 1414 was 1414, checked in by Sam Hocevar, 14 years ago
  • Added some box drawing glyphs that are used by TOIlet's future.tlf font to the flip/flop/rotation filters.
  • Property svn:keywords set to Id
File size: 13.1 KB
Line 
1/*
2 *  libcucul      Canvas for ultrafast compositing of Unicode letters
3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: transform.c 1414 2006-11-16 02:08:05Z sam $
7 *
8 *  This library 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 horizontal and vertical flipping routines.
16 */
17
18#include "config.h"
19#include "common.h"
20
21#if !defined(__KERNEL__)
22#endif
23
24#include "cucul.h"
25#include "cucul_internals.h"
26
27static uint32_t flipchar(uint32_t ch);
28static uint32_t flopchar(uint32_t ch);
29static uint32_t rotatechar(uint32_t ch);
30
31/** \brief Invert a canvas' colours.
32 *
33 *  Invert a canvas' colours (black becomes white, red becomes cyan, etc.)
34 *  without changing the characters in it.
35 *
36 *  This function never fails.
37 *
38 *  \param cv The canvas to invert.
39 *  \return This function always returns 0.
40 */
41int cucul_invert(cucul_canvas_t *cv)
42{
43    uint32_t *attrs = cv->attrs;
44    unsigned int i;
45
46    for(i = cv->height * cv->width; i--; )
47    {
48        *attrs = *attrs ^ 0x000f000f;
49        attrs++;
50    }
51
52    return 0;
53}
54
55/** \brief Flip a canvas horizontally.
56 *
57 *  Flip a canvas horizontally, choosing characters that look like the
58 *  mirrored version wherever possible. Some characters will stay
59 *  unchanged by the process, but the operation is guaranteed to be
60 *  involutive: performing it again gives back the original canvas.
61 *
62 *  This function never fails.
63 *
64 *  \param cv The canvas to flip.
65 *  \return This function always returns 0.
66 */
67int cucul_flip(cucul_canvas_t *cv)
68{
69    unsigned int y;
70
71    for(y = 0; y < cv->height; y++)
72    {
73        uint32_t *cleft = cv->chars + y * cv->width;
74        uint32_t *cright = cleft + cv->width - 1;
75        uint32_t *aleft = cv->attrs + y * cv->width;
76        uint32_t *aright = aleft + cv->width - 1;
77
78        while(cleft < cright)
79        {
80            uint32_t ch;
81            uint32_t attr;
82
83            /* Swap attributes */
84            attr = *aright;
85            *aright-- = *aleft;
86            *aleft++ = attr;
87
88            /* Swap characters */
89            ch = *cright;
90            *cright-- = flipchar(*cleft);
91            *cleft++ = flipchar(ch);
92        }
93
94        if(cleft == cright)
95            *cleft = flipchar(*cleft);
96
97        /* Fix fullwidth characters. Could it be done in one loop? */
98        cleft = cv->chars + y * cv->width;
99        cright = cleft + cv->width - 1;
100        for( ; cleft < cright; cleft++)
101        {
102            if(cleft[0] == CUCUL_MAGIC_FULLWIDTH)
103            {
104                cleft[0] = cleft[1];
105                cleft[1] = CUCUL_MAGIC_FULLWIDTH;
106                cleft++;
107            }
108        }
109    }
110
111    return 0;
112}
113
114/** \brief Flip a canvas vertically.
115 *
116 *  Flip a canvas vertically, choosing characters that look like the
117 *  mirrored version wherever possible. Some characters will stay
118 *  unchanged by the process, but the operation is guaranteed to be
119 *  involutive: performing it again gives back the original canvas.
120 *
121 *  This function never fails.
122 *
123 *  \param cv The canvas to flop.
124 *  \return This function always returns 0.
125 */
126int cucul_flop(cucul_canvas_t *cv)
127{
128    unsigned int x;
129
130    for(x = 0; x < cv->width; x++)
131    {
132        uint32_t *ctop = cv->chars + x;
133        uint32_t *cbottom = ctop + cv->width * (cv->height - 1);
134        uint32_t *atop = cv->attrs + x;
135        uint32_t *abottom = atop + cv->width * (cv->height - 1);
136
137        while(ctop < cbottom)
138        {
139            uint32_t ch;
140            uint32_t attr;
141
142            /* Swap attributes */
143            attr = *abottom; *abottom = *atop; *atop = attr;
144
145            /* Swap characters */
146            ch = *cbottom; *cbottom = flopchar(*ctop); *ctop = flopchar(ch);
147
148            ctop += cv->width; cbottom -= cv->width;
149            atop += cv->width; abottom -= cv->width;
150        }
151
152        if(ctop == cbottom)
153            *ctop = flopchar(*ctop);
154    }
155
156    return 0;
157}
158
159/** \brief Rotate a canvas.
160 *
161 *  Apply a 180-degree transformation to a canvas, choosing characters
162 *  that look like the upside-down version wherever possible. Some
163 *  characters will stay unchanged by the process, but the operation is
164 *  guaranteed to be involutive: performing it again gives back the
165 *  original canvas.
166 *
167 *  This function never fails.
168 *
169 *  \param cv The canvas to rotate.
170 *  \return This function always returns 0.
171 */
172int cucul_rotate(cucul_canvas_t *cv)
173{
174    uint32_t *cbegin = cv->chars;
175    uint32_t *cend = cbegin + cv->width * cv->height - 1;
176    uint32_t *abegin = cv->attrs;
177    uint32_t *aend = abegin + cv->width * cv->height - 1;
178    unsigned int y;
179
180    while(cbegin < cend)
181    {
182        uint32_t ch;
183        uint32_t attr;
184
185        /* Swap attributes */
186        attr = *aend; *aend = *abegin; *abegin = attr;
187
188        /* Swap characters */
189        ch = *cend; *cend = rotatechar(*cbegin); *cbegin = rotatechar(ch);
190
191        cbegin++; cend--; abegin++; aend--;
192    }
193
194    if(cbegin == cend)
195        *cbegin = rotatechar(*cbegin);
196
197    /* Fix fullwidth characters. Could it be done in one loop? */
198    for(y = 0; y < cv->height; y++)
199    {
200        cbegin = cv->chars + y * cv->width;
201        cend = cbegin + cv->width - 1;
202        for( ; cbegin < cend; cbegin++)
203        {
204            if(cbegin[0] == CUCUL_MAGIC_FULLWIDTH)
205            {
206                cbegin[0] = cbegin[1];
207                cbegin[1] = CUCUL_MAGIC_FULLWIDTH;
208                cbegin++;
209            }
210        }
211    }
212
213    return 0;
214}
215
216/* FIXME: as the lookup tables grow bigger, use a log(n) lookup instead
217 * of linear lookup. */
218static uint32_t flipchar(uint32_t ch)
219{
220    int i;
221
222    static uint32_t const noflip[] =
223    {
224         /* ASCII */
225         ' ', '"', '#', '\'', '-', '.', '*', '+', ':', '=', '0', '8',
226         'A', 'H', 'I', 'M', 'O', 'T', 'U', 'V', 'W', 'X', 'Y', '^',
227         '_', 'i', 'o', 'v', 'w', 'x', '|',
228         /* CP437 and box drawing */
229         0x2591, 0x2592, 0x2593, 0x2588, 0x2584, 0x2580, /* ░ ▒ ▓ █ ▄ ▀ */
230         0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
231         0x252c, 0x2534, 0x2533, 0x253b, 0x2566, 0x2569, /* ┬ ┴ ┳ ┻ ╦ ╩ */
232         0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
233         0x2575, 0x2577, 0x2579, 0x257b, /* ╵ ╷ ╹ ╻ */
234         0
235    };
236
237    static uint32_t const pairs[] =
238    {
239         /* ASCII */
240         '(', ')',
241         '/', '\\',
242         '<', '>',
243         '[', ']',
244         'b', 'd',
245         'p', 'q',
246         '{', '}',
247         /* ASCII-Unicode */
248         ';', 0x204f, /* ; ⁏ */
249         '`', 0x00b4, /* ` ´ */
250         ',', 0x02ce, /* , ˎ */
251         'C', 0x03fd, /* C Ͻ */
252         'E', 0x018e, /* E Ǝ */
253         'N', 0x0418, /* N И */
254         'R', 0x042f, /* R Я */
255         'S', 0x01a7, /* S Ƨ */
256         'c', 0x0254, /* c ɔ */
257         'e', 0x0258, /* e ɘ */
258         /* CP437 */
259         0x258c, 0x2590, /* ▌ ▐ */
260         0x2596, 0x2597, /* ▖ ▗ */
261         0x2598, 0x259d, /* ▘ ▝ */
262         0x2599, 0x259f, /* ▙ ▟ */
263         0x259a, 0x259e, /* ▚ ▞ */
264         0x259b, 0x259c, /* ▛ ▜ */
265         0x25ba, 0x25c4, /* ► ◄ */
266         0x2192, 0x2190, /* → ← */
267         0x2310, 0xac,   /* ⌐ ¬ */
268         /* Box drawing */
269         0x250c, 0x2510, /* ┌ ┐ */
270         0x2514, 0x2518, /* └ ┘ */
271         0x251c, 0x2524, /* ├ ┤ */
272         0x250f, 0x2513, /* ┏ ┓ */
273         0x2517, 0x251b, /* ┗ ┛ */
274         0x2523, 0x252b, /* ┣ ┫ */
275         0x2554, 0x2557, /* ╔ ╗ */
276         0x255a, 0x255d, /* ╚ ╝ */
277         0x2560, 0x2563, /* ╠ ╣ */
278         0x2574, 0x2576, /* ╴ ╶ */
279         0x2578, 0x257a, /* ╸ ╺ */
280         0
281    };
282
283    for(i = 0; noflip[i]; i++)
284        if(ch == noflip[i])
285            return ch;
286
287    for(i = 0; pairs[i]; i++)
288        if(ch == pairs[i])
289            return pairs[i ^ 1];
290
291    return ch;
292}
293
294static uint32_t flopchar(uint32_t ch)
295{
296    int i;
297
298    static uint32_t const noflop[] =
299    {
300         /* ASCII */
301         ' ', '(', ')', '*', '+', '-', '0', '3', '8', ':', '<', '=',
302         '>', 'B', 'C', 'D', 'E', 'H', 'I', 'K', 'O', 'X', '[', ']',
303         'c', 'o', '{', '|', '}',
304         /* CP437 and box drawing */
305         0x2591, 0x2592, 0x2593, 0x2588, 0x258c, 0x2590, /* ░ ▒ ▓ █ ▌ ▐ */
306         0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
307         0x251c, 0x2524, 0x2523, 0x252b, 0x2560, 0x2563, /* ├ ┤ ┣ ┫ ╠ ╣ */
308         0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
309         0x2574, 0x2576, 0x2578, 0x257a, /* ╴ ╶ ╸ ╺ */
310         0
311    };
312
313    static uint32_t const pairs[] =
314    {
315         /* ASCII */
316         '/', '\\',
317         'M', 'W',
318         ',', '`',
319         'b', 'p',
320         'd', 'q',
321         'p', 'q',
322         'f', 't',
323         '.', '\'',
324         /* ASCII-Unicode */
325         '_', 0x203e, /* _ ‾ */
326         '!', 0x00a1, /* ! ¡ */
327         'L', 0x0413, /* L Г */
328         'N', 0x0418, /* N И */
329         'P', 0x042c, /* P Ь */
330         'R', 0x0281, /* R ʁ */
331         'S', 0x01a7, /* S Ƨ */
332         'U', 0x0548, /* U Ո */
333         'V', 0x039b, /* V Λ */
334         'h', 0x03bc, /* h μ */
335         'i', 0x1d09, /* i ᴉ */
336         'v', 0x028c, /* v ʌ */
337         'w', 0x028d, /* w ʍ */
338         'y', 0x03bb, /* y λ */
339         /* Not perfect, but better than nothing */
340         '"', 0x201e, /* " „ */
341         'm', 0x026f, /* m ɯ */
342         'n', 'u',
343         /* CP437 */
344         0x2584, 0x2580, /* ▄ ▀ */
345         0x2596, 0x2598, /* ▖ ▘ */
346         0x2597, 0x259d, /* ▗ ▝ */
347         0x2599, 0x259b, /* ▙ ▛ */
348         0x259f, 0x259c, /* ▟ ▜ */
349         0x259a, 0x259e, /* ▚ ▞ */
350         /* Box drawing */
351         0x250c, 0x2514, /* ┌ └ */
352         0x2510, 0x2518, /* ┐ ┘ */
353         0x252c, 0x2534, /* ┬ ┴ */
354         0x250f, 0x2517, /* ┏ ┗ */
355         0x2513, 0x251b, /* ┓ ┛ */
356         0x2533, 0x253b, /* ┳ ┻ */
357         0x2554, 0x255a, /* ╔ ╚ */
358         0x2557, 0x255d, /* ╗ ╝ */
359         0x2566, 0x2569, /* ╦ ╩ */
360         0x2575, 0x2577, /* ╵ ╷ */
361         0x2579, 0x257b, /* ╹ ╻ */
362         0
363    };
364
365    for(i = 0; noflop[i]; i++)
366        if(ch == noflop[i])
367            return ch;
368
369    for(i = 0; pairs[i]; i++)
370        if(ch == pairs[i])
371            return pairs[i ^ 1];
372
373    return ch;
374}
375
376static uint32_t rotatechar(uint32_t ch)
377{
378    int i;
379
380    static uint32_t const norotate[] =
381    {
382         /* ASCII */
383         ' ', '*', '+', '-', '/', '0', '8', ':', '=', 'H', 'I', 'N',
384         'O', 'S', 'X', 'Z', '\\', 'l', 'o', 's', 'x', 'z', '|',
385         /* Unicode */
386         0x2591, 0x2592, 0x2593, 0x2588, 0x259a, 0x259e, /* ░ ▒ ▓ █ ▚ ▞ */
387         0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
388         0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
389         0
390    };
391
392    static uint32_t const pairs[] =
393    {
394         /* ASCII */
395         '(', ')',
396         '<', '>',
397         '[', ']',
398         '{', '}',
399         '.', '\'',
400         '6', '9',
401         'M', 'W',
402         'b', 'q',
403         'd', 'p',
404         'n', 'u',
405         /* ASCII-Unicode */
406         '_', 0x203e, /* _ ‾ */
407         ',', 0x00b4, /* , ´ */
408         '`', 0x02ce, /* ` ˎ */
409         '&', 0x214b, /* & ⅋ */
410         '!', 0x00a1, /* ! ¡ */
411         '?', 0x00bf, /* ? ¿ */
412         'C', 0x03fd, /* C Ͻ */
413         'E', 0x018e, /* E Ǝ */
414         'F', 0x2132, /* F Ⅎ */
415         'U', 0x0548, /* U Ո */
416         'V', 0x039b, /* V Λ */
417         'a', 0x0250, /* a ɐ */
418         'c', 0x0254, /* c ɔ */
419         'e', 0x0259, /* e ə */
420         'f', 0x025f, /* f ɟ */
421         'g', 0x1d77, /* g ᵷ */
422         'h', 0x0265, /* h ɥ */
423         'i', 0x1d09, /* i ᴉ */
424         'k', 0x029e, /* k ʞ */
425         'm', 0x026f, /* m ɯ */
426         'r', 0x0279, /* r ɹ */
427         't', 0x0287, /* t ʇ */
428         'v', 0x028c, /* v ʌ */
429         'w', 0x028d, /* w ʍ */
430         'y', 0x028e, /* y ʎ */
431         /* Not perfect, but better than nothing */
432         '"', 0x201e, /* " „ */
433         /* CP437 */
434         0x258c, 0x2590, /* ▌ ▐ */
435         0x2584, 0x2580, /* ▄ ▀ */
436         0x2596, 0x259d, /* ▖ ▝ */
437         0x2597, 0x2598, /* ▗ ▘ */
438         0x2599, 0x259c, /* ▙ ▜ */
439         0x259f, 0x259b, /* ▟ ▛ */
440         /* Box drawing */
441         0x250c, 0x2518, /* ┌ ┘ */
442         0x2510, 0x2514, /* ┐ └ */
443         0x251c, 0x2524, /* ├ ┤ */
444         0x252c, 0x2534, /* ┬ ┴ */
445         0x250f, 0x251b, /* ┏ ┛ */
446         0x2513, 0x2517, /* ┓ ┗ */
447         0x2523, 0x252b, /* ┣ ┫ */
448         0x2533, 0x253b, /* ┳ ┻ */
449         0x2554, 0x255d, /* ╔ ╝ */
450         0x2557, 0x255a, /* ╗ ╚ */
451         0x2560, 0x2563, /* ╠ ╣ */
452         0x2566, 0x2569, /* ╦ ╩ */
453         0x2574, 0x2576, /* ╴ ╶ */
454         0x2575, 0x2577, /* ╵ ╷ */
455         0x2578, 0x257a, /* ╸ ╺ */
456         0x2579, 0x257b, /* ╹ ╻ */
457         0
458    };
459
460    for(i = 0; norotate[i]; i++)
461        if(ch == norotate[i])
462            return ch;
463
464    for(i = 0; pairs[i]; i++)
465        if(ch == pairs[i])
466            return pairs[i ^ 1];
467
468    return ch;
469}
470
Note: See TracBrowser for help on using the repository browser.