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

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