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

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