/src/leptonica/src/rotateorth.c
Line | Count | Source (jump to first uncovered line) |
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 | | |
27 | | /*! |
28 | | * \file rotateorth.c |
29 | | * <pre> |
30 | | * |
31 | | * Top-level rotation by multiples of 90 degrees |
32 | | * PIX *pixRotateOrth() |
33 | | * |
34 | | * 180-degree rotation |
35 | | * PIX *pixRotate180() |
36 | | * |
37 | | * 90-degree rotation (both directions) |
38 | | * PIX *pixRotate90() |
39 | | * |
40 | | * Left-right flip |
41 | | * PIX *pixFlipLR() |
42 | | * |
43 | | * Top-bottom flip |
44 | | * PIX *pixFlipTB() |
45 | | * |
46 | | * Byte reverse tables |
47 | | * static l_uint8 *makeReverseByteTab1() |
48 | | * static l_uint8 *makeReverseByteTab2() |
49 | | * static l_uint8 *makeReverseByteTab4() |
50 | | * </pre> |
51 | | */ |
52 | | |
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 | | |
60 | | static l_uint8 *makeReverseByteTab1(void); |
61 | | static l_uint8 *makeReverseByteTab2(void); |
62 | | static l_uint8 *makeReverseByteTab4(void); |
63 | | |
64 | | /*------------------------------------------------------------------* |
65 | | * Top-level rotation by multiples of 90 degrees * |
66 | | *------------------------------------------------------------------*/ |
67 | | /*! |
68 | | * \brief pixRotateOrth() |
69 | | * |
70 | | * \param[in] pixs all depths |
71 | | * \param[in] quads 0-3; number of 90 degree cw rotations |
72 | | * \return pixd, or NULL on error |
73 | | */ |
74 | | PIX * |
75 | | pixRotateOrth(PIX *pixs, |
76 | | l_int32 quads) |
77 | 0 | { |
78 | 0 | if (!pixs) |
79 | 0 | return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); |
80 | 0 | if (quads < 0 || quads > 3) |
81 | 0 | return (PIX *)ERROR_PTR("quads not in {0,1,2,3}", __func__, NULL); |
82 | | |
83 | 0 | if (quads == 0) |
84 | 0 | return pixCopy(NULL, pixs); |
85 | 0 | else if (quads == 1) |
86 | 0 | return pixRotate90(pixs, 1); |
87 | 0 | else if (quads == 2) |
88 | 0 | return pixRotate180(NULL, pixs); |
89 | 0 | else /* quads == 3 */ |
90 | 0 | return pixRotate90(pixs, -1); |
91 | 0 | } |
92 | | |
93 | | |
94 | | /*------------------------------------------------------------------* |
95 | | * 180 degree rotation * |
96 | | *------------------------------------------------------------------*/ |
97 | | /*! |
98 | | * \brief pixRotate180() |
99 | | * |
100 | | * \param[in] pixd [optional]; can be null, equal to pixs, |
101 | | * or different from pixs |
102 | | * \param[in] pixs all depths |
103 | | * \return pixd, or NULL on error |
104 | | * |
105 | | * <pre> |
106 | | * Notes: |
107 | | * (1) This does a 180 rotation of the image about the center, |
108 | | * which is equivalent to a left-right flip about a vertical |
109 | | * line through the image center, followed by a top-bottom |
110 | | * flip about a horizontal line through the image center. |
111 | | * (2) There are 3 cases for input: |
112 | | * (a) pixd == null (creates a new pixd) |
113 | | * (b) pixd == pixs (in-place operation) |
114 | | * (c) pixd != pixs (existing pixd) |
115 | | * (3) For clarity, use these three patterns, respectively: |
116 | | * (a) pixd = pixRotate180(NULL, pixs); |
117 | | * (b) pixRotate180(pixs, pixs); |
118 | | * (c) pixRotate180(pixd, pixs); |
119 | | * </pre> |
120 | | */ |
121 | | PIX * |
122 | | pixRotate180(PIX *pixd, |
123 | | PIX *pixs) |
124 | 0 | { |
125 | 0 | l_int32 d; |
126 | |
|
127 | 0 | if (!pixs) |
128 | 0 | return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); |
129 | 0 | d = pixGetDepth(pixs); |
130 | 0 | if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) |
131 | 0 | return (PIX *)ERROR_PTR("pixs not in {1,2,4,8,16,32} bpp", |
132 | 0 | __func__, NULL); |
133 | | |
134 | | /* Prepare pixd for in-place operation */ |
135 | 0 | if ((pixd = pixCopy(pixd, pixs)) == NULL) |
136 | 0 | return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); |
137 | | |
138 | 0 | pixFlipLR(pixd, pixd); |
139 | 0 | pixFlipTB(pixd, pixd); |
140 | 0 | return pixd; |
141 | 0 | } |
142 | | |
143 | | |
144 | | /*------------------------------------------------------------------* |
145 | | * 90 degree rotation * |
146 | | *------------------------------------------------------------------*/ |
147 | | /*! |
148 | | * \brief pixRotate90() |
149 | | * |
150 | | * \param[in] pixs all depths |
151 | | * \param[in] direction clockwise = 1, counterclockwise = -1 |
152 | | * \return pixd, or NULL on error |
153 | | * |
154 | | * <pre> |
155 | | * Notes: |
156 | | * (1) This does a 90 degree rotation of the image about the center, |
157 | | * either cw or ccw, returning a new pix. |
158 | | * (2) The direction must be either 1 (cw) or -1 (ccw). |
159 | | * </pre> |
160 | | */ |
161 | | PIX * |
162 | | pixRotate90(PIX *pixs, |
163 | | l_int32 direction) |
164 | 0 | { |
165 | 0 | l_int32 wd, hd, d, wpls, wpld; |
166 | 0 | l_int32 i, j, k, m, iend, nswords; |
167 | 0 | l_uint32 val, word; |
168 | 0 | l_uint32 *lines, *datas, *lined, *datad; |
169 | 0 | PIX *pixd; |
170 | |
|
171 | 0 | if (!pixs) |
172 | 0 | return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); |
173 | 0 | pixGetDimensions(pixs, &hd, &wd, &d); /* note: reversed */ |
174 | 0 | if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) |
175 | 0 | return (PIX *)ERROR_PTR("pixs not in {1,2,4,8,16,32} bpp", |
176 | 0 | __func__, NULL); |
177 | 0 | if (direction != 1 && direction != -1) |
178 | 0 | return (PIX *)ERROR_PTR("invalid direction", __func__, NULL); |
179 | | |
180 | 0 | if ((pixd = pixCreate(wd, hd, d)) == NULL) |
181 | 0 | return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); |
182 | 0 | pixCopyColormap(pixd, pixs); |
183 | 0 | pixCopyResolution(pixd, pixs); |
184 | 0 | pixCopyInputFormat(pixd, pixs); |
185 | 0 | pixCopySpp(pixd, pixs); |
186 | |
|
187 | 0 | datas = pixGetData(pixs); |
188 | 0 | wpls = pixGetWpl(pixs); |
189 | 0 | datad = pixGetData(pixd); |
190 | 0 | wpld = pixGetWpl(pixd); |
191 | |
|
192 | 0 | if (direction == 1) { /* clockwise */ |
193 | 0 | switch (d) |
194 | 0 | { |
195 | 0 | case 32: |
196 | 0 | for (i = 0; i < hd; i++) { |
197 | 0 | lined = datad + i * wpld; |
198 | 0 | lines = datas + (wd - 1) * wpls; |
199 | 0 | for (j = 0; j < wd; j++) { |
200 | 0 | lined[j] = lines[i]; |
201 | 0 | lines -= wpls; |
202 | 0 | } |
203 | 0 | } |
204 | 0 | break; |
205 | 0 | case 16: |
206 | 0 | for (i = 0; i < hd; i++) { |
207 | 0 | lined = datad + i * wpld; |
208 | 0 | lines = datas + (wd - 1) * wpls; |
209 | 0 | for (j = 0; j < wd; j++) { |
210 | 0 | if ((val = GET_DATA_TWO_BYTES(lines, i))) |
211 | 0 | SET_DATA_TWO_BYTES(lined, j, val); |
212 | 0 | lines -= wpls; |
213 | 0 | } |
214 | 0 | } |
215 | 0 | break; |
216 | 0 | case 8: |
217 | 0 | for (i = 0; i < hd; i++) { |
218 | 0 | lined = datad + i * wpld; |
219 | 0 | lines = datas + (wd - 1) * wpls; |
220 | 0 | for (j = 0; j < wd; j++) { |
221 | 0 | if ((val = GET_DATA_BYTE(lines, i))) |
222 | 0 | SET_DATA_BYTE(lined, j, val); |
223 | 0 | lines -= wpls; |
224 | 0 | } |
225 | 0 | } |
226 | 0 | break; |
227 | 0 | case 4: |
228 | 0 | for (i = 0; i < hd; i++) { |
229 | 0 | lined = datad + i * wpld; |
230 | 0 | lines = datas + (wd - 1) * wpls; |
231 | 0 | for (j = 0; j < wd; j++) { |
232 | 0 | if ((val = GET_DATA_QBIT(lines, i))) |
233 | 0 | SET_DATA_QBIT(lined, j, val); |
234 | 0 | lines -= wpls; |
235 | 0 | } |
236 | 0 | } |
237 | 0 | break; |
238 | 0 | case 2: |
239 | 0 | for (i = 0; i < hd; i++) { |
240 | 0 | lined = datad + i * wpld; |
241 | 0 | lines = datas + (wd - 1) * wpls; |
242 | 0 | for (j = 0; j < wd; j++) { |
243 | 0 | if ((val = GET_DATA_DIBIT(lines, i))) |
244 | 0 | SET_DATA_DIBIT(lined, j, val); |
245 | 0 | lines -= wpls; |
246 | 0 | } |
247 | 0 | } |
248 | 0 | break; |
249 | 0 | case 1: |
250 | 0 | nswords = hd / 32; |
251 | 0 | for (j = 0; j < wd; j++) { |
252 | 0 | lined = datad; |
253 | 0 | lines = datas + (wd - 1 - j) * wpls; |
254 | 0 | for (k = 0; k < nswords; k++) { |
255 | 0 | word = lines[k]; |
256 | 0 | if (!word) { |
257 | 0 | lined += 32 * wpld; |
258 | 0 | continue; |
259 | 0 | } else { |
260 | 0 | iend = 32 * (k + 1); |
261 | 0 | for (m = 0, i = 32 * k; i < iend; i++, m++) { |
262 | 0 | if ((word << m) & 0x80000000) |
263 | 0 | SET_DATA_BIT(lined, j); |
264 | 0 | lined += wpld; |
265 | 0 | } |
266 | 0 | } |
267 | 0 | } |
268 | 0 | for (i = 32 * nswords; i < hd; i++) { |
269 | 0 | if (GET_DATA_BIT(lines, i)) |
270 | 0 | SET_DATA_BIT(lined, j); |
271 | 0 | lined += wpld; |
272 | 0 | } |
273 | 0 | } |
274 | 0 | break; |
275 | 0 | default: |
276 | 0 | pixDestroy(&pixd); |
277 | 0 | L_ERROR("illegal depth: %d\n", __func__, d); |
278 | 0 | break; |
279 | 0 | } |
280 | 0 | } else { /* direction counter-clockwise */ |
281 | 0 | switch (d) |
282 | 0 | { |
283 | 0 | case 32: |
284 | 0 | for (i = 0; i < hd; i++) { |
285 | 0 | lined = datad + i * wpld; |
286 | 0 | lines = datas; |
287 | 0 | for (j = 0; j < wd; j++) { |
288 | 0 | lined[j] = lines[hd - 1 - i]; |
289 | 0 | lines += wpls; |
290 | 0 | } |
291 | 0 | } |
292 | 0 | break; |
293 | 0 | case 16: |
294 | 0 | for (i = 0; i < hd; i++) { |
295 | 0 | lined = datad + i * wpld; |
296 | 0 | lines = datas; |
297 | 0 | for (j = 0; j < wd; j++) { |
298 | 0 | if ((val = GET_DATA_TWO_BYTES(lines, hd - 1 - i))) |
299 | 0 | SET_DATA_TWO_BYTES(lined, j, val); |
300 | 0 | lines += wpls; |
301 | 0 | } |
302 | 0 | } |
303 | 0 | break; |
304 | 0 | case 8: |
305 | 0 | for (i = 0; i < hd; i++) { |
306 | 0 | lined = datad + i * wpld; |
307 | 0 | lines = datas; |
308 | 0 | for (j = 0; j < wd; j++) { |
309 | 0 | if ((val = GET_DATA_BYTE(lines, hd - 1 - i))) |
310 | 0 | SET_DATA_BYTE(lined, j, val); |
311 | 0 | lines += wpls; |
312 | 0 | } |
313 | 0 | } |
314 | 0 | break; |
315 | 0 | case 4: |
316 | 0 | for (i = 0; i < hd; i++) { |
317 | 0 | lined = datad + i * wpld; |
318 | 0 | lines = datas; |
319 | 0 | for (j = 0; j < wd; j++) { |
320 | 0 | if ((val = GET_DATA_QBIT(lines, hd - 1 - i))) |
321 | 0 | SET_DATA_QBIT(lined, j, val); |
322 | 0 | lines += wpls; |
323 | 0 | } |
324 | 0 | } |
325 | 0 | break; |
326 | 0 | case 2: |
327 | 0 | for (i = 0; i < hd; i++) { |
328 | 0 | lined = datad + i * wpld; |
329 | 0 | lines = datas; |
330 | 0 | for (j = 0; j < wd; j++) { |
331 | 0 | if ((val = GET_DATA_DIBIT(lines, hd - 1 - i))) |
332 | 0 | SET_DATA_DIBIT(lined, j, val); |
333 | 0 | lines += wpls; |
334 | 0 | } |
335 | 0 | } |
336 | 0 | break; |
337 | 0 | case 1: |
338 | 0 | nswords = hd / 32; |
339 | 0 | for (j = 0; j < wd; j++) { |
340 | 0 | lined = datad + (hd - 1) * wpld; |
341 | 0 | lines = datas + (wd - 1 - j) * wpls; |
342 | 0 | for (k = 0; k < nswords; k++) { |
343 | 0 | word = lines[k]; |
344 | 0 | if (!word) { |
345 | 0 | lined -= 32 * wpld; |
346 | 0 | continue; |
347 | 0 | } else { |
348 | 0 | iend = 32 * (k + 1); |
349 | 0 | for (m = 0, i = 32 * k; i < iend; i++, m++) { |
350 | 0 | if ((word << m) & 0x80000000) |
351 | 0 | SET_DATA_BIT(lined, wd - 1 - j); |
352 | 0 | lined -= wpld; |
353 | 0 | } |
354 | 0 | } |
355 | 0 | } |
356 | 0 | for (i = 32 * nswords; i < hd; i++) { |
357 | 0 | if (GET_DATA_BIT(lines, i)) |
358 | 0 | SET_DATA_BIT(lined, wd - 1 - j); |
359 | 0 | lined -= wpld; |
360 | 0 | } |
361 | 0 | } |
362 | 0 | break; |
363 | 0 | default: |
364 | 0 | pixDestroy(&pixd); |
365 | 0 | L_ERROR("illegal depth: %d\n", __func__, d); |
366 | 0 | break; |
367 | 0 | } |
368 | 0 | } |
369 | | |
370 | 0 | return pixd; |
371 | 0 | } |
372 | | |
373 | | |
374 | | /*------------------------------------------------------------------* |
375 | | * Left-right flip * |
376 | | *------------------------------------------------------------------*/ |
377 | | /*! |
378 | | * \brief pixFlipLR() |
379 | | * |
380 | | * \param[in] pixd [optional]; can be null, equal to pixs, |
381 | | * or different from pixs |
382 | | * \param[in] pixs all depths |
383 | | * \return pixd, or NULL on error |
384 | | * |
385 | | * <pre> |
386 | | * Notes: |
387 | | * (1) This does a left-right flip of the image, which is |
388 | | * equivalent to a rotation out of the plane about a |
389 | | * vertical line through the image center. |
390 | | * (2) There are 3 cases for input: |
391 | | * (a) pixd == null (creates a new pixd) |
392 | | * (b) pixd == pixs (in-place operation) |
393 | | * (c) pixd != pixs (existing pixd) |
394 | | * (3) For clarity, use these three patterns, respectively: |
395 | | * (a) pixd = pixFlipLR(NULL, pixs); |
396 | | * (b) pixFlipLR(pixs, pixs); |
397 | | * (c) pixFlipLR(pixd, pixs); |
398 | | * (4) If an existing pixd is not the same size as pixs, the |
399 | | * image data will be reallocated. |
400 | | * (5) The pixel access routines allow a trivial implementation. |
401 | | * However, for d < 8, it is more efficient to right-justify |
402 | | * each line to a 32-bit boundary and then extract bytes and |
403 | | * do pixel reversing. In those cases, as in the 180 degree |
404 | | * rotation, we right-shift the data (if necessary) to |
405 | | * right-justify on the 32 bit boundary, and then read the |
406 | | * bytes off each raster line in reverse order, reversing |
407 | | * the pixels in each byte using a table. These functions |
408 | | * for 1, 2 and 4 bpp were tested against the "trivial" |
409 | | * version (shown here for 4 bpp): |
410 | | * for (i = 0; i < h; i++) { |
411 | | * line = data + i * wpl; |
412 | | * memcpy(buffer, line, bpl); |
413 | | * for (j = 0; j < w; j++) { |
414 | | * val = GET_DATA_QBIT(buffer, w - 1 - j); |
415 | | * SET_DATA_QBIT(line, j, val); |
416 | | * } |
417 | | * } |
418 | | * </pre> |
419 | | */ |
420 | | PIX * |
421 | | pixFlipLR(PIX *pixd, |
422 | | PIX *pixs) |
423 | 0 | { |
424 | 0 | l_uint8 *tab; |
425 | 0 | l_int32 w, h, d, wpl; |
426 | 0 | l_int32 extra, shift, databpl, bpl, i, j; |
427 | 0 | l_uint32 val; |
428 | 0 | l_uint32 *line, *data, *buffer; |
429 | |
|
430 | 0 | if (!pixs) |
431 | 0 | return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); |
432 | 0 | pixGetDimensions(pixs, &w, &h, &d); |
433 | 0 | if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) |
434 | 0 | return (PIX *)ERROR_PTR("pixs not in {1,2,4,8,16,32} bpp", |
435 | 0 | __func__, NULL); |
436 | | |
437 | | /* Prepare pixd for in-place operation */ |
438 | 0 | if ((pixd = pixCopy(pixd, pixs)) == NULL) |
439 | 0 | return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); |
440 | | |
441 | 0 | data = pixGetData(pixd); |
442 | 0 | wpl = pixGetWpl(pixd); |
443 | 0 | switch (d) |
444 | 0 | { |
445 | 0 | case 1: |
446 | 0 | tab = makeReverseByteTab1(); |
447 | 0 | break; |
448 | 0 | case 2: |
449 | 0 | tab = makeReverseByteTab2(); |
450 | 0 | break; |
451 | 0 | case 4: |
452 | 0 | tab = makeReverseByteTab4(); |
453 | 0 | break; |
454 | 0 | default: |
455 | 0 | tab = NULL; |
456 | 0 | break; |
457 | 0 | } |
458 | | |
459 | | /* Possibly inplace assigning return val, so on failure return pixd */ |
460 | 0 | if ((buffer = (l_uint32 *)LEPT_CALLOC(wpl, sizeof(l_uint32))) == NULL) { |
461 | 0 | if (tab) LEPT_FREE(tab); |
462 | 0 | return (PIX *)ERROR_PTR("buffer not made", __func__, pixd); |
463 | 0 | } |
464 | | |
465 | 0 | bpl = 4 * wpl; |
466 | 0 | switch (d) |
467 | 0 | { |
468 | 0 | case 32: |
469 | 0 | for (i = 0; i < h; i++) { |
470 | 0 | line = data + i * wpl; |
471 | 0 | memcpy(buffer, line, bpl); |
472 | 0 | for (j = 0; j < w; j++) |
473 | 0 | line[j] = buffer[w - 1 - j]; |
474 | 0 | } |
475 | 0 | break; |
476 | 0 | case 16: |
477 | 0 | for (i = 0; i < h; i++) { |
478 | 0 | line = data + i * wpl; |
479 | 0 | memcpy(buffer, line, bpl); |
480 | 0 | for (j = 0; j < w; j++) { |
481 | 0 | val = GET_DATA_TWO_BYTES(buffer, w - 1 - j); |
482 | 0 | SET_DATA_TWO_BYTES(line, j, val); |
483 | 0 | } |
484 | 0 | } |
485 | 0 | break; |
486 | 0 | case 8: |
487 | 0 | for (i = 0; i < h; i++) { |
488 | 0 | line = data + i * wpl; |
489 | 0 | memcpy(buffer, line, bpl); |
490 | 0 | for (j = 0; j < w; j++) { |
491 | 0 | val = GET_DATA_BYTE(buffer, w - 1 - j); |
492 | 0 | SET_DATA_BYTE(line, j, val); |
493 | 0 | } |
494 | 0 | } |
495 | 0 | break; |
496 | 0 | case 4: |
497 | 0 | extra = (w * d) & 31; |
498 | 0 | if (extra) |
499 | 0 | shift = 8 - extra / 4; |
500 | 0 | else |
501 | 0 | shift = 0; |
502 | 0 | if (shift) |
503 | 0 | rasteropHipLow(data, h, d, wpl, 0, h, shift); |
504 | |
|
505 | 0 | databpl = (w + 1) / 2; |
506 | 0 | for (i = 0; i < h; i++) { |
507 | 0 | line = data + i * wpl; |
508 | 0 | memcpy(buffer, line, bpl); |
509 | 0 | for (j = 0; j < databpl; j++) { |
510 | 0 | val = GET_DATA_BYTE(buffer, bpl - 1 - j); |
511 | 0 | SET_DATA_BYTE(line, j, tab[val]); |
512 | 0 | } |
513 | 0 | } |
514 | 0 | break; |
515 | 0 | case 2: |
516 | 0 | extra = (w * d) & 31; |
517 | 0 | if (extra) |
518 | 0 | shift = 16 - extra / 2; |
519 | 0 | else |
520 | 0 | shift = 0; |
521 | 0 | if (shift) |
522 | 0 | rasteropHipLow(data, h, d, wpl, 0, h, shift); |
523 | |
|
524 | 0 | databpl = (w + 3) / 4; |
525 | 0 | for (i = 0; i < h; i++) { |
526 | 0 | line = data + i * wpl; |
527 | 0 | memcpy(buffer, line, bpl); |
528 | 0 | for (j = 0; j < databpl; j++) { |
529 | 0 | val = GET_DATA_BYTE(buffer, bpl - 1 - j); |
530 | 0 | SET_DATA_BYTE(line, j, tab[val]); |
531 | 0 | } |
532 | 0 | } |
533 | 0 | break; |
534 | 0 | case 1: |
535 | 0 | extra = (w * d) & 31; |
536 | 0 | if (extra) |
537 | 0 | shift = 32 - extra; |
538 | 0 | else |
539 | 0 | shift = 0; |
540 | 0 | if (shift) |
541 | 0 | rasteropHipLow(data, h, d, wpl, 0, h, shift); |
542 | |
|
543 | 0 | databpl = (w + 7) / 8; |
544 | 0 | for (i = 0; i < h; i++) { |
545 | 0 | line = data + i * wpl; |
546 | 0 | memcpy(buffer, line, bpl); |
547 | 0 | for (j = 0; j < databpl; j++) { |
548 | 0 | val = GET_DATA_BYTE(buffer, bpl - 1 - j); |
549 | 0 | SET_DATA_BYTE(line, j, tab[val]); |
550 | 0 | } |
551 | 0 | } |
552 | 0 | break; |
553 | 0 | default: |
554 | 0 | pixDestroy(&pixd); |
555 | 0 | L_ERROR("illegal depth: %d\n", __func__, d); |
556 | 0 | break; |
557 | 0 | } |
558 | | |
559 | 0 | LEPT_FREE(buffer); |
560 | 0 | if (tab) LEPT_FREE(tab); |
561 | 0 | return pixd; |
562 | 0 | } |
563 | | |
564 | | |
565 | | /*------------------------------------------------------------------* |
566 | | * Top-bottom flip * |
567 | | *------------------------------------------------------------------*/ |
568 | | /*! |
569 | | * \brief pixFlipTB() |
570 | | * |
571 | | * \param[in] pixd [optional]; can be null, equal to pixs, |
572 | | * or different from pixs |
573 | | * \param[in] pixs all depths |
574 | | * \return pixd, or NULL on error |
575 | | * |
576 | | * <pre> |
577 | | * Notes: |
578 | | * (1) This does a top-bottom flip of the image, which is |
579 | | * equivalent to a rotation out of the plane about a |
580 | | * horizontal line through the image center. |
581 | | * (2) There are 3 cases for input: |
582 | | * (a) pixd == null (creates a new pixd) |
583 | | * (b) pixd == pixs (in-place operation) |
584 | | * (c) pixd != pixs (existing pixd) |
585 | | * (3) For clarity, use these three patterns, respectively: |
586 | | * (a) pixd = pixFlipTB(NULL, pixs); |
587 | | * (b) pixFlipTB(pixs, pixs); |
588 | | * (c) pixFlipTB(pixd, pixs); |
589 | | * (4) If an existing pixd is not the same size as pixs, the |
590 | | * image data will be reallocated. |
591 | | * (5) This is simple and fast. We use the memcpy function |
592 | | * to do all the work on aligned data, regardless of pixel |
593 | | * depth. |
594 | | * </pre> |
595 | | */ |
596 | | PIX * |
597 | | pixFlipTB(PIX *pixd, |
598 | | PIX *pixs) |
599 | 0 | { |
600 | 0 | l_int32 h, d, wpl, i, k, h2, bpl; |
601 | 0 | l_uint32 *linet, *lineb; |
602 | 0 | l_uint32 *data, *buffer; |
603 | |
|
604 | 0 | if (!pixs) |
605 | 0 | return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL); |
606 | 0 | pixGetDimensions(pixs, NULL, &h, &d); |
607 | 0 | if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) |
608 | 0 | return (PIX *)ERROR_PTR("pixs not in {1,2,4,8,16,32} bpp", |
609 | 0 | __func__, NULL); |
610 | | |
611 | | /* Prepare pixd for in-place operation */ |
612 | 0 | if ((pixd = pixCopy(pixd, pixs)) == NULL) |
613 | 0 | return (PIX *)ERROR_PTR("pixd not made", __func__, NULL); |
614 | | |
615 | 0 | data = pixGetData(pixd); |
616 | 0 | wpl = pixGetWpl(pixd); |
617 | 0 | if ((buffer = (l_uint32 *)LEPT_CALLOC(wpl, sizeof(l_uint32))) == NULL) |
618 | 0 | return (PIX *)ERROR_PTR("buffer not made", __func__, pixd); |
619 | | |
620 | 0 | h2 = h / 2; |
621 | 0 | bpl = 4 * wpl; |
622 | 0 | for (i = 0, k = h - 1; i < h2; i++, k--) { |
623 | 0 | linet = data + i * wpl; |
624 | 0 | lineb = data + k * wpl; |
625 | 0 | memcpy(buffer, linet, bpl); |
626 | 0 | memcpy(linet, lineb, bpl); |
627 | 0 | memcpy(lineb, buffer, bpl); |
628 | 0 | } |
629 | |
|
630 | 0 | LEPT_FREE(buffer); |
631 | 0 | return pixd; |
632 | 0 | } |
633 | | |
634 | | |
635 | | /*------------------------------------------------------------------* |
636 | | * Static byte reverse tables * |
637 | | *------------------------------------------------------------------*/ |
638 | | /*! |
639 | | * \brief makeReverseByteTab1() |
640 | | * |
641 | | * Notes: |
642 | | * (1) This generates an 8 bit lookup table for reversing |
643 | | * the order of eight 1-bit pixels. |
644 | | */ |
645 | | static l_uint8 * |
646 | | makeReverseByteTab1(void) |
647 | 0 | { |
648 | 0 | l_int32 i; |
649 | 0 | l_uint8 *tab; |
650 | |
|
651 | 0 | tab = (l_uint8 *)LEPT_CALLOC(256, sizeof(l_uint8)); |
652 | 0 | for (i = 0; i < 256; i++) |
653 | 0 | tab[i] = ((0x80 & i) >> 7) | |
654 | 0 | ((0x40 & i) >> 5) | |
655 | 0 | ((0x20 & i) >> 3) | |
656 | 0 | ((0x10 & i) >> 1) | |
657 | 0 | ((0x08 & i) << 1) | |
658 | 0 | ((0x04 & i) << 3) | |
659 | 0 | ((0x02 & i) << 5) | |
660 | 0 | ((0x01 & i) << 7); |
661 | 0 | return tab; |
662 | 0 | } |
663 | | |
664 | | |
665 | | /*! |
666 | | * \brief makeReverseByteTab2() |
667 | | * |
668 | | * Notes: |
669 | | * (1) This generates an 8 bit lookup table for reversing |
670 | | * the order of four 2-bit pixels. |
671 | | */ |
672 | | static l_uint8 * |
673 | | makeReverseByteTab2(void) |
674 | 0 | { |
675 | 0 | l_int32 i; |
676 | 0 | l_uint8 *tab; |
677 | |
|
678 | 0 | tab = (l_uint8 *)LEPT_CALLOC(256, sizeof(l_uint8)); |
679 | 0 | for (i = 0; i < 256; i++) |
680 | 0 | tab[i] = ((0xc0 & i) >> 6) | |
681 | 0 | ((0x30 & i) >> 2) | |
682 | 0 | ((0x0c & i) << 2) | |
683 | 0 | ((0x03 & i) << 6); |
684 | 0 | return tab; |
685 | 0 | } |
686 | | |
687 | | |
688 | | /*! |
689 | | * \brief makeReverseByteTab4() |
690 | | * |
691 | | * Notes: |
692 | | * (1) This generates an 8 bit lookup table for reversing |
693 | | * the order of two 4-bit pixels. |
694 | | */ |
695 | | static l_uint8 * |
696 | | makeReverseByteTab4(void) |
697 | 0 | { |
698 | 0 | l_int32 i; |
699 | 0 | l_uint8 *tab; |
700 | |
|
701 | 0 | tab = (l_uint8 *)LEPT_CALLOC(256, sizeof(l_uint8)); |
702 | 0 | for (i = 0; i < 256; i++) |
703 | 0 | tab[i] = ((0xf0 & i) >> 4) | ((0x0f & i) << 4); |
704 | 0 | return tab; |
705 | 0 | } |