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

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