Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
rotateorth.c
Go to the documentation of this file.
1/*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
53#ifdef HAVE_CONFIG_H
54#include <config_auto.h>
55#endif /* HAVE_CONFIG_H */
56
57#include <string.h>
58#include "allheaders.h"
59
60static l_uint8 *makeReverseByteTab1(void);
61static l_uint8 *makeReverseByteTab2(void);
62static l_uint8 *makeReverseByteTab4(void);
63
64/*------------------------------------------------------------------*
65 * Top-level rotation by multiples of 90 degrees *
66 *------------------------------------------------------------------*/
74PIX *
76 l_int32 quads)
77{
78 if (!pixs)
79 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
80 if (quads < 0 || quads > 3)
81 return (PIX *)ERROR_PTR("quads not in {0,1,2,3}", __func__, NULL);
82
83 if (quads == 0)
84 return pixCopy(NULL, pixs);
85 else if (quads == 1)
86 return pixRotate90(pixs, 1);
87 else if (quads == 2)
88 return pixRotate180(NULL, pixs);
89 else /* quads == 3 */
90 return pixRotate90(pixs, -1);
91}
92
93
94/*------------------------------------------------------------------*
95 * 180 degree rotation *
96 *------------------------------------------------------------------*/
121PIX *
123 PIX *pixs)
124{
125l_int32 d;
126
127 if (!pixs)
128 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
129 d = pixGetDepth(pixs);
130 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
131 return (PIX *)ERROR_PTR("pixs not in {1,2,4,8,16,32} bpp",
132 __func__, NULL);
133
134 /* Prepare pixd for in-place operation */
135 if ((pixd = pixCopy(pixd, pixs)) == NULL)
136 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
137
138 pixFlipLR(pixd, pixd);
139 pixFlipTB(pixd, pixd);
140 return pixd;
141}
142
143
144/*------------------------------------------------------------------*
145 * 90 degree rotation *
146 *------------------------------------------------------------------*/
161PIX *
163 l_int32 direction)
164{
165l_int32 wd, hd, d, wpls, wpld;
166l_int32 i, j, k, m, iend, nswords;
167l_uint32 val, word;
168l_uint32 *lines, *datas, *lined, *datad;
169PIX *pixd;
170
171 if (!pixs)
172 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
173 pixGetDimensions(pixs, &hd, &wd, &d); /* note: reversed */
174 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
175 return (PIX *)ERROR_PTR("pixs not in {1,2,4,8,16,32} bpp",
176 __func__, NULL);
177 if (direction != 1 && direction != -1)
178 return (PIX *)ERROR_PTR("invalid direction", __func__, NULL);
179
180 if ((pixd = pixCreate(wd, hd, d)) == NULL)
181 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
182 pixCopyColormap(pixd, pixs);
183 pixCopyResolution(pixd, pixs);
184 pixCopyInputFormat(pixd, pixs);
185 pixCopySpp(pixd, pixs);
186
187 datas = pixGetData(pixs);
188 wpls = pixGetWpl(pixs);
189 datad = pixGetData(pixd);
190 wpld = pixGetWpl(pixd);
191
192 if (direction == 1) { /* clockwise */
193 switch (d)
194 {
195 case 32:
196 for (i = 0; i < hd; i++) {
197 lined = datad + i * wpld;
198 lines = datas + (wd - 1) * wpls;
199 for (j = 0; j < wd; j++) {
200 lined[j] = lines[i];
201 lines -= wpls;
202 }
203 }
204 break;
205 case 16:
206 for (i = 0; i < hd; i++) {
207 lined = datad + i * wpld;
208 lines = datas + (wd - 1) * wpls;
209 for (j = 0; j < wd; j++) {
210 if ((val = GET_DATA_TWO_BYTES(lines, i)))
211 SET_DATA_TWO_BYTES(lined, j, val);
212 lines -= wpls;
213 }
214 }
215 break;
216 case 8:
217 for (i = 0; i < hd; i++) {
218 lined = datad + i * wpld;
219 lines = datas + (wd - 1) * wpls;
220 for (j = 0; j < wd; j++) {
221 if ((val = GET_DATA_BYTE(lines, i)))
222 SET_DATA_BYTE(lined, j, val);
223 lines -= wpls;
224 }
225 }
226 break;
227 case 4:
228 for (i = 0; i < hd; i++) {
229 lined = datad + i * wpld;
230 lines = datas + (wd - 1) * wpls;
231 for (j = 0; j < wd; j++) {
232 if ((val = GET_DATA_QBIT(lines, i)))
233 SET_DATA_QBIT(lined, j, val);
234 lines -= wpls;
235 }
236 }
237 break;
238 case 2:
239 for (i = 0; i < hd; i++) {
240 lined = datad + i * wpld;
241 lines = datas + (wd - 1) * wpls;
242 for (j = 0; j < wd; j++) {
243 if ((val = GET_DATA_DIBIT(lines, i)))
244 SET_DATA_DIBIT(lined, j, val);
245 lines -= wpls;
246 }
247 }
248 break;
249 case 1:
250 nswords = hd / 32;
251 for (j = 0; j < wd; j++) {
252 lined = datad;
253 lines = datas + (wd - 1 - j) * wpls;
254 for (k = 0; k < nswords; k++) {
255 word = lines[k];
256 if (!word) {
257 lined += 32 * wpld;
258 continue;
259 } else {
260 iend = 32 * (k + 1);
261 for (m = 0, i = 32 * k; i < iend; i++, m++) {
262 if ((word << m) & 0x80000000)
263 SET_DATA_BIT(lined, j);
264 lined += wpld;
265 }
266 }
267 }
268 for (i = 32 * nswords; i < hd; i++) {
269 if (GET_DATA_BIT(lines, i))
270 SET_DATA_BIT(lined, j);
271 lined += wpld;
272 }
273 }
274 break;
275 default:
276 pixDestroy(&pixd);
277 L_ERROR("illegal depth: %d\n", __func__, d);
278 break;
279 }
280 } else { /* direction counter-clockwise */
281 switch (d)
282 {
283 case 32:
284 for (i = 0; i < hd; i++) {
285 lined = datad + i * wpld;
286 lines = datas;
287 for (j = 0; j < wd; j++) {
288 lined[j] = lines[hd - 1 - i];
289 lines += wpls;
290 }
291 }
292 break;
293 case 16:
294 for (i = 0; i < hd; i++) {
295 lined = datad + i * wpld;
296 lines = datas;
297 for (j = 0; j < wd; j++) {
298 if ((val = GET_DATA_TWO_BYTES(lines, hd - 1 - i)))
299 SET_DATA_TWO_BYTES(lined, j, val);
300 lines += wpls;
301 }
302 }
303 break;
304 case 8:
305 for (i = 0; i < hd; i++) {
306 lined = datad + i * wpld;
307 lines = datas;
308 for (j = 0; j < wd; j++) {
309 if ((val = GET_DATA_BYTE(lines, hd - 1 - i)))
310 SET_DATA_BYTE(lined, j, val);
311 lines += wpls;
312 }
313 }
314 break;
315 case 4:
316 for (i = 0; i < hd; i++) {
317 lined = datad + i * wpld;
318 lines = datas;
319 for (j = 0; j < wd; j++) {
320 if ((val = GET_DATA_QBIT(lines, hd - 1 - i)))
321 SET_DATA_QBIT(lined, j, val);
322 lines += wpls;
323 }
324 }
325 break;
326 case 2:
327 for (i = 0; i < hd; i++) {
328 lined = datad + i * wpld;
329 lines = datas;
330 for (j = 0; j < wd; j++) {
331 if ((val = GET_DATA_DIBIT(lines, hd - 1 - i)))
332 SET_DATA_DIBIT(lined, j, val);
333 lines += wpls;
334 }
335 }
336 break;
337 case 1:
338 nswords = hd / 32;
339 for (j = 0; j < wd; j++) {
340 lined = datad + (hd - 1) * wpld;
341 lines = datas + (wd - 1 - j) * wpls;
342 for (k = 0; k < nswords; k++) {
343 word = lines[k];
344 if (!word) {
345 lined -= 32 * wpld;
346 continue;
347 } else {
348 iend = 32 * (k + 1);
349 for (m = 0, i = 32 * k; i < iend; i++, m++) {
350 if ((word << m) & 0x80000000)
351 SET_DATA_BIT(lined, wd - 1 - j);
352 lined -= wpld;
353 }
354 }
355 }
356 for (i = 32 * nswords; i < hd; i++) {
357 if (GET_DATA_BIT(lines, i))
358 SET_DATA_BIT(lined, wd - 1 - j);
359 lined -= wpld;
360 }
361 }
362 break;
363 default:
364 pixDestroy(&pixd);
365 L_ERROR("illegal depth: %d\n", __func__, d);
366 break;
367 }
368 }
369
370 return pixd;
371}
372
373
374/*------------------------------------------------------------------*
375 * Left-right flip *
376 *------------------------------------------------------------------*/
420PIX *
422 PIX *pixs)
423{
424l_uint8 *tab;
425l_int32 w, h, d, wpl;
426l_int32 extra, shift, databpl, bpl, i, j;
427l_uint32 val;
428l_uint32 *line, *data, *buffer;
429
430 if (!pixs)
431 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
432 pixGetDimensions(pixs, &w, &h, &d);
433 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
434 return (PIX *)ERROR_PTR("pixs not in {1,2,4,8,16,32} bpp",
435 __func__, NULL);
436
437 /* Prepare pixd for in-place operation */
438 if ((pixd = pixCopy(pixd, pixs)) == NULL)
439 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
440
441 data = pixGetData(pixd);
442 wpl = pixGetWpl(pixd);
443 switch (d)
444 {
445 case 1:
446 tab = makeReverseByteTab1();
447 break;
448 case 2:
449 tab = makeReverseByteTab2();
450 break;
451 case 4:
452 tab = makeReverseByteTab4();
453 break;
454 default:
455 tab = NULL;
456 break;
457 }
458
459 /* Possibly inplace assigning return val, so on failure return pixd */
460 if ((buffer = (l_uint32 *)LEPT_CALLOC(wpl, sizeof(l_uint32))) == NULL) {
461 if (tab) LEPT_FREE(tab);
462 return (PIX *)ERROR_PTR("buffer not made", __func__, pixd);
463 }
464
465 bpl = 4 * wpl;
466 switch (d)
467 {
468 case 32:
469 for (i = 0; i < h; i++) {
470 line = data + i * wpl;
471 memcpy(buffer, line, bpl);
472 for (j = 0; j < w; j++)
473 line[j] = buffer[w - 1 - j];
474 }
475 break;
476 case 16:
477 for (i = 0; i < h; i++) {
478 line = data + i * wpl;
479 memcpy(buffer, line, bpl);
480 for (j = 0; j < w; j++) {
481 val = GET_DATA_TWO_BYTES(buffer, w - 1 - j);
482 SET_DATA_TWO_BYTES(line, j, val);
483 }
484 }
485 break;
486 case 8:
487 for (i = 0; i < h; i++) {
488 line = data + i * wpl;
489 memcpy(buffer, line, bpl);
490 for (j = 0; j < w; j++) {
491 val = GET_DATA_BYTE(buffer, w - 1 - j);
492 SET_DATA_BYTE(line, j, val);
493 }
494 }
495 break;
496 case 4:
497 extra = (w * d) & 31;
498 if (extra)
499 shift = 8 - extra / 4;
500 else
501 shift = 0;
502 if (shift)
503 rasteropHipLow(data, h, d, wpl, 0, h, shift);
504
505 databpl = (w + 1) / 2;
506 for (i = 0; i < h; i++) {
507 line = data + i * wpl;
508 memcpy(buffer, line, bpl);
509 for (j = 0; j < databpl; j++) {
510 val = GET_DATA_BYTE(buffer, bpl - 1 - j);
511 SET_DATA_BYTE(line, j, tab[val]);
512 }
513 }
514 break;
515 case 2:
516 extra = (w * d) & 31;
517 if (extra)
518 shift = 16 - extra / 2;
519 else
520 shift = 0;
521 if (shift)
522 rasteropHipLow(data, h, d, wpl, 0, h, shift);
523
524 databpl = (w + 3) / 4;
525 for (i = 0; i < h; i++) {
526 line = data + i * wpl;
527 memcpy(buffer, line, bpl);
528 for (j = 0; j < databpl; j++) {
529 val = GET_DATA_BYTE(buffer, bpl - 1 - j);
530 SET_DATA_BYTE(line, j, tab[val]);
531 }
532 }
533 break;
534 case 1:
535 extra = (w * d) & 31;
536 if (extra)
537 shift = 32 - extra;
538 else
539 shift = 0;
540 if (shift)
541 rasteropHipLow(data, h, d, wpl, 0, h, shift);
542
543 databpl = (w + 7) / 8;
544 for (i = 0; i < h; i++) {
545 line = data + i * wpl;
546 memcpy(buffer, line, bpl);
547 for (j = 0; j < databpl; j++) {
548 val = GET_DATA_BYTE(buffer, bpl - 1 - j);
549 SET_DATA_BYTE(line, j, tab[val]);
550 }
551 }
552 break;
553 default:
554 pixDestroy(&pixd);
555 L_ERROR("illegal depth: %d\n", __func__, d);
556 break;
557 }
558
559 LEPT_FREE(buffer);
560 if (tab) LEPT_FREE(tab);
561 return pixd;
562}
563
564
565/*------------------------------------------------------------------*
566 * Top-bottom flip *
567 *------------------------------------------------------------------*/
596PIX *
598 PIX *pixs)
599{
600l_int32 h, d, wpl, i, k, h2, bpl;
601l_uint32 *linet, *lineb;
602l_uint32 *data, *buffer;
603
604 if (!pixs)
605 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
606 pixGetDimensions(pixs, NULL, &h, &d);
607 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
608 return (PIX *)ERROR_PTR("pixs not in {1,2,4,8,16,32} bpp",
609 __func__, NULL);
610
611 /* Prepare pixd for in-place operation */
612 if ((pixd = pixCopy(pixd, pixs)) == NULL)
613 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
614
615 data = pixGetData(pixd);
616 wpl = pixGetWpl(pixd);
617 if ((buffer = (l_uint32 *)LEPT_CALLOC(wpl, sizeof(l_uint32))) == NULL)
618 return (PIX *)ERROR_PTR("buffer not made", __func__, pixd);
619
620 h2 = h / 2;
621 bpl = 4 * wpl;
622 for (i = 0, k = h - 1; i < h2; i++, k--) {
623 linet = data + i * wpl;
624 lineb = data + k * wpl;
625 memcpy(buffer, linet, bpl);
626 memcpy(linet, lineb, bpl);
627 memcpy(lineb, buffer, bpl);
628 }
629
630 LEPT_FREE(buffer);
631 return pixd;
632}
633
634
635/*------------------------------------------------------------------*
636 * Static byte reverse tables *
637 *------------------------------------------------------------------*/
645static l_uint8 *
647{
648l_int32 i;
649l_uint8 *tab;
650
651 tab = (l_uint8 *)LEPT_CALLOC(256, sizeof(l_uint8));
652 for (i = 0; i < 256; i++)
653 tab[i] = ((0x80 & i) >> 7) |
654 ((0x40 & i) >> 5) |
655 ((0x20 & i) >> 3) |
656 ((0x10 & i) >> 1) |
657 ((0x08 & i) << 1) |
658 ((0x04 & i) << 3) |
659 ((0x02 & i) << 5) |
660 ((0x01 & i) << 7);
661 return tab;
662}
663
664
672static l_uint8 *
674{
675l_int32 i;
676l_uint8 *tab;
677
678 tab = (l_uint8 *)LEPT_CALLOC(256, sizeof(l_uint8));
679 for (i = 0; i < 256; i++)
680 tab[i] = ((0xc0 & i) >> 6) |
681 ((0x30 & i) >> 2) |
682 ((0x0c & i) << 2) |
683 ((0x03 & i) << 6);
684 return tab;
685}
686
687
695static l_uint8 *
697{
698l_int32 i;
699l_uint8 *tab;
700
701 tab = (l_uint8 *)LEPT_CALLOC(256, sizeof(l_uint8));
702 for (i = 0; i < 256; i++)
703 tab[i] = ((0xf0 & i) >> 4) | ((0x0f & i) << 4);
704 return tab;
705}
#define GET_DATA_QBIT(pdata, n)
#define GET_DATA_TWO_BYTES(pdata, n)
#define SET_DATA_BIT(pdata, n)
#define SET_DATA_DIBIT(pdata, n, val)
#define SET_DATA_TWO_BYTES(pdata, n, val)
#define GET_DATA_BYTE(pdata, n)
#define GET_DATA_DIBIT(pdata, n)
#define SET_DATA_BYTE(pdata, n, val)
#define GET_DATA_BIT(pdata, n)
#define SET_DATA_QBIT(pdata, n, val)
PIX * pixRotate90(PIX *pixs, l_int32 direction)
pixRotate90()
Definition rotateorth.c:162
PIX * pixFlipTB(PIX *pixd, PIX *pixs)
pixFlipTB()
Definition rotateorth.c:597
PIX * pixRotate180(PIX *pixd, PIX *pixs)
pixRotate180()
Definition rotateorth.c:122
PIX * pixFlipLR(PIX *pixd, PIX *pixs)
pixFlipLR()
Definition rotateorth.c:421
PIX * pixRotateOrth(PIX *pixs, l_int32 quads)
pixRotateOrth()
Definition rotateorth.c:75
static l_uint8 * makeReverseByteTab1(void)
makeReverseByteTab1()
Definition rotateorth.c:646
static l_uint8 * makeReverseByteTab2(void)
makeReverseByteTab2()
Definition rotateorth.c:673
static l_uint8 * makeReverseByteTab4(void)
makeReverseByteTab4()
Definition rotateorth.c:696