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

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