• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*====================================================================*
2  -  Copyright (C) 2001 Leptonica.  All rights reserved.
3  -  This software is distributed in the hope that it will be
4  -  useful, but with NO WARRANTY OF ANY KIND.
5  -  No author or distributor accepts responsibility to anyone for the
6  -  consequences of using this software, or for whether it serves any
7  -  particular purpose or works at all, unless he or she says so in
8  -  writing.  Everyone is granted permission to copy, modify and
9  -  redistribute this source code, for commercial or non-commercial
10  -  purposes, with the following restrictions: (1) the origin of this
11  -  source code must not be misrepresented; (2) modified versions must
12  -  be plainly marked as such; and (3) this notice may not be removed
13  -  or altered from any source or modified source distribution.
14  *====================================================================*/
15 
16 
17 /*
18  *  rotateorthlow.c
19  *
20  *      90-degree rotation (cw)
21  *            void      rotate90Low()
22  *
23  *      LR-flip
24  *            void      flipLRLow()
25  *
26  *      TB-flip
27  *            void      flipTBLow()
28  *
29  *      Byte reverse tables
30  *            l_uint8  *makeReverseByteTab1()
31  *            l_uint8  *makeReverseByteTab2()
32  *            l_uint8  *makeReverseByteTab4()
33  */
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include "allheaders.h"
39 
40 
41 
42 /*------------------------------------------------------------------*
43  *                           90 degree rotation                     *
44  *------------------------------------------------------------------*/
45 /*!
46  *  rotate90Low()
47  *
48  *      direction:  1 for cw rotation
49  *                 -1 for ccw rotation
50  *
51  *  Notes:
52  *      (1) The dest must be cleared in advance because not
53  *          all source pixels are written to the destination.
54  */
55 void
rotate90Low(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 d,l_int32 wpld,l_uint32 * datas,l_int32 wpls,l_int32 direction)56 rotate90Low(l_uint32  *datad,
57             l_int32    wd,
58             l_int32    hd,
59             l_int32    d,
60             l_int32    wpld,
61             l_uint32  *datas,
62             l_int32    wpls,
63             l_int32    direction)
64 {
65 l_int32    i, j, k, m, iend, nswords;
66 l_uint32   val, word;
67 l_uint32  *lines, *lined;
68 
69     PROCNAME("rotate90Low");
70 
71     if (direction == 1) {  /* clockwise */
72         switch (d)
73         {
74             case 32:
75                 for (i = 0; i < hd; i++) {
76                     lined = datad + i * wpld;
77                     lines = datas + (wd - 1) * wpls;
78                     for (j = 0; j < wd; j++) {
79                         lined[j] = lines[i];
80                         lines -= wpls;
81                     }
82                 }
83                 break;
84             case 16:
85                 for (i = 0; i < hd; i++) {
86                     lined = datad + i * wpld;
87                     lines = datas + (wd - 1) * wpls;
88                     for (j = 0; j < wd; j++) {
89                         if ((val = GET_DATA_TWO_BYTES(lines, i)))
90                             SET_DATA_TWO_BYTES(lined, j, val);
91                         lines -= wpls;
92                     }
93                 }
94                 break;
95             case 8:
96                 for (i = 0; i < hd; i++) {
97                     lined = datad + i * wpld;
98                     lines = datas + (wd - 1) * wpls;
99                     for (j = 0; j < wd; j++) {
100                         if ((val = GET_DATA_BYTE(lines, i)))
101                             SET_DATA_BYTE(lined, j, val);
102                         lines -= wpls;
103                     }
104                 }
105                 break;
106             case 4:
107                 for (i = 0; i < hd; i++) {
108                     lined = datad + i * wpld;
109                     lines = datas + (wd - 1) * wpls;
110                     for (j = 0; j < wd; j++) {
111                         if ((val = GET_DATA_QBIT(lines, i)))
112                             SET_DATA_QBIT(lined, j, val);
113                         lines -= wpls;
114                     }
115                 }
116                 break;
117             case 2:
118                 for (i = 0; i < hd; i++) {
119                     lined = datad + i * wpld;
120                     lines = datas + (wd - 1) * wpls;
121                     for (j = 0; j < wd; j++) {
122                         if ((val = GET_DATA_DIBIT(lines, i)))
123                             SET_DATA_DIBIT(lined, j, val);
124                         lines -= wpls;
125                     }
126                 }
127                 break;
128             case 1:
129                 nswords = hd / 32;
130                 for (j = 0; j < wd; j++) {
131                     lined = datad;
132                     lines = datas + (wd - 1 - j) * wpls;
133                     for (k = 0; k < nswords; k++) {
134                         word = lines[k];
135                         if (!word) {
136                             lined += 32 * wpld;
137                             continue;
138                         }
139                         else {
140                             iend = 32 * (k + 1);
141                             for (m = 0, i = 32 * k; i < iend; i++, m++) {
142                                 if ((word << m) & 0x80000000)
143                                     SET_DATA_BIT(lined, j);
144                                 lined += wpld;
145                             }
146                         }
147                     }
148                     for (i = 32 * nswords; i < hd; i++) {
149                         if (GET_DATA_BIT(lines, i))
150                             SET_DATA_BIT(lined, j);
151                         lined += wpld;
152                     }
153                 }
154                 break;
155             default:
156                 ERROR_VOID("illegal depth", procName);
157         }
158     }
159     else  {     /* direction counter-clockwise */
160         switch (d)
161         {
162             case 32:
163                 for (i = 0; i < hd; i++) {
164                     lined = datad + i * wpld;
165                     lines = datas;
166                     for (j = 0; j < wd; j++) {
167                         lined[j] = lines[hd - 1 - i];
168                         lines += wpls;
169                     }
170                 }
171                 break;
172             case 16:
173                 for (i = 0; i < hd; i++) {
174                     lined = datad + i * wpld;
175                     lines = datas;
176                     for (j = 0; j < wd; j++) {
177                         if ((val = GET_DATA_TWO_BYTES(lines, hd - 1 - i)))
178                             SET_DATA_TWO_BYTES(lined, j, val);
179                         lines += wpls;
180                     }
181                 }
182                 break;
183             case 8:
184                 for (i = 0; i < hd; i++) {
185                     lined = datad + i * wpld;
186                     lines = datas;
187                     for (j = 0; j < wd; j++) {
188                         if ((val = GET_DATA_BYTE(lines, hd - 1 - i)))
189                             SET_DATA_BYTE(lined, j, val);
190                         lines += wpls;
191                     }
192                 }
193                 break;
194             case 4:
195                 for (i = 0; i < hd; i++) {
196                     lined = datad + i * wpld;
197                     lines = datas;
198                     for (j = 0; j < wd; j++) {
199                         if ((val = GET_DATA_QBIT(lines, hd - 1 - i)))
200                             SET_DATA_QBIT(lined, j, val);
201                         lines += wpls;
202                     }
203                 }
204                 break;
205             case 2:
206                 for (i = 0; i < hd; i++) {
207                     lined = datad + i * wpld;
208                     lines = datas;
209                     for (j = 0; j < wd; j++) {
210                         if ((val = GET_DATA_DIBIT(lines, hd - 1 - i)))
211                             SET_DATA_DIBIT(lined, j, val);
212                         lines += wpls;
213                     }
214                 }
215                 break;
216             case 1:
217                 nswords = hd / 32;
218                 for (j = 0; j < wd; j++) {
219                     lined = datad + (hd - 1) * wpld;
220                     lines = datas + (wd - 1 - j) * wpls;
221                     for (k = 0; k < nswords; k++) {
222                         word = lines[k];
223                         if (!word) {
224                             lined -= 32 * wpld;
225                             continue;
226                         }
227                         else {
228                             iend = 32 * (k + 1);
229                             for (m = 0, i = 32 * k; i < iend; i++, m++) {
230                                 if ((word << m) & 0x80000000)
231                                     SET_DATA_BIT(lined, wd - 1 - j);
232                                 lined -= wpld;
233                             }
234                         }
235                     }
236                     for (i = 32 * nswords; i < hd; i++) {
237                         if (GET_DATA_BIT(lines, i))
238                             SET_DATA_BIT(lined, wd - 1 - j);
239                         lined -= wpld;
240                     }
241                 }
242                 break;
243             default:
244                 ERROR_VOID("illegal depth", procName);
245         }
246     }
247 
248     return;
249 }
250 
251 
252 /*------------------------------------------------------------------*
253  *                           Left/right flip                        *
254  *------------------------------------------------------------------*/
255 /*!
256  *  flipLRLow()
257  *
258  *  Notes:
259  *      (1) The pixel access routines allow a trivial implementation.
260  *          However, for d < 8, it is more efficient to right-justify
261  *          each line to a 32-bit boundary and then extract bytes and
262  *          do pixel reversing.   In those cases, as in the 180 degree
263  *          rotation, we right-shift the data (if necessary) to
264  *          right-justify on the 32 bit boundary, and then read the
265  *          bytes off each raster line in reverse order, reversing
266  *          the pixels in each byte using a table.  These functions
267  *          for 1, 2 and 4 bpp were tested against the "trivial"
268  *          version (shown here for 4 bpp):
269  *              for (i = 0; i < h; i++) {
270  *                  line = data + i * wpl;
271  *                  memcpy(buffer, line, bpl);
272  *                    for (j = 0; j < w; j++) {
273  *                      val = GET_DATA_QBIT(buffer, w - 1 - j);
274  *                        SET_DATA_QBIT(line, j, val);
275  *                  }
276  *              }
277  *      (2) This operation is in-place.
278  */
279 void
flipLRLow(l_uint32 * data,l_int32 w,l_int32 h,l_int32 d,l_int32 wpl,l_uint8 * tab,l_uint32 * buffer)280 flipLRLow(l_uint32  *data,
281           l_int32    w,
282           l_int32    h,
283           l_int32    d,
284           l_int32    wpl,
285           l_uint8   *tab,
286           l_uint32  *buffer)
287 {
288 l_int32    extra, shift, databpl, bpl, i, j;
289 l_uint32   val;
290 l_uint32  *line;
291 
292     PROCNAME("flipLRLow");
293 
294     bpl = 4 * wpl;
295     switch (d)
296     {
297         case 32:
298             for (i = 0; i < h; i++) {
299                 line = data + i * wpl;
300                 memcpy(buffer, line, bpl);
301                 for (j = 0; j < w; j++)
302                     line[j] = buffer[w - 1 - j];
303             }
304             break;
305         case 16:
306             for (i = 0; i < h; i++) {
307                 line = data + i * wpl;
308                 memcpy(buffer, line, bpl);
309                 for (j = 0; j < w; j++) {
310                     val = GET_DATA_TWO_BYTES(buffer, w - 1 - j);
311                     SET_DATA_TWO_BYTES(line, j, val);
312                 }
313             }
314             break;
315         case 8:
316             for (i = 0; i < h; i++) {
317                 line = data + i * wpl;
318                 memcpy(buffer, line, bpl);
319                 for (j = 0; j < w; j++) {
320                     val = GET_DATA_BYTE(buffer, w - 1 - j);
321                     SET_DATA_BYTE(line, j, val);
322                 }
323             }
324             break;
325         case 4:
326             extra = (w * d) & 31;
327             if (extra)
328                 shift = 8 - extra / 4;
329             else
330                 shift = 0;
331             if (shift)
332                 rasteropHipLow(data, h, d, wpl, 0, h, shift);
333 
334             databpl = (w + 1) / 2;
335             for (i = 0; i < h; i++) {
336                 line = data + i * wpl;
337                 memcpy(buffer, line, bpl);
338                 for (j = 0; j < databpl; j++) {
339                     val = GET_DATA_BYTE(buffer, bpl - 1 - j);
340                     SET_DATA_BYTE(line, j, tab[val]);
341                 }
342             }
343             break;
344         case 2:
345             extra = (w * d) & 31;
346             if (extra)
347                 shift = 16 - extra / 2;
348             else
349                 shift = 0;
350             if (shift)
351                 rasteropHipLow(data, h, d, wpl, 0, h, shift);
352 
353             databpl = (w + 3) / 4;
354             for (i = 0; i < h; i++) {
355                 line = data + i * wpl;
356                 memcpy(buffer, line, bpl);
357                 for (j = 0; j < databpl; j++) {
358                     val = GET_DATA_BYTE(buffer, bpl - 1 - j);
359                     SET_DATA_BYTE(line, j, tab[val]);
360                 }
361             }
362             break;
363         case 1:
364             extra = (w * d) & 31;
365             if (extra)
366                 shift = 32 - extra;
367             else
368                 shift = 0;
369             if (shift)
370                 rasteropHipLow(data, h, d, wpl, 0, h, shift);
371 
372             databpl = (w + 7) / 8;
373             for (i = 0; i < h; i++) {
374                 line = data + i * wpl;
375                 memcpy(buffer, line, bpl);
376                 for (j = 0; j < databpl; j++) {
377                     val = GET_DATA_BYTE(buffer, bpl - 1 - j);
378                     SET_DATA_BYTE(line, j, tab[val]);
379                 }
380             }
381             break;
382         default:
383             ERROR_VOID("depth not permitted for LR rot", procName);
384             return;
385     }
386 
387     return;
388 }
389 
390 
391 /*------------------------------------------------------------------*
392  *                            Top/bottom flip                       *
393  *------------------------------------------------------------------*/
394 /*!
395  *  flipTBLow()
396  *
397  *  Notes:
398  *      (1) This is simple and fast.  We use the memcpy function
399  *          to do all the work on aligned data, regardless of pixel
400  *          depth.
401  *      (2) This operation is in-place.
402  */
403 void
flipTBLow(l_uint32 * data,l_int32 h,l_int32 wpl,l_uint32 * buffer)404 flipTBLow(l_uint32  *data,
405           l_int32    h,
406           l_int32    wpl,
407           l_uint32  *buffer)
408 {
409 l_int32    i, k, h2, bpl;
410 l_uint32  *linet, *lineb;
411 
412     h2 = h / 2;
413     bpl = 4 * wpl;
414     for (i = 0, k = h - 1; i < h2; i++, k--) {
415         linet = data + i * wpl;
416         lineb = data + k * wpl;
417         memcpy(buffer, linet, bpl);
418         memcpy(linet, lineb, bpl);
419         memcpy(lineb, buffer, bpl);
420     }
421 
422     return;
423 }
424 
425 
426 /*------------------------------------------------------------------*
427  *                          Byte reverse tables                     *
428  *------------------------------------------------------------------*/
429 /*!
430  *  makeReverseByteTab1()
431  *
432  *  Notes:
433  *      (1) This generates an 8 bit lookup table for reversing
434  *          the order of eight 1-bit pixels.
435  */
436 l_uint8 *
makeReverseByteTab1(void)437 makeReverseByteTab1(void)
438 {
439 l_int32   i;
440 l_uint8  *tab;
441 
442     PROCNAME("makeReverseByteTab1");
443 
444     if ((tab = (l_uint8 *)CALLOC(256, sizeof(l_uint8))) == NULL)
445         return (l_uint8 *)ERROR_PTR("calloc fail for tab", procName, NULL);
446 
447     for (i = 0; i < 256; i++)
448         tab[i] = ((0x80 & i) >> 7) |
449                  ((0x40 & i) >> 5) |
450                  ((0x20 & i) >> 3) |
451                  ((0x10 & i) >> 1) |
452                  ((0x08 & i) << 1) |
453                  ((0x04 & i) << 3) |
454                  ((0x02 & i) << 5) |
455                  ((0x01 & i) << 7);
456 
457     return tab;
458 }
459 
460 
461 /*!
462  *  makeReverseByteTab2()
463  *
464  *  Notes:
465  *      (1) This generates an 8 bit lookup table for reversing
466  *          the order of four 2-bit pixels.
467  */
468 l_uint8 *
makeReverseByteTab2(void)469 makeReverseByteTab2(void)
470 {
471 l_int32   i;
472 l_uint8  *tab;
473 
474     PROCNAME("makeReverseByteTab2");
475 
476     if ((tab = (l_uint8 *)CALLOC(256, sizeof(l_uint8))) == NULL)
477         return (l_uint8 *)ERROR_PTR("calloc fail for tab", procName, NULL);
478 
479     for (i = 0; i < 256; i++)
480         tab[i] = ((0xc0 & i) >> 6) |
481                  ((0x30 & i) >> 2) |
482                  ((0x0c & i) << 2) |
483                  ((0x03 & i) << 6);
484     return tab;
485 }
486 
487 
488 /*!
489  *  makeReverseByteTab4()
490  *
491  *  Notes:
492  *      (1) This generates an 8 bit lookup table for reversing
493  *          the order of two 4-bit pixels.
494  */
495 l_uint8 *
makeReverseByteTab4(void)496 makeReverseByteTab4(void)
497 {
498 l_int32   i;
499 l_uint8  *tab;
500 
501     PROCNAME("makeReverseByteTab4");
502 
503     if ((tab = (l_uint8 *)CALLOC(256, sizeof(l_uint8))) == NULL)
504         return (l_uint8 *)ERROR_PTR("calloc fail for tab", procName, NULL);
505 
506     for (i = 0; i < 256; i++)
507         tab[i] = ((0xf0 & i) >> 4) | ((0x0f & i) << 4);
508     return tab;
509 }
510 
511