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 pixconv.c
29 * <pre>
30 *
31 * These functions convert between images of different types
32 * without scaling.
33 *
34 * Conversion from 8 bpp grayscale to 1, 2, 4 and 8 bpp
35 * PIX *pixThreshold8()
36 *
37 * Conversion from colormap to full color or grayscale
38 * PIX *pixRemoveColormapGeneral()
39 * PIX *pixRemoveColormap()
40 *
41 * Add colormap losslessly (8 to 8)
42 * l_int32 pixAddGrayColormap8()
43 * PIX *pixAddMinimalGrayColormap8()
44 *
45 * Conversion from RGB color to grayscale
46 * PIX *pixConvertRGBToLuminance()
47 * PIX *pixConvertRGBToGray()
48 * PIX *pixConvertRGBToGrayFast()
49 * PIX *pixConvertRGBToGrayMinMax()
50 * PIX *pixConvertRGBToGraySatBoost()
51 * PIX *pixConvertRGBToGrayArb()
52 * PIX *pixConvertRGBToBinaryArb()
53 *
54 * Conversion from grayscale to colormap
55 * PIX *pixConvertGrayToColormap() -- 2, 4, 8 bpp
56 * PIX *pixConvertGrayToColormap8() -- 8 bpp only
57 *
58 * Colorizing conversion from grayscale to color
59 * PIX *pixColorizeGray() -- 8 bpp or cmapped
60 *
61 * Conversion from RGB color to colormap
62 * PIX *pixConvertRGBToColormap()
63 *
64 * Conversion from colormap to 1 bpp
65 * PIX *pixConvertCmapTo1()
66 *
67 * Quantization for relatively small number of colors in source
68 * l_int32 pixQuantizeIfFewColors()
69 *
70 * Conversion from 16 bpp to 8 bpp
71 * PIX *pixConvert16To8()
72 *
73 * Conversion from grayscale to false color
74 * PIX *pixConvertGrayToFalseColor()
75 *
76 * Unpacking conversion from 1 bpp to 2, 4, 8, 16 and 32 bpp
77 * PIX *pixUnpackBinary()
78 * PIX *pixConvert1To16()
79 * PIX *pixConvert1To32()
80 *
81 * Unpacking conversion from 1 bpp to 2 bpp
82 * PIX *pixConvert1To2Cmap()
83 * PIX *pixConvert1To2()
84 *
85 * Unpacking conversion from 1 bpp to 4 bpp
86 * PIX *pixConvert1To4Cmap()
87 * PIX *pixConvert1To4()
88 *
89 * Unpacking conversion from 1, 2 and 4 bpp to 8 bpp
90 * PIX *pixConvert1To8()
91 * PIX *pixConvert2To8()
92 * PIX *pixConvert4To8()
93 *
94 * Unpacking conversion from 8 bpp to 16 bpp
95 * PIX *pixConvert8To16()
96 *
97 * Top-level conversion to 1 bpp
98 * PIX *pixConvertTo1()
99 * PIX *pixConvertTo1BySampling()
100 *
101 * Top-level conversion to 2 bpp
102 * PIX *pixConvertTo2()
103 * PIX *pixConvert8To2()
104 *
105 * Top-level conversion to 4 bpp
106 * PIX *pixConvertTo4()
107 * PIX *pixConvert8To4()
108 *
109 * Top-level conversion to 8 bpp
110 * PIX *pixConvertTo8()
111 * PIX *pixConvertTo8BySampling()
112 * PIX *pixConvertTo8Colormap()
113 *
114 * Top-level conversion to 16 bpp
115 * PIX *pixConvertTo16()
116 *
117 * Top-level conversion to 32 bpp (RGB)
118 * PIX *pixConvertTo32() ***
119 * PIX *pixConvertTo32BySampling() ***
120 * PIX *pixConvert8To32() ***
121 *
122 * Top-level conversion to 8 or 32 bpp, without colormap
123 * PIX *pixConvertTo8Or32
124 *
125 * Conversion between 24 bpp and 32 bpp rgb
126 * PIX *pixConvert24To32()
127 * PIX *pixConvert32To24()
128 *
129 * Conversion between 32 bpp (1 spp) and 16 or 8 bpp
130 * PIX *pixConvert32To16()
131 * PIX *pixConvert32To8()
132 *
133 * Removal of alpha component by blending with white background
134 * PIX *pixRemoveAlpha()
135 *
136 * Addition of alpha component to 1 bpp
137 * PIX *pixAddAlphaTo1bpp()
138 *
139 * Lossless depth conversion (unpacking)
140 * PIX *pixConvertLossless()
141 *
142 * Conversion for printing in PostScript
143 * PIX *pixConvertForPSWrap()
144 *
145 * Scaling conversion to subpixel RGB
146 * PIX *pixConvertToSubpixelRGB()
147 * PIX *pixConvertGrayToSubpixelRGB()
148 * PIX *pixConvertColorToSubpixelRGB()
149 *
150 * Setting neutral point for min/max boost conversion to gray
151 * void l_setNeutralBoostVal()
152 * </pre>
153 */
154
155 #include <string.h>
156 #include <math.h>
157 #include "allheaders.h"
158
159 /* ------- Set neutral point for min/max boost conversion to gray ------ */
160 /* Call l_setNeutralBoostVal() to change this */
161 static l_int32 var_NEUTRAL_BOOST_VAL = 180;
162
163
164 #ifndef NO_CONSOLE_IO
165 #define DEBUG_CONVERT_TO_COLORMAP 0
166 #define DEBUG_UNROLLING 0
167 #endif /* ~NO_CONSOLE_IO */
168
169
170 /*-------------------------------------------------------------*
171 * Conversion from 8 bpp grayscale to 1, 2 4 and 8 bpp *
172 *-------------------------------------------------------------*/
173 /*!
174 * \brief pixThreshold8()
175 *
176 * \param[in] pixs 8 bpp grayscale
177 * \param[in] d destination depth: 1, 2, 4 or 8
178 * \param[in] nlevels number of levels to be used for colormap
179 * \param[in] cmapflag 1 if makes colormap; 0 otherwise
180 * \return pixd thresholded with standard dest thresholds,
181 * or NULL on error
182 *
183 * <pre>
184 * Notes:
185 * (1) This uses, by default, equally spaced "target" values
186 * that depend on the number of levels, with thresholds
187 * halfway between. For N levels, with separation (N-1)/255,
188 * there are N-1 fixed thresholds.
189 * (2) For 1 bpp destination, the number of levels can only be 2
190 * and if a cmap is made, black is (0,0,0) and white
191 * is (255,255,255), which is opposite to the convention
192 * without a colormap.
193 * (3) For 1, 2 and 4 bpp, the nlevels arg is used if a colormap
194 * is made; otherwise, we take the most significant bits
195 * from the src that will fit in the dest.
196 * (4) For 8 bpp, the input pixs is quantized to nlevels. The
197 * dest quantized with that mapping, either through a colormap
198 * table or directly with 8 bit values.
199 * (5) Typically you should not use make a colormap for 1 bpp dest.
200 * (6) This is not dithering. Each pixel is treated independently.
201 * </pre>
202 */
203 PIX *
pixThreshold8(PIX * pixs,l_int32 d,l_int32 nlevels,l_int32 cmapflag)204 pixThreshold8(PIX *pixs,
205 l_int32 d,
206 l_int32 nlevels,
207 l_int32 cmapflag)
208 {
209 PIX *pixd;
210 PIXCMAP *cmap;
211
212 PROCNAME("pixThreshold8");
213
214 if (!pixs)
215 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
216 if (pixGetDepth(pixs) != 8)
217 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
218 if (cmapflag && nlevels < 2)
219 return (PIX *)ERROR_PTR("nlevels must be at least 2", procName, NULL);
220
221 switch (d) {
222 case 1:
223 pixd = pixThresholdToBinary(pixs, 128);
224 if (cmapflag) {
225 cmap = pixcmapCreateLinear(1, 2);
226 pixSetColormap(pixd, cmap);
227 }
228 break;
229 case 2:
230 pixd = pixThresholdTo2bpp(pixs, nlevels, cmapflag);
231 break;
232 case 4:
233 pixd = pixThresholdTo4bpp(pixs, nlevels, cmapflag);
234 break;
235 case 8:
236 pixd = pixThresholdOn8bpp(pixs, nlevels, cmapflag);
237 break;
238 default:
239 return (PIX *)ERROR_PTR("d must be in {1,2,4,8}", procName, NULL);
240 }
241
242 if (!pixd)
243 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
244 pixCopyInputFormat(pixd, pixs);
245 return pixd;
246 }
247
248
249 /*-------------------------------------------------------------*
250 * Conversion from colormapped pix *
251 *-------------------------------------------------------------*/
252 /*!
253 * \brief pixRemoveColormapGeneral()
254 *
255 * \param[in] pixs any depth, with or without colormap
256 * \param[in] type REMOVE_CMAP_TO_BINARY,
257 * REMOVE_CMAP_TO_GRAYSCALE,
258 * REMOVE_CMAP_TO_FULL_COLOR,
259 * REMOVE_CMAP_WITH_ALPHA,
260 * REMOVE_CMAP_BASED_ON_SRC
261 * \param[in] ifnocmap L_CLONE, L_COPY
262 * \return pixd always a new pix; without colormap, or NULL on error
263 *
264 * <pre>
265 * Notes:
266 * (1) Convenience function that allows choice between returning
267 * a clone or a copy if pixs does not have a colormap.
268 * (2) See pixRemoveColormap().
269 * </pre>
270 */
271 PIX *
pixRemoveColormapGeneral(PIX * pixs,l_int32 type,l_int32 ifnocmap)272 pixRemoveColormapGeneral(PIX *pixs,
273 l_int32 type,
274 l_int32 ifnocmap)
275 {
276 PROCNAME("pixRemoveColormapGeneral");
277
278 if (!pixs)
279 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
280 if (ifnocmap != L_CLONE && ifnocmap != L_COPY)
281 return (PIX *)ERROR_PTR("invalid value for ifnocmap", procName, NULL);
282
283 if (pixGetColormap(pixs))
284 return pixRemoveColormap(pixs, type);
285
286 if (ifnocmap == L_CLONE)
287 return pixClone(pixs);
288 else
289 return pixCopy(NULL, pixs);
290 }
291
292
293 /*!
294 * \brief pixRemoveColormap()
295 *
296 * \param[in] pixs see restrictions below
297 * \param[in] type REMOVE_CMAP_TO_BINARY,
298 * REMOVE_CMAP_TO_GRAYSCALE,
299 * REMOVE_CMAP_TO_FULL_COLOR,
300 * REMOVE_CMAP_WITH_ALPHA,
301 * REMOVE_CMAP_BASED_ON_SRC
302 * \return pixd without colormap, or NULL on error
303 *
304 * <pre>
305 * Notes:
306 * (1) If pixs does not have a colormap, a clone is returned.
307 * (2) Otherwise, the input pixs is restricted to 1, 2, 4 or 8 bpp.
308 * (3) Use REMOVE_CMAP_TO_BINARY only on 1 bpp pix.
309 * (4) For grayscale conversion from RGB, use a weighted average
310 * of RGB values, and always return an 8 bpp pix, regardless
311 * of whether the input pixs depth is 2, 4 or 8 bpp.
312 * (5) REMOVE_CMAP_TO_FULL_COLOR ignores the alpha component and
313 * returns a 32 bpp pix with spp == 3 and the alpha bytes are 0.
314 * (6) For REMOVE_CMAP_BASED_ON_SRC, if there is no color, this
315 * returns either a 1 bpp or 8 bpp grayscale pix.
316 * If there is color, this returns a 32 bpp pix, with either:
317 * * 3 spp, if the alpha values are all 255 (opaque), or
318 * * 4 spp (preserving the alpha), if any alpha values are not 255.
319 * </pre>
320 */
321 PIX *
pixRemoveColormap(PIX * pixs,l_int32 type)322 pixRemoveColormap(PIX *pixs,
323 l_int32 type)
324 {
325 l_int32 sval, rval, gval, bval, val0, val1;
326 l_int32 i, j, k, w, h, d, wpls, wpld, ncolors, count;
327 l_int32 opaque, colorfound, blackwhite;
328 l_int32 *rmap, *gmap, *bmap, *amap, *graymap;
329 l_uint32 *datas, *lines, *datad, *lined, *lut;
330 l_uint32 sword, dword;
331 PIXCMAP *cmap;
332 PIX *pixd;
333
334 PROCNAME("pixRemoveColormap");
335
336 if (!pixs)
337 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
338 if ((cmap = pixGetColormap(pixs)) == NULL)
339 return pixClone(pixs);
340
341 if (type != REMOVE_CMAP_TO_BINARY &&
342 type != REMOVE_CMAP_TO_GRAYSCALE &&
343 type != REMOVE_CMAP_TO_FULL_COLOR &&
344 type != REMOVE_CMAP_WITH_ALPHA &&
345 type != REMOVE_CMAP_BASED_ON_SRC) {
346 L_WARNING("Invalid type; converting based on src\n", procName);
347 type = REMOVE_CMAP_BASED_ON_SRC;
348 }
349
350 pixGetDimensions(pixs, &w, &h, &d);
351 if (d != 1 && d != 2 && d != 4 && d != 8)
352 return (PIX *)ERROR_PTR("pixs must be {1,2,4,8} bpp", procName, NULL);
353
354 if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap, &amap))
355 return (PIX *)ERROR_PTR("colormap arrays not made", procName, NULL);
356
357 if (d != 1 && type == REMOVE_CMAP_TO_BINARY) {
358 L_WARNING("not 1 bpp; can't remove cmap to binary\n", procName);
359 type = REMOVE_CMAP_BASED_ON_SRC;
360 }
361
362 /* Select output type depending on colormap content */
363 if (type == REMOVE_CMAP_BASED_ON_SRC) {
364 pixcmapIsOpaque(cmap, &opaque);
365 pixcmapHasColor(cmap, &colorfound);
366 pixcmapIsBlackAndWhite(cmap, &blackwhite);
367 if (!opaque) { /* save the alpha */
368 type = REMOVE_CMAP_WITH_ALPHA;
369 } else if (colorfound) {
370 type = REMOVE_CMAP_TO_FULL_COLOR;
371 } else { /* opaque and no color */
372 if (d == 1 && blackwhite) /* can binarize without loss */
373 type = REMOVE_CMAP_TO_BINARY;
374 else
375 type = REMOVE_CMAP_TO_GRAYSCALE;
376 }
377 }
378
379 ncolors = pixcmapGetCount(cmap);
380 datas = pixGetData(pixs);
381 wpls = pixGetWpl(pixs);
382 if (type == REMOVE_CMAP_TO_BINARY) {
383 if ((pixd = pixCopy(NULL, pixs)) == NULL) {
384 L_ERROR("pixd not made\n", procName);
385 goto cleanup_arrays;
386 }
387 pixcmapGetColor(cmap, 0, &rval, &gval, &bval);
388 val0 = rval + gval + bval;
389 pixcmapGetColor(cmap, 1, &rval, &gval, &bval);
390 val1 = rval + gval + bval;
391 if (val0 < val1) /* photometrically inverted from standard */
392 pixInvert(pixd, pixd);
393 pixDestroyColormap(pixd);
394 } else if (type == REMOVE_CMAP_TO_GRAYSCALE) {
395 if ((pixd = pixCreate(w, h, 8)) == NULL) {
396 L_ERROR("pixd not made\n", procName);
397 goto cleanup_arrays;
398 }
399 pixCopyResolution(pixd, pixs);
400 pixCopyInputFormat(pixd, pixs);
401 datad = pixGetData(pixd);
402 wpld = pixGetWpl(pixd);
403 graymap = (l_int32 *)LEPT_CALLOC(ncolors, sizeof(l_int32));
404 for (i = 0; i < pixcmapGetCount(cmap); i++) {
405 graymap[i] = (l_int32)(L_RED_WEIGHT * rmap[i] +
406 L_GREEN_WEIGHT * gmap[i] +
407 L_BLUE_WEIGHT * bmap[i] + 0.5);
408 }
409 for (i = 0; i < h; i++) {
410 lines = datas + i * wpls;
411 lined = datad + i * wpld;
412 switch (d) /* depth test above; no default permitted */
413 {
414 case 8:
415 /* Unrolled 4x */
416 for (j = 0, count = 0; j + 3 < w; j += 4, count++) {
417 sword = lines[count];
418 dword = (graymap[(sword >> 24) & 0xff] << 24) |
419 (graymap[(sword >> 16) & 0xff] << 16) |
420 (graymap[(sword >> 8) & 0xff] << 8) |
421 graymap[sword & 0xff];
422 lined[count] = dword;
423 }
424 /* Cleanup partial word */
425 for (; j < w; j++) {
426 sval = GET_DATA_BYTE(lines, j);
427 gval = graymap[sval];
428 SET_DATA_BYTE(lined, j, gval);
429 }
430 #if DEBUG_UNROLLING
431 #define CHECK_VALUE(a, b, c) if (GET_DATA_BYTE(a, b) != c) { \
432 fprintf(stderr, "Error: mismatch at %d, %d vs %d\n", \
433 j, GET_DATA_BYTE(a, b), c); }
434 for (j = 0; j < w; j++) {
435 sval = GET_DATA_BYTE(lines, j);
436 gval = graymap[sval];
437 CHECK_VALUE(lined, j, gval);
438 }
439 #endif
440 break;
441 case 4:
442 /* Unrolled 8x */
443 for (j = 0, count = 0; j + 7 < w; j += 8, count++) {
444 sword = lines[count];
445 dword = (graymap[(sword >> 28) & 0xf] << 24) |
446 (graymap[(sword >> 24) & 0xf] << 16) |
447 (graymap[(sword >> 20) & 0xf] << 8) |
448 graymap[(sword >> 16) & 0xf];
449 lined[2 * count] = dword;
450 dword = (graymap[(sword >> 12) & 0xf] << 24) |
451 (graymap[(sword >> 8) & 0xf] << 16) |
452 (graymap[(sword >> 4) & 0xf] << 8) |
453 graymap[sword & 0xf];
454 lined[2 * count + 1] = dword;
455 }
456 /* Cleanup partial word */
457 for (; j < w; j++) {
458 sval = GET_DATA_QBIT(lines, j);
459 gval = graymap[sval];
460 SET_DATA_BYTE(lined, j, gval);
461 }
462 #if DEBUG_UNROLLING
463 for (j = 0; j < w; j++) {
464 sval = GET_DATA_QBIT(lines, j);
465 gval = graymap[sval];
466 CHECK_VALUE(lined, j, gval);
467 }
468 #endif
469 break;
470 case 2:
471 /* Unrolled 16x */
472 for (j = 0, count = 0; j + 15 < w; j += 16, count++) {
473 sword = lines[count];
474 dword = (graymap[(sword >> 30) & 0x3] << 24) |
475 (graymap[(sword >> 28) & 0x3] << 16) |
476 (graymap[(sword >> 26) & 0x3] << 8) |
477 graymap[(sword >> 24) & 0x3];
478 lined[4 * count] = dword;
479 dword = (graymap[(sword >> 22) & 0x3] << 24) |
480 (graymap[(sword >> 20) & 0x3] << 16) |
481 (graymap[(sword >> 18) & 0x3] << 8) |
482 graymap[(sword >> 16) & 0x3];
483 lined[4 * count + 1] = dword;
484 dword = (graymap[(sword >> 14) & 0x3] << 24) |
485 (graymap[(sword >> 12) & 0x3] << 16) |
486 (graymap[(sword >> 10) & 0x3] << 8) |
487 graymap[(sword >> 8) & 0x3];
488 lined[4 * count + 2] = dword;
489 dword = (graymap[(sword >> 6) & 0x3] << 24) |
490 (graymap[(sword >> 4) & 0x3] << 16) |
491 (graymap[(sword >> 2) & 0x3] << 8) |
492 graymap[sword & 0x3];
493 lined[4 * count + 3] = dword;
494 }
495 /* Cleanup partial word */
496 for (; j < w; j++) {
497 sval = GET_DATA_DIBIT(lines, j);
498 gval = graymap[sval];
499 SET_DATA_BYTE(lined, j, gval);
500 }
501 #if DEBUG_UNROLLING
502 for (j = 0; j < w; j++) {
503 sval = GET_DATA_DIBIT(lines, j);
504 gval = graymap[sval];
505 CHECK_VALUE(lined, j, gval);
506 }
507 #endif
508 break;
509 case 1:
510 /* Unrolled 8x */
511 for (j = 0, count = 0; j + 31 < w; j += 32, count++) {
512 sword = lines[count];
513 for (k = 0; k < 4; k++) {
514 /* The top byte is always the relevant one */
515 dword = (graymap[(sword >> 31) & 0x1] << 24) |
516 (graymap[(sword >> 30) & 0x1] << 16) |
517 (graymap[(sword >> 29) & 0x1] << 8) |
518 graymap[(sword >> 28) & 0x1];
519 lined[8 * count + 2 * k] = dword;
520 dword = (graymap[(sword >> 27) & 0x1] << 24) |
521 (graymap[(sword >> 26) & 0x1] << 16) |
522 (graymap[(sword >> 25) & 0x1] << 8) |
523 graymap[(sword >> 24) & 0x1];
524 lined[8 * count + 2 * k + 1] = dword;
525 sword <<= 8; /* Move up the next byte */
526 }
527 }
528 /* Cleanup partial word */
529 for (; j < w; j++) {
530 sval = GET_DATA_BIT(lines, j);
531 gval = graymap[sval];
532 SET_DATA_BYTE(lined, j, gval);
533 }
534 #if DEBUG_UNROLLING
535 for (j = 0; j < w; j++) {
536 sval = GET_DATA_BIT(lines, j);
537 gval = graymap[sval];
538 CHECK_VALUE(lined, j, gval);
539 }
540 #undef CHECK_VALUE
541 #endif
542 break;
543 default:
544 return NULL;
545 }
546 }
547 if (graymap)
548 LEPT_FREE(graymap);
549 } else { /* type == REMOVE_CMAP_TO_FULL_COLOR or REMOVE_CMAP_WITH_ALPHA */
550 if ((pixd = pixCreate(w, h, 32)) == NULL) {
551 L_ERROR("pixd not made\n", procName);
552 goto cleanup_arrays;
553 }
554 pixCopyInputFormat(pixd, pixs);
555 pixCopyResolution(pixd, pixs);
556 if (type == REMOVE_CMAP_WITH_ALPHA)
557 pixSetSpp(pixd, 4);
558 datad = pixGetData(pixd);
559 wpld = pixGetWpl(pixd);
560 lut = (l_uint32 *)LEPT_CALLOC(ncolors, sizeof(l_uint32));
561 for (i = 0; i < ncolors; i++) {
562 if (type == REMOVE_CMAP_TO_FULL_COLOR)
563 composeRGBPixel(rmap[i], gmap[i], bmap[i], lut + i);
564 else /* full color plus alpha */
565 composeRGBAPixel(rmap[i], gmap[i], bmap[i], amap[i], lut + i);
566 }
567
568 for (i = 0; i < h; i++) {
569 lines = datas + i * wpls;
570 lined = datad + i * wpld;
571 for (j = 0; j < w; j++) {
572 if (d == 8)
573 sval = GET_DATA_BYTE(lines, j);
574 else if (d == 4)
575 sval = GET_DATA_QBIT(lines, j);
576 else if (d == 2)
577 sval = GET_DATA_DIBIT(lines, j);
578 else /* (d == 1) */
579 sval = GET_DATA_BIT(lines, j);
580 if (sval >= ncolors)
581 L_WARNING("pixel value out of bounds\n", procName);
582 else
583 lined[j] = lut[sval];
584 }
585 }
586 LEPT_FREE(lut);
587 }
588
589 cleanup_arrays:
590 LEPT_FREE(rmap);
591 LEPT_FREE(gmap);
592 LEPT_FREE(bmap);
593 LEPT_FREE(amap);
594 return pixd;
595 }
596
597
598 /*-------------------------------------------------------------*
599 * Add colormap losslessly (8 to 8) *
600 *-------------------------------------------------------------*/
601 /*!
602 * \brief pixAddGrayColormap8()
603 *
604 * \param[in] pixs 8 bpp
605 * \return 0 if OK, 1 on error
606 *
607 * <pre>
608 * Notes:
609 * (1) If pixs has a colormap, this is a no-op.
610 * </pre>
611 */
612 l_int32
pixAddGrayColormap8(PIX * pixs)613 pixAddGrayColormap8(PIX *pixs)
614 {
615 PIXCMAP *cmap;
616
617 PROCNAME("pixAddGrayColormap8");
618
619 if (!pixs || pixGetDepth(pixs) != 8)
620 return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
621 if (pixGetColormap(pixs))
622 return 0;
623
624 cmap = pixcmapCreateLinear(8, 256);
625 pixSetColormap(pixs, cmap);
626 return 0;
627 }
628
629
630 /*!
631 * \brief pixAddMinimalGrayColormap8()
632 *
633 * \param[in] pixs 8 bpp
634 * \return 0 if OK, 1 on error
635 *
636 * <pre>
637 * Notes:
638 * (1) This generates a colormapped version of the input image
639 * that has the same number of colormap entries as the
640 * input image has unique gray levels.
641 * </pre>
642 */
643 PIX *
pixAddMinimalGrayColormap8(PIX * pixs)644 pixAddMinimalGrayColormap8(PIX *pixs)
645 {
646 l_int32 ncolors, w, h, i, j, wpl1, wpld, index, val;
647 l_int32 *inta, *revmap;
648 l_uint32 *data1, *datad, *line1, *lined;
649 PIX *pix1, *pixd;
650 PIXCMAP *cmap;
651
652 PROCNAME("pixAddMinimalGrayColormap8");
653
654 if (!pixs || pixGetDepth(pixs) != 8)
655 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
656
657 /* Eliminate the easy cases */
658 pixNumColors(pixs, 1, &ncolors);
659 cmap = pixGetColormap(pixs);
660 if (cmap) {
661 if (pixcmapGetCount(cmap) == ncolors) /* irreducible */
662 return pixCopy(NULL, pixs);
663 else
664 pix1 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
665 } else {
666 if (ncolors == 256) {
667 pix1 = pixCopy(NULL, pixs);
668 pixAddGrayColormap8(pix1);
669 return pix1;
670 }
671 pix1 = pixClone(pixs);
672 }
673
674 /* Find the gray levels and make a reverse map */
675 pixGetDimensions(pix1, &w, &h, NULL);
676 data1 = pixGetData(pix1);
677 wpl1 = pixGetWpl(pix1);
678 inta = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
679 for (i = 0; i < h; i++) {
680 line1 = data1 + i * wpl1;
681 for (j = 0; j < w; j++) {
682 val = GET_DATA_BYTE(line1, j);
683 inta[val] = 1;
684 }
685 }
686 cmap = pixcmapCreate(8);
687 revmap = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
688 for (i = 0, index = 0; i < 256; i++) {
689 if (inta[i]) {
690 pixcmapAddColor(cmap, i, i, i);
691 revmap[i] = index++;
692 }
693 }
694
695 /* Set all pixels in pixd to the colormap index */
696 pixd = pixCreateTemplate(pix1);
697 pixSetColormap(pixd, cmap);
698 pixCopyInputFormat(pixd, pixs);
699 pixCopyResolution(pixd, pixs);
700 datad = pixGetData(pixd);
701 wpld = pixGetWpl(pixd);
702 for (i = 0; i < h; i++) {
703 line1 = data1 + i * wpl1;
704 lined = datad + i * wpld;
705 for (j = 0; j < w; j++) {
706 val = GET_DATA_BYTE(line1, j);
707 SET_DATA_BYTE(lined, j, revmap[val]);
708 }
709 }
710
711 pixDestroy(&pix1);
712 LEPT_FREE(inta);
713 LEPT_FREE(revmap);
714 return pixd;
715 }
716
717
718 /*-------------------------------------------------------------*
719 * Conversion from RGB color to grayscale *
720 *-------------------------------------------------------------*/
721 /*!
722 * \brief pixConvertRGBToLuminance()
723 *
724 * \param[in] pixs 32 bpp RGB
725 * \return 8 bpp pix, or NULL on error
726 *
727 * <pre>
728 * Notes:
729 * (1) Use a standard luminance conversion.
730 * </pre>
731 */
732 PIX *
pixConvertRGBToLuminance(PIX * pixs)733 pixConvertRGBToLuminance(PIX *pixs)
734 {
735 return pixConvertRGBToGray(pixs, 0.0, 0.0, 0.0);
736 }
737
738
739 /*!
740 * \brief pixConvertRGBToGray()
741 *
742 * \param[in] pixs 32 bpp RGB
743 * \param[in] rwt, gwt, bwt non-negative; these should add to 1.0,
744 * or use 0.0 for default
745 * \return 8 bpp pix, or NULL on error
746 *
747 * <pre>
748 * Notes:
749 * (1) Use a weighted average of the RGB values.
750 * </pre>
751 */
752 PIX *
pixConvertRGBToGray(PIX * pixs,l_float32 rwt,l_float32 gwt,l_float32 bwt)753 pixConvertRGBToGray(PIX *pixs,
754 l_float32 rwt,
755 l_float32 gwt,
756 l_float32 bwt)
757 {
758 l_int32 i, j, w, h, wpls, wpld, val;
759 l_uint32 word;
760 l_uint32 *datas, *lines, *datad, *lined;
761 l_float32 sum;
762 PIX *pixd;
763
764 PROCNAME("pixConvertRGBToGray");
765
766 if (!pixs)
767 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
768 if (pixGetDepth(pixs) != 32)
769 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
770 if (rwt < 0.0 || gwt < 0.0 || bwt < 0.0)
771 return (PIX *)ERROR_PTR("weights not all >= 0.0", procName, NULL);
772
773 /* Make sure the sum of weights is 1.0; otherwise, you can get
774 * overflow in the gray value. */
775 if (rwt == 0.0 && gwt == 0.0 && bwt == 0.0) {
776 rwt = L_RED_WEIGHT;
777 gwt = L_GREEN_WEIGHT;
778 bwt = L_BLUE_WEIGHT;
779 }
780 sum = rwt + gwt + bwt;
781 if (L_ABS(sum - 1.0) > 0.0001) { /* maintain ratios with sum == 1.0 */
782 L_WARNING("weights don't sum to 1; maintaining ratios\n", procName);
783 rwt = rwt / sum;
784 gwt = gwt / sum;
785 bwt = bwt / sum;
786 }
787
788 pixGetDimensions(pixs, &w, &h, NULL);
789 datas = pixGetData(pixs);
790 wpls = pixGetWpl(pixs);
791 if ((pixd = pixCreate(w, h, 8)) == NULL)
792 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
793 pixCopyResolution(pixd, pixs);
794 pixCopyInputFormat(pixd, pixs);
795 datad = pixGetData(pixd);
796 wpld = pixGetWpl(pixd);
797
798 for (i = 0; i < h; i++) {
799 lines = datas + i * wpls;
800 lined = datad + i * wpld;
801 for (j = 0; j < w; j++) {
802 word = *(lines + j);
803 val = (l_int32)(rwt * ((word >> L_RED_SHIFT) & 0xff) +
804 gwt * ((word >> L_GREEN_SHIFT) & 0xff) +
805 bwt * ((word >> L_BLUE_SHIFT) & 0xff) + 0.5);
806 SET_DATA_BYTE(lined, j, val);
807 }
808 }
809
810 return pixd;
811 }
812
813
814 /*!
815 * \brief pixConvertRGBToGrayFast()
816 *
817 * \param[in] pixs 32 bpp RGB
818 * \return 8 bpp pix, or NULL on error
819 *
820 * <pre>
821 * Notes:
822 * (1) This function should be used if speed of conversion
823 * is paramount, and the green channel can be used as
824 * a fair representative of the RGB intensity. It is
825 * several times faster than pixConvertRGBToGray().
826 * (2) To combine RGB to gray conversion with subsampling,
827 * use pixScaleRGBToGrayFast() instead.
828 * </pre>
829 */
830 PIX *
pixConvertRGBToGrayFast(PIX * pixs)831 pixConvertRGBToGrayFast(PIX *pixs)
832 {
833 l_int32 i, j, w, h, wpls, wpld, val;
834 l_uint32 *datas, *lines, *datad, *lined;
835 PIX *pixd;
836
837 PROCNAME("pixConvertRGBToGrayFast");
838
839 if (!pixs)
840 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
841 if (pixGetDepth(pixs) != 32)
842 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
843
844 pixGetDimensions(pixs, &w, &h, NULL);
845 datas = pixGetData(pixs);
846 wpls = pixGetWpl(pixs);
847 if ((pixd = pixCreate(w, h, 8)) == NULL)
848 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
849 pixCopyResolution(pixd, pixs);
850 pixCopyInputFormat(pixd, pixs);
851 datad = pixGetData(pixd);
852 wpld = pixGetWpl(pixd);
853
854 for (i = 0; i < h; i++) {
855 lines = datas + i * wpls;
856 lined = datad + i * wpld;
857 for (j = 0; j < w; j++, lines++) {
858 val = ((*lines) >> L_GREEN_SHIFT) & 0xff;
859 SET_DATA_BYTE(lined, j, val);
860 }
861 }
862
863 return pixd;
864 }
865
866
867 /*!
868 * \brief pixConvertRGBToGrayMinMax()
869 *
870 * \param[in] pixs 32 bpp RGB
871 * \param[in] type L_CHOOSE_MIN, L_CHOOSE_MAX, L_CHOOSE_MAXDIFF,
872 * L_CHOOSE_MIN_BOOST, L_CHOOSE_MAX_BOOST
873 * \return 8 bpp pix, or NULL on error
874 *
875 * <pre>
876 * Notes:
877 * (1) This chooses various components or combinations of them,
878 * from the three RGB sample values. In addition to choosing
879 * the min, max, and maxdiff (difference between max and min),
880 * this also allows boosting the min and max about a reference
881 * value.
882 * (2) The default reference value for boosting the min and max
883 * is 200. This can be changed with l_setNeutralBoostVal()
884 * </pre>
885 */
886 PIX *
pixConvertRGBToGrayMinMax(PIX * pixs,l_int32 type)887 pixConvertRGBToGrayMinMax(PIX *pixs,
888 l_int32 type)
889 {
890 l_int32 i, j, w, h, wpls, wpld, rval, gval, bval, val, minval, maxval;
891 l_uint32 *datas, *lines, *datad, *lined;
892 PIX *pixd;
893
894 PROCNAME("pixConvertRGBToGrayMinMax");
895
896 if (!pixs)
897 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
898 if (pixGetDepth(pixs) != 32)
899 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
900 if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX &&
901 type != L_CHOOSE_MAXDIFF && type != L_CHOOSE_MIN_BOOST &&
902 type != L_CHOOSE_MAX_BOOST)
903 return (PIX *)ERROR_PTR("invalid type", procName, NULL);
904
905 pixGetDimensions(pixs, &w, &h, NULL);
906 datas = pixGetData(pixs);
907 wpls = pixGetWpl(pixs);
908 if ((pixd = pixCreate(w, h, 8)) == NULL)
909 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
910 pixCopyResolution(pixd, pixs);
911 pixCopyInputFormat(pixd, pixs);
912 datad = pixGetData(pixd);
913 wpld = pixGetWpl(pixd);
914
915 for (i = 0; i < h; i++) {
916 lines = datas + i * wpls;
917 lined = datad + i * wpld;
918 for (j = 0; j < w; j++) {
919 extractRGBValues(lines[j], &rval, &gval, &bval);
920 if (type == L_CHOOSE_MIN || type == L_CHOOSE_MIN_BOOST) {
921 val = L_MIN(rval, gval);
922 val = L_MIN(val, bval);
923 if (type == L_CHOOSE_MIN_BOOST)
924 val = L_MIN(255, (val * val) / var_NEUTRAL_BOOST_VAL);
925 } else if (type == L_CHOOSE_MAX || type == L_CHOOSE_MAX_BOOST) {
926 val = L_MAX(rval, gval);
927 val = L_MAX(val, bval);
928 if (type == L_CHOOSE_MAX_BOOST)
929 val = L_MIN(255, (val * val) / var_NEUTRAL_BOOST_VAL);
930 } else { /* L_CHOOSE_MAXDIFF */
931 minval = L_MIN(rval, gval);
932 minval = L_MIN(minval, bval);
933 maxval = L_MAX(rval, gval);
934 maxval = L_MAX(maxval, bval);
935 val = maxval - minval;
936 }
937 SET_DATA_BYTE(lined, j, val);
938 }
939 }
940
941 return pixd;
942 }
943
944
945 /*!
946 * \brief pixConvertRGBToGraySatBoost()
947 *
948 * \param[in] pixs 32 bpp rgb
949 * \param[in] refval between 1 and 255; typ. less than 128
950 * \return pixd 8 bpp, or NULL on error
951 *
952 * <pre>
953 * Notes:
954 * (1) This returns the max component value, boosted by
955 * the saturation. The maximum boost occurs where
956 * the maximum component value is equal to some reference value.
957 * This particular weighting is due to Dany Qumsiyeh.
958 * (2) For gray pixels (zero saturation), this returns
959 * the intensity of any component.
960 * (3) For fully saturated pixels ('fullsat'), this rises linearly
961 * with the max value and has a slope equal to 255 divided
962 * by the reference value; for a max value greater than
963 * the reference value, it is clipped to 255.
964 * (4) For saturation values in between, the output is a linear
965 * combination of (2) and (3), weighted by saturation.
966 * It falls between these two curves, and does not exceed 255.
967 * (5) This can be useful for distinguishing an object that has nonzero
968 * saturation from a gray background. For this, the refval
969 * should be chosen near the expected value of the background,
970 * to achieve maximum saturation boost there.
971 * </pre>
972 */
973 PIX *
pixConvertRGBToGraySatBoost(PIX * pixs,l_int32 refval)974 pixConvertRGBToGraySatBoost(PIX *pixs,
975 l_int32 refval)
976 {
977 l_int32 w, h, d, i, j, wplt, wpld;
978 l_int32 rval, gval, bval, sval, minrg, maxrg, min, max, delta;
979 l_int32 fullsat, newval;
980 l_float32 *invmax, *ratio;
981 l_uint32 *linet, *lined, *datat, *datad;
982 PIX *pixt, *pixd;
983
984 PROCNAME("pixConvertRGBToGraySatBoost");
985
986 if (!pixs)
987 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
988 pixGetDimensions(pixs, &w, &h, &d);
989 if (d != 32 && !pixGetColormap(pixs))
990 return (PIX *)ERROR_PTR("pixs not cmapped or rgb", procName, NULL);
991 if (refval < 1 || refval > 255)
992 return (PIX *)ERROR_PTR("refval not in [1 ... 255]", procName, NULL);
993
994 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
995 pixd = pixCreate(w, h, 8);
996 pixCopyResolution(pixd, pixs);
997 pixCopyInputFormat(pixd, pixs);
998 wplt = pixGetWpl(pixt);
999 datat = pixGetData(pixt);
1000 wpld = pixGetWpl(pixd);
1001 datad = pixGetData(pixd);
1002 invmax = (l_float32 *)LEPT_CALLOC(256, sizeof(l_float32));
1003 ratio = (l_float32 *)LEPT_CALLOC(256, sizeof(l_float32));
1004 for (i = 1; i < 256; i++) { /* i == 0 --> delta = sval = newval = 0 */
1005 invmax[i] = 1.0 / (l_float32)i;
1006 ratio[i] = (l_float32)i / (l_float32)refval;
1007 }
1008 for (i = 0; i < h; i++) {
1009 linet = datat + i * wplt;
1010 lined = datad + i * wpld;
1011 for (j = 0; j < w; j++) {
1012 extractRGBValues(linet[j], &rval, &gval, &bval);
1013 minrg = L_MIN(rval, gval);
1014 min = L_MIN(minrg, bval);
1015 maxrg = L_MAX(rval, gval);
1016 max = L_MAX(maxrg, bval);
1017 delta = max - min;
1018 if (delta == 0) /* gray; no chroma */
1019 sval = 0;
1020 else
1021 sval = (l_int32)(255. * (l_float32)delta * invmax[max] + 0.5);
1022
1023 fullsat = L_MIN(255, 255 * ratio[max]);
1024 newval = (sval * fullsat + (255 - sval) * max) / 255;
1025 SET_DATA_BYTE(lined, j, newval);
1026 }
1027 }
1028
1029 pixDestroy(&pixt);
1030 LEPT_FREE(invmax);
1031 LEPT_FREE(ratio);
1032 return pixd;
1033 }
1034
1035
1036 /*!
1037 * \brief pixConvertRGBToGrayArb()
1038 *
1039 * \param[in] pixs 32 bpp RGB
1040 * \param[in] rc, gc, bc arithmetic factors; can be negative
1041 * \return 8 bpp pix, or NULL on error
1042 *
1043 * <pre>
1044 * Notes:
1045 * (1) This converts to gray using an arbitrary linear combination
1046 * of the rgb color components. It differs from pixConvertToGray(),
1047 * which uses only positive coefficients that sum to 1.
1048 * (2) The gray output values are clipped to 0 and 255.
1049 * </pre>
1050 */
1051 PIX *
pixConvertRGBToGrayArb(PIX * pixs,l_float32 rc,l_float32 gc,l_float32 bc)1052 pixConvertRGBToGrayArb(PIX *pixs,
1053 l_float32 rc,
1054 l_float32 gc,
1055 l_float32 bc)
1056 {
1057 l_int32 i, j, w, h, wpls, wpld, rval, gval, bval, val;
1058 l_uint32 *datas, *lines, *datad, *lined;
1059 PIX *pixd;
1060
1061 PROCNAME("pixConvertRGBToGrayArb");
1062
1063 if (!pixs)
1064 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1065 if (pixGetDepth(pixs) != 32)
1066 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
1067 if (rc <= 0 && gc <= 0 && bc <= 0)
1068 return (PIX *)ERROR_PTR("all coefficients <= 0", procName, NULL);
1069
1070 pixGetDimensions(pixs, &w, &h, NULL);
1071 datas = pixGetData(pixs);
1072 wpls = pixGetWpl(pixs);
1073 if ((pixd = pixCreate(w, h, 8)) == NULL)
1074 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1075 pixCopyResolution(pixd, pixs);
1076 pixCopyInputFormat(pixd, pixs);
1077 datad = pixGetData(pixd);
1078 wpld = pixGetWpl(pixd);
1079
1080 for (i = 0; i < h; i++) {
1081 lines = datas + i * wpls;
1082 lined = datad + i * wpld;
1083 for (j = 0; j < w; j++) {
1084 extractRGBValues(lines[j], &rval, &gval, &bval);
1085 val = (l_int32)(rc * rval + gc * gval + bc * bval);
1086 val = L_MIN(255, L_MAX(0, val));
1087 SET_DATA_BYTE(lined, j, val);
1088 }
1089 }
1090
1091 return pixd;
1092 }
1093
1094
1095 /*!
1096 * \brief pixConvertRGBToBinaryArb()
1097 *
1098 * \param[in] pixs 32 bpp RGB
1099 * \param[in] rc, gc, bc arithmetic factors; can be negative
1100 * \param[in] thresh binarization threshold
1101 * \param[in] relation L_SELECT_IF_LT, L_SELECT_IF_GT
1102 * L_SELECT_IF_LTE, L_SELECT_IF_GTE
1103 * \return 1 bpp pix, or NULL on error
1104 *
1105 * <pre>
1106 * Notes:
1107 * (1) This makes a 1 bpp mask from an RGB image, using an arbitrary
1108 * linear combination of the rgb color components, along with
1109 * a threshold and a selection choice of the gray value relative
1110 * to %thresh.
1111 * </pre>
1112 */
1113 PIX *
pixConvertRGBToBinaryArb(PIX * pixs,l_float32 rc,l_float32 gc,l_float32 bc,l_int32 thresh,l_int32 relation)1114 pixConvertRGBToBinaryArb(PIX *pixs,
1115 l_float32 rc,
1116 l_float32 gc,
1117 l_float32 bc,
1118 l_int32 thresh,
1119 l_int32 relation)
1120 {
1121 l_int32 threshold;
1122 PIX *pix1, *pix2;
1123
1124 PROCNAME("pixConvertRGBToBinaryArb");
1125
1126 if (!pixs || pixGetDepth(pixs) != 32)
1127 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
1128 if (rc <= 0 && gc <= 0 && bc <= 0)
1129 return (PIX *)ERROR_PTR("all coefficients <= 0", procName, NULL);
1130 if (relation != L_SELECT_IF_LT && relation != L_SELECT_IF_GT &&
1131 relation != L_SELECT_IF_LTE && relation != L_SELECT_IF_GTE)
1132 return (PIX *)ERROR_PTR("invalid relation", procName, NULL);
1133
1134 pix1 = pixConvertRGBToGrayArb(pixs, rc, gc, bc);
1135 threshold = (relation == L_SELECT_IF_LTE || relation == L_SELECT_IF_GT) ?
1136 thresh : thresh + 1;
1137 pix2 = pixThresholdToBinary(pix1, threshold);
1138 if (relation == L_SELECT_IF_GT || relation == L_SELECT_IF_GTE)
1139 pixInvert(pix2, pix2);
1140 pixDestroy(&pix1);
1141 return pix2;
1142 }
1143
1144
1145 /*---------------------------------------------------------------------------*
1146 * Conversion from grayscale to colormap *
1147 *---------------------------------------------------------------------------*/
1148 /*!
1149 * \brief pixConvertGrayToColormap()
1150 *
1151 * \param[in] pixs 2, 4 or 8 bpp grayscale
1152 * \return pixd 2, 4 or 8 bpp with colormap, or NULL on error
1153 *
1154 * <pre>
1155 * Notes:
1156 * (1) This is a simple interface for adding a colormap to a
1157 * 2, 4 or 8 bpp grayscale image without causing any
1158 * quantization. There is some similarity to operations
1159 * in grayquant.c, such as pixThresholdOn8bpp(), where
1160 * the emphasis is on quantization with an arbitrary number
1161 * of levels, and a colormap is an option.
1162 * (2) Returns a copy if pixs already has a colormap.
1163 * (3) For 8 bpp src, this is a lossless transformation.
1164 * (4) For 2 and 4 bpp src, this generates a colormap that
1165 * assumes full coverage of the gray space, with equally spaced
1166 * levels: 4 levels for d = 2 and 16 levels for d = 4.
1167 * (5) In all cases, the depth of the dest is the same as the src.
1168 * </pre>
1169 */
1170 PIX *
pixConvertGrayToColormap(PIX * pixs)1171 pixConvertGrayToColormap(PIX *pixs)
1172 {
1173 l_int32 d;
1174 PIX *pixd;
1175 PIXCMAP *cmap;
1176
1177 PROCNAME("pixConvertGrayToColormap");
1178
1179 if (!pixs)
1180 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1181 d = pixGetDepth(pixs);
1182 if (d != 2 && d != 4 && d != 8)
1183 return (PIX *)ERROR_PTR("pixs not 2, 4 or 8 bpp", procName, NULL);
1184
1185 if (pixGetColormap(pixs)) {
1186 L_INFO("pixs already has a colormap\n", procName);
1187 return pixCopy(NULL, pixs);
1188 }
1189
1190 if (d == 8) /* lossless conversion */
1191 return pixConvertGrayToColormap8(pixs, 2);
1192
1193 /* Build a cmap with equally spaced target values over the
1194 * full 8 bpp range. */
1195 pixd = pixCopy(NULL, pixs);
1196 cmap = pixcmapCreateLinear(d, 1 << d);
1197 pixSetColormap(pixd, cmap);
1198 pixCopyInputFormat(pixd, pixs);
1199 return pixd;
1200 }
1201
1202
1203 /*!
1204 * \brief pixConvertGrayToColormap8()
1205 *
1206 * \param[in] pixs 8 bpp grayscale
1207 * \param[in] mindepth of pixd; valid values are 2, 4 and 8
1208 * \return pixd 2, 4 or 8 bpp with colormap, or NULL on error
1209 *
1210 * <pre>
1211 * Notes:
1212 * (1) Returns a copy if pixs already has a colormap.
1213 * (2) This is a lossless transformation; there is no quantization.
1214 * We compute the number of different gray values in pixs,
1215 * and construct a colormap that has exactly these values.
1216 * (3) 'mindepth' is the minimum depth of pixd. If mindepth == 8,
1217 * pixd will always be 8 bpp. Let the number of different
1218 * gray values in pixs be ngray. If mindepth == 4, we attempt
1219 * to save pixd as a 4 bpp image, but if ngray > 16,
1220 * pixd must be 8 bpp. Likewise, if mindepth == 2,
1221 * the depth of pixd will be 2 if ngray <= 4 and 4 if ngray > 4
1222 * but <= 16.
1223 * </pre>
1224 */
1225 PIX *
pixConvertGrayToColormap8(PIX * pixs,l_int32 mindepth)1226 pixConvertGrayToColormap8(PIX *pixs,
1227 l_int32 mindepth)
1228 {
1229 l_int32 ncolors, w, h, depth, i, j, wpls, wpld;
1230 l_int32 index, num, val, newval;
1231 l_int32 array[256];
1232 l_uint32 *lines, *lined, *datas, *datad;
1233 NUMA *na;
1234 PIX *pixd;
1235 PIXCMAP *cmap;
1236
1237 PROCNAME("pixConvertGrayToColormap8");
1238
1239 if (!pixs)
1240 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1241 if (pixGetDepth(pixs) != 8)
1242 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
1243 if (mindepth != 2 && mindepth != 4 && mindepth != 8) {
1244 L_WARNING("invalid value of mindepth; setting to 8\n", procName);
1245 mindepth = 8;
1246 }
1247
1248 if (pixGetColormap(pixs)) {
1249 L_INFO("pixs already has a colormap\n", procName);
1250 return pixCopy(NULL, pixs);
1251 }
1252
1253 na = pixGetGrayHistogram(pixs, 1);
1254 numaGetCountRelativeToZero(na, L_GREATER_THAN_ZERO, &ncolors);
1255 if (mindepth == 8 || ncolors > 16)
1256 depth = 8;
1257 else if (mindepth == 4 || ncolors > 4)
1258 depth = 4;
1259 else
1260 depth = 2;
1261
1262 pixGetDimensions(pixs, &w, &h, NULL);
1263 pixd = pixCreate(w, h, depth);
1264 cmap = pixcmapCreate(depth);
1265 pixSetColormap(pixd, cmap);
1266 pixCopyInputFormat(pixd, pixs);
1267 pixCopyResolution(pixd, pixs);
1268
1269 index = 0;
1270 for (i = 0; i < 256; i++) {
1271 array[i] = 0; /* only to quiet the static checker */
1272 numaGetIValue(na, i, &num);
1273 if (num > 0) {
1274 pixcmapAddColor(cmap, i, i, i);
1275 array[i] = index;
1276 index++;
1277 }
1278 }
1279
1280 datas = pixGetData(pixs);
1281 wpls = pixGetWpl(pixs);
1282 datad = pixGetData(pixd);
1283 wpld = pixGetWpl(pixd);
1284 for (i = 0; i < h; i++) {
1285 lines = datas + i * wpls;
1286 lined = datad + i * wpld;
1287 for (j = 0; j < w; j++) {
1288 val = GET_DATA_BYTE(lines, j);
1289 newval = array[val];
1290 if (depth == 2)
1291 SET_DATA_DIBIT(lined, j, newval);
1292 else if (depth == 4)
1293 SET_DATA_QBIT(lined, j, newval);
1294 else /* depth == 8 */
1295 SET_DATA_BYTE(lined, j, newval);
1296 }
1297 }
1298
1299 numaDestroy(&na);
1300 return pixd;
1301 }
1302
1303
1304 /*---------------------------------------------------------------------------*
1305 * Colorizing conversion from grayscale to color *
1306 *---------------------------------------------------------------------------*/
1307 /*!
1308 * \brief pixColorizeGray()
1309 *
1310 * \param[in] pixs 8 bpp gray; 2, 4 or 8 bpp colormapped
1311 * \param[in] color 32 bit rgba pixel
1312 * \param[in] cmapflag 1 for result to have colormap; 0 for RGB
1313 * \return pixd 8 bpp colormapped or 32 bpp rgb, or NULL on error
1314 *
1315 * <pre>
1316 * Notes:
1317 * (1) This applies the specific color to the grayscale image.
1318 * (2) If pixs already has a colormap, it is removed to gray
1319 * before colorizing.
1320 * </pre>
1321 */
1322 PIX *
pixColorizeGray(PIX * pixs,l_uint32 color,l_int32 cmapflag)1323 pixColorizeGray(PIX *pixs,
1324 l_uint32 color,
1325 l_int32 cmapflag)
1326 {
1327 l_int32 i, j, w, h, wplt, wpld, val8;
1328 l_uint32 *datad, *datat, *lined, *linet, *tab;
1329 PIX *pixt, *pixd;
1330 PIXCMAP *cmap;
1331
1332 PROCNAME("pixColorizeGray");
1333
1334 if (!pixs)
1335 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1336 if (pixGetDepth(pixs) != 8 && !pixGetColormap(pixs))
1337 return (PIX *)ERROR_PTR("pixs not 8 bpp or cmapped", procName, NULL);
1338
1339 if (pixGetColormap(pixs))
1340 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1341 else
1342 pixt = pixClone(pixs);
1343
1344 cmap = pixcmapGrayToColor(color);
1345 if (cmapflag) {
1346 pixd = pixCopy(NULL, pixt);
1347 pixSetColormap(pixd, cmap);
1348 pixDestroy(&pixt);
1349 return pixd;
1350 }
1351
1352 /* Make an RGB pix */
1353 pixcmapToRGBTable(cmap, &tab, NULL);
1354 pixGetDimensions(pixt, &w, &h, NULL);
1355 pixd = pixCreate(w, h, 32);
1356 pixCopyResolution(pixd, pixs);
1357 pixCopyInputFormat(pixd, pixs);
1358 datad = pixGetData(pixd);
1359 wpld = pixGetWpl(pixd);
1360 datat = pixGetData(pixt);
1361 wplt = pixGetWpl(pixt);
1362 for (i = 0; i < h; i++) {
1363 lined = datad + i * wpld;
1364 linet = datat + i * wplt;
1365 for (j = 0; j < w; j++) {
1366 val8 = GET_DATA_BYTE(linet, j);
1367 lined[j] = tab[val8];
1368 }
1369 }
1370
1371 pixDestroy(&pixt);
1372 pixcmapDestroy(&cmap);
1373 LEPT_FREE(tab);
1374 return pixd;
1375 }
1376
1377
1378 /*---------------------------------------------------------------------------*
1379 * Conversion from RGB color to colormap *
1380 *---------------------------------------------------------------------------*/
1381 /*!
1382 * \brief pixConvertRGBToColormap()
1383 *
1384 * \param[in] pixs 32 bpp rgb
1385 * \param[in] ditherflag 1 to dither, 0 otherwise
1386 * \return pixd 2, 4 or 8 bpp with colormap, or NULL on error
1387 *
1388 * <pre>
1389 * Notes:
1390 * (1) This function has two relatively simple modes of color
1391 * quantization:
1392 * (a) If the image is made orthographically and has not more
1393 * than 256 'colors' at the level 4 octcube leaves,
1394 * it is quantized nearly exactly. The ditherflag
1395 * is ignored.
1396 * (b) Most natural images have more than 256 different colors;
1397 * in that case we use adaptive octree quantization,
1398 * with dithering if requested.
1399 * (2) If there are not more than 256 occupied level 4 octcubes,
1400 * the color in the colormap that represents all pixels in
1401 * one of those octcubes is given by the first pixel that
1402 * falls into that octcube.
1403 * (3) If there are more than 256 colors, we use adaptive octree
1404 * color quantization.
1405 * (4) Dithering gives better visual results on images where
1406 * there is a color wash (a slow variation of color), but it
1407 * is about twice as slow and results in significantly larger
1408 * files when losslessly compressed (e.g., into png).
1409 * </pre>
1410 */
1411 PIX *
pixConvertRGBToColormap(PIX * pixs,l_int32 ditherflag)1412 pixConvertRGBToColormap(PIX *pixs,
1413 l_int32 ditherflag)
1414 {
1415 l_int32 ncolors;
1416 NUMA *na;
1417 PIX *pixd;
1418
1419 PROCNAME("pixConvertRGBToColormap");
1420
1421 if (!pixs)
1422 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1423 if (pixGetDepth(pixs) != 32)
1424 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
1425 if (pixGetSpp(pixs) == 4)
1426 L_WARNING("pixs has alpha; removing\n", procName);
1427
1428 /* Get the histogram and count the number of occupied level 4
1429 * leaf octcubes. We don't yet know if this is the number of
1430 * actual colors, but if it's not, all pixels falling into
1431 * the same leaf octcube will be assigned to the color of the
1432 * first pixel that lands there. */
1433 na = pixOctcubeHistogram(pixs, 4, &ncolors);
1434
1435 /* If there are too many occupied leaf octcubes to be
1436 * represented directly in a colormap, fall back to octree
1437 * quantization, optionally with dithering. */
1438 if (ncolors > 256) {
1439 numaDestroy(&na);
1440 if (ditherflag)
1441 L_INFO("More than 256 colors; using octree quant with dithering\n",
1442 procName);
1443 else
1444 L_INFO("More than 256 colors; using octree quant; no dithering\n",
1445 procName);
1446 return pixOctreeColorQuant(pixs, 240, ditherflag);
1447 }
1448
1449 /* There are not more than 256 occupied leaf octcubes.
1450 * Quantize to those octcubes. */
1451 pixd = pixFewColorsOctcubeQuant2(pixs, 4, na, ncolors, NULL);
1452 pixCopyInputFormat(pixd, pixs);
1453 numaDestroy(&na);
1454 return pixd;
1455 }
1456
1457
1458 /*---------------------------------------------------------------------------*
1459 * Conversion from colormap to 1 bpp *
1460 *---------------------------------------------------------------------------*/
1461 /*!
1462 * \brief pixConvertCmapTo1()
1463 *
1464 * \param[in] pixs cmapped
1465 * \return pixd 1 bpp, or NULL on error
1466 *
1467 * <pre>
1468 * Notes:
1469 * (1) This is an extreme color quantizer. It decides which
1470 * colors map to FG (black) and which to BG (white).
1471 * (2) This uses two heuristics to make the decision:
1472 * (a) colors similar to each other are likely to be in the same class
1473 * (b) there is usually much less FG than BG.
1474 * </pre>
1475 */
1476 PIX *
pixConvertCmapTo1(PIX * pixs)1477 pixConvertCmapTo1(PIX *pixs)
1478 {
1479 l_int32 i, j, nc, w, h, imin, imax, factor, wpl1, wpld;
1480 l_int32 index, rmin, gmin, bmin, rmax, gmax, bmax, dmin, dmax;
1481 l_float32 minfract, ifract;
1482 l_int32 *lut;
1483 l_uint32 *line1, *lined, *data1, *datad;
1484 NUMA *na1, *na2; /* histograms */
1485 PIX *pix1, *pixd;
1486 PIXCMAP *cmap;
1487
1488 PROCNAME("pixConvertCmapTo1");
1489
1490 if (!pixs)
1491 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1492 if ((cmap = pixGetColormap(pixs)) == NULL)
1493 return (PIX *)ERROR_PTR("no colormap", procName, NULL);
1494
1495 /* Select target colors for the two classes. Find the
1496 * colors with smallest and largest average component values.
1497 * The smallest is class 0 and the largest is class 1. */
1498 pixcmapGetRangeValues(cmap, L_SELECT_AVERAGE, NULL, NULL, &imin, &imax);
1499 pixcmapGetColor(cmap, imin, &rmin, &gmin, &bmin);
1500 pixcmapGetColor(cmap, imax, &rmax, &gmax, &bmax);
1501 nc = pixcmapGetCount(cmap);
1502
1503 /* Assign colors to the two classes. The histogram is
1504 * initialized to 0, so any colors not found when computing
1505 * the sampled histogram will get zero weight in minfract. */
1506 if ((lut = (l_int32 *)LEPT_CALLOC(nc, sizeof(l_int32))) == NULL)
1507 return (PIX *)ERROR_PTR("calloc fail for lut", procName, NULL);
1508 pixGetDimensions(pixs, &w, &h, NULL);
1509 factor = L_MAX(1, (l_int32)sqrt((l_float64)(w * h) / 50000. + 0.5));
1510 na1 = pixGetCmapHistogram(pixs, factor);
1511 na2 = numaNormalizeHistogram(na1, 1.0);
1512 minfract = 0.0;
1513 for (i = 0; i < nc; i++) {
1514 numaGetFValue(na2, i, &ifract);
1515 pixcmapGetDistanceToColor(cmap, i, rmin, gmin, bmin, &dmin);
1516 pixcmapGetDistanceToColor(cmap, i, rmax, gmax, bmax, &dmax);
1517 if (dmin < dmax) { /* closer to dark extreme value */
1518 lut[i] = 1; /* black pixel in 1 bpp image */
1519 minfract += ifract;
1520 }
1521 }
1522 numaDestroy(&na1);
1523 numaDestroy(&na2);
1524
1525 /* Generate the output binarized image */
1526 pix1 = pixConvertTo8(pixs, 1);
1527 pixd = pixCreate(w, h, 1);
1528 data1 = pixGetData(pix1);
1529 datad = pixGetData(pixd);
1530 wpl1 = pixGetWpl(pix1);
1531 wpld = pixGetWpl(pixd);
1532 for (i = 0; i < h; i++) {
1533 line1 = data1 + i * wpl1;
1534 lined = datad + i * wpld;
1535 for (j = 0; j < w; j++) {
1536 index = GET_DATA_BYTE(line1, j);
1537 if (lut[index] == 1) SET_DATA_BIT(lined, j);
1538 }
1539 }
1540 pixDestroy(&pix1);
1541 LEPT_FREE(lut);
1542
1543 /* We expect minfract (the dark colors) to be less than 0.5.
1544 * If that is not the case, invert pixd. */
1545 if (minfract > 0.5) {
1546 L_INFO("minfract = %5.3f; inverting\n", procName, minfract);
1547 pixInvert(pixd, pixd);
1548 }
1549
1550 return pixd;
1551 }
1552
1553
1554 /*---------------------------------------------------------------------------*
1555 * Quantization for relatively small number of colors in source *
1556 *---------------------------------------------------------------------------*/
1557 /*!
1558 * \brief pixQuantizeIfFewColors()
1559 *
1560 * \param[in] pixs 8 bpp gray or 32 bpp rgb
1561 * \param[in] maxcolors max number of colors allowed to be returned
1562 * from pixColorsForQuantization();
1563 * use 0 for default
1564 * \param[in] mingraycolors min number of gray levels that a grayscale
1565 * image is quantized to; use 0 for default
1566 * \param[in] octlevel for octcube quantization: 3 or 4
1567 * \param[out] ppixd 2,4 or 8 bpp quantized; null if too many colors
1568 * \return 0 if OK, 1 on error or if pixs can't be quantized into
1569 * a small number of colors.
1570 *
1571 * <pre>
1572 * Notes:
1573 * (1) This is a wrapper that tests if the pix can be quantized
1574 * with good quality using a small number of colors. If so,
1575 * it does the quantization, defining a colormap and using
1576 * pixels whose value is an index into the colormap.
1577 * (2) If the image has color, it is quantized with 8 bpp pixels.
1578 * If the image is essentially grayscale, the pixels are
1579 * either 4 or 8 bpp, depending on the size of the required
1580 * colormap.
1581 * (3) %octlevel = 4 generates a larger colormap and larger
1582 * compressed image than %octlevel = 3. If image quality is
1583 * important, you should use %octlevel = 4.
1584 * (4) If the image already has a colormap, it returns a clone.
1585 * </pre>
1586 */
1587 l_int32
pixQuantizeIfFewColors(PIX * pixs,l_int32 maxcolors,l_int32 mingraycolors,l_int32 octlevel,PIX ** ppixd)1588 pixQuantizeIfFewColors(PIX *pixs,
1589 l_int32 maxcolors,
1590 l_int32 mingraycolors,
1591 l_int32 octlevel,
1592 PIX **ppixd)
1593 {
1594 l_int32 d, ncolors, iscolor, graycolors;
1595 PIX *pixg, *pixd;
1596
1597 PROCNAME("pixQuantizeIfFewColors");
1598
1599 if (!ppixd)
1600 return ERROR_INT("&pixd not defined", procName, 1);
1601 *ppixd = NULL;
1602 if (!pixs)
1603 return ERROR_INT("pixs not defined", procName, 1);
1604 d = pixGetDepth(pixs);
1605 if (d != 8 && d != 32)
1606 return ERROR_INT("pixs not defined", procName, 1);
1607 if (pixGetColormap(pixs) != NULL) {
1608 *ppixd = pixClone(pixs);
1609 return 0;
1610 }
1611 if (maxcolors <= 0)
1612 maxcolors = 15; /* default */
1613 if (maxcolors > 50)
1614 L_WARNING("maxcolors > 50; very large!\n", procName);
1615 if (mingraycolors <= 0)
1616 mingraycolors = 10; /* default */
1617 if (mingraycolors > 30)
1618 L_WARNING("mingraycolors > 30; very large!\n", procName);
1619 if (octlevel != 3 && octlevel != 4) {
1620 L_WARNING("invalid octlevel; setting to 3\n", procName);
1621 octlevel = 3;
1622 }
1623
1624 /* Test the number of colors. For color, the octcube leaves
1625 * are at level 4. */
1626 pixColorsForQuantization(pixs, 0, &ncolors, &iscolor, 0);
1627 if (ncolors > maxcolors)
1628 return ERROR_INT("too many colors", procName, 1);
1629
1630 /* Quantize!
1631 * (1) For color:
1632 * If octlevel == 4, try to quantize to an octree where
1633 * the octcube leaves are at level 4. If that fails,
1634 * back off to level 3.
1635 * If octlevel == 3, quantize to level 3 directly.
1636 * For level 3, the quality is usually good enough and there
1637 * is negligible chance of getting more than 256 colors.
1638 * (2) For grayscale, multiply ncolors by 1.5 for extra quality,
1639 * but use at least mingraycolors and not more than 256. */
1640 if (iscolor) {
1641 pixd = pixFewColorsOctcubeQuant1(pixs, octlevel);
1642 if (!pixd) { /* backoff */
1643 pixd = pixFewColorsOctcubeQuant1(pixs, octlevel - 1);
1644 if (octlevel == 3) /* shouldn't happen */
1645 L_WARNING("quantized at level 2; low quality\n", procName);
1646 }
1647 } else { /* image is really grayscale */
1648 if (d == 32)
1649 pixg = pixConvertRGBToLuminance(pixs);
1650 else
1651 pixg = pixClone(pixs);
1652 graycolors = L_MAX(mingraycolors, (l_int32)(1.5 * ncolors));
1653 graycolors = L_MIN(graycolors, 256);
1654 if (graycolors < 16)
1655 pixd = pixThresholdTo4bpp(pixg, graycolors, 1);
1656 else
1657 pixd = pixThresholdOn8bpp(pixg, graycolors, 1);
1658 pixDestroy(&pixg);
1659 }
1660 *ppixd = pixd;
1661
1662 if (!pixd)
1663 return ERROR_INT("pixd not made", procName, 1);
1664 pixCopyInputFormat(pixd, pixs);
1665 return 0;
1666 }
1667
1668
1669
1670 /*---------------------------------------------------------------------------*
1671 * Conversion from 16 bpp to 8 bpp *
1672 *---------------------------------------------------------------------------*/
1673 /*!
1674 * \brief pixConvert16To8()
1675 *
1676 * \param[in] pixs 16 bpp
1677 * \param[in] type L_LS_BYTE, L_MS_BYTE, L_AUTO_BYTE, L_CLIP_TO_FF
1678 * \return pixd 8 bpp, or NULL on error
1679 *
1680 * <pre>
1681 * Notes:
1682 * (1) With L_AUTO_BYTE, if the max pixel value is greater than 255,
1683 * use the MSB; otherwise, use the LSB.
1684 * (2) With L_CLIP_TO_FF, use min(pixel-value, 0xff) for each
1685 * 16-bit src pixel.
1686 * </pre>
1687 */
1688 PIX *
pixConvert16To8(PIX * pixs,l_int32 type)1689 pixConvert16To8(PIX *pixs,
1690 l_int32 type)
1691 {
1692 l_uint16 dword;
1693 l_int32 w, h, wpls, wpld, i, j, val, use_lsb;
1694 l_uint32 sword, first, second;
1695 l_uint32 *datas, *datad, *lines, *lined;
1696 PIX *pixd;
1697
1698 PROCNAME("pixConvert16To8");
1699
1700 if (!pixs)
1701 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1702 if (pixGetDepth(pixs) != 16)
1703 return (PIX *)ERROR_PTR("pixs not 16 bpp", procName, NULL);
1704 if (type != L_LS_BYTE && type != L_MS_BYTE &&
1705 type != L_AUTO_BYTE && type != L_CLIP_TO_FF)
1706 return (PIX *)ERROR_PTR("invalid type", procName, NULL);
1707
1708 pixGetDimensions(pixs, &w, &h, NULL);
1709 if ((pixd = pixCreate(w, h, 8)) == NULL)
1710 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1711 pixCopyInputFormat(pixd, pixs);
1712 pixCopyResolution(pixd, pixs);
1713 wpls = pixGetWpl(pixs);
1714 datas = pixGetData(pixs);
1715 wpld = pixGetWpl(pixd);
1716 datad = pixGetData(pixd);
1717
1718 if (type == L_AUTO_BYTE) {
1719 use_lsb = TRUE;
1720 for (i = 0; i < h; i++) {
1721 lines = datas + i * wpls;
1722 for (j = 0; j < wpls; j++) {
1723 val = GET_DATA_TWO_BYTES(lines, j);
1724 if (val > 255) {
1725 use_lsb = FALSE;
1726 break;
1727 }
1728 }
1729 if (!use_lsb) break;
1730 }
1731 type = (use_lsb) ? L_LS_BYTE : L_MS_BYTE;
1732 }
1733
1734 /* Convert 2 pixels at a time */
1735 for (i = 0; i < h; i++) {
1736 lines = datas + i * wpls;
1737 lined = datad + i * wpld;
1738 if (type == L_LS_BYTE) {
1739 for (j = 0; j < wpls; j++) {
1740 sword = *(lines + j);
1741 dword = ((sword >> 8) & 0xff00) | (sword & 0xff);
1742 SET_DATA_TWO_BYTES(lined, j, dword);
1743 }
1744 } else if (type == L_MS_BYTE) {
1745 for (j = 0; j < wpls; j++) {
1746 sword = *(lines + j);
1747 dword = ((sword >> 16) & 0xff00) | ((sword >> 8) & 0xff);
1748 SET_DATA_TWO_BYTES(lined, j, dword);
1749 }
1750 } else { /* type == L_CLIP_TO_FF */
1751 for (j = 0; j < wpls; j++) {
1752 sword = *(lines + j);
1753 first = (sword >> 24) ? 255 : ((sword >> 16) & 0xff);
1754 second = ((sword >> 8) & 0xff) ? 255 : (sword & 0xff);
1755 dword = (first << 8) | second;
1756 SET_DATA_TWO_BYTES(lined, j, dword);
1757 }
1758 }
1759 }
1760
1761 return pixd;
1762 }
1763
1764
1765
1766 /*---------------------------------------------------------------------------*
1767 * Conversion from grayscale to false color
1768 *---------------------------------------------------------------------------*/
1769 /*!
1770 * \brief pixConvertGrayToFalseColor()
1771 *
1772 * \param[in] pixs 8 or 16 bpp grayscale
1773 * \param[in] gamma (factor) 0.0 or 1.0 for default; > 1.0 for brighter;
1774 * 2.0 is quite nice
1775 * \return pixd 8 bpp with colormap, or NULL on error
1776 *
1777 * <pre>
1778 * Notes:
1779 * (1) For 8 bpp input, this simply adds a colormap to the input image.
1780 * (2) For 16 bpp input, it first converts to 8 bpp, using the MSB,
1781 * and then adds the colormap.
1782 * (3) The colormap is modeled after the Matlab "jet" configuration.
1783 * </pre>
1784 */
1785 PIX *
pixConvertGrayToFalseColor(PIX * pixs,l_float32 gamma)1786 pixConvertGrayToFalseColor(PIX *pixs,
1787 l_float32 gamma)
1788 {
1789 l_int32 d, i, rval, bval, gval;
1790 l_int32 *curve;
1791 l_float32 invgamma, x;
1792 PIX *pixd;
1793 PIXCMAP *cmap;
1794
1795 PROCNAME("pixConvertGrayToFalseColor");
1796
1797 if (!pixs)
1798 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1799 d = pixGetDepth(pixs);
1800 if (d != 8 && d != 16)
1801 return (PIX *)ERROR_PTR("pixs not 8 or 16 bpp", procName, NULL);
1802
1803 if (d == 16) {
1804 pixd = pixConvert16To8(pixs, L_MS_BYTE);
1805 } else { /* d == 8 */
1806 if (pixGetColormap(pixs))
1807 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1808 else
1809 pixd = pixCopy(NULL, pixs);
1810 }
1811 if (!pixd)
1812 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1813 cmap = pixcmapCreate(8);
1814 pixSetColormap(pixd, cmap);
1815 pixCopyResolution(pixd, pixs);
1816 pixCopyInputFormat(pixd, pixs);
1817
1818 /* Generate curve for transition part of color map */
1819 curve = (l_int32 *)LEPT_CALLOC(64, sizeof(l_int32));
1820 if (gamma == 0.0) gamma = 1.0;
1821 invgamma = 1. / gamma;
1822 for (i = 0; i < 64; i++) {
1823 x = (l_float32)i / 64.;
1824 curve[i] = (l_int32)(255. * powf(x, invgamma) + 0.5);
1825 }
1826
1827 for (i = 0; i < 256; i++) {
1828 if (i < 32) {
1829 rval = 0;
1830 gval = 0;
1831 bval = curve[i + 32];
1832 } else if (i < 96) { /* 32 - 95 */
1833 rval = 0;
1834 gval = curve[i - 32];
1835 bval = 255;
1836 } else if (i < 160) { /* 96 - 159 */
1837 rval = curve[i - 96];
1838 gval = 255;
1839 bval = curve[159 - i];
1840 } else if (i < 224) { /* 160 - 223 */
1841 rval = 255;
1842 gval = curve[223 - i];
1843 bval = 0;
1844 } else { /* 224 - 255 */
1845 rval = curve[287 - i];
1846 gval = 0;
1847 bval = 0;
1848 }
1849 pixcmapAddColor(cmap, rval, gval, bval);
1850 }
1851
1852 LEPT_FREE(curve);
1853 return pixd;
1854 }
1855
1856
1857 /*---------------------------------------------------------------------------*
1858 * Unpacking conversion from 1 bpp to 2, 4, 8, 16 and 32 bpp *
1859 *---------------------------------------------------------------------------*/
1860 /*!
1861 * \brief pixUnpackBinary()
1862 *
1863 * \param[in] pixs 1 bpp
1864 * \param[in] depth of destination: 2, 4, 8, 16 or 32 bpp
1865 * \param[in] invert 0: binary 0 --> grayscale 0
1866 * binary 1 --> grayscale 0xff...
1867 * 1: binary 0 --> grayscale 0xff...
1868 * binary 1 --> grayscale 0
1869 * \return pixd 2, 4, 8, 16 or 32 bpp, or NULL on error
1870 *
1871 * <pre>
1872 * Notes:
1873 * (1) This function calls special cases of pixConvert1To*(),
1874 * for 2, 4, 8, 16 and 32 bpp destinations.
1875 * </pre>
1876 */
1877 PIX *
pixUnpackBinary(PIX * pixs,l_int32 depth,l_int32 invert)1878 pixUnpackBinary(PIX *pixs,
1879 l_int32 depth,
1880 l_int32 invert)
1881 {
1882 PIX *pixd;
1883
1884 PROCNAME("pixUnpackBinary");
1885
1886 if (!pixs)
1887 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1888 if (pixGetDepth(pixs) != 1)
1889 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1890 if (depth != 2 && depth != 4 && depth != 8 && depth != 16 && depth != 32)
1891 return (PIX *)ERROR_PTR("depth not 2, 4, 8, 16 or 32 bpp",
1892 procName, NULL);
1893
1894 if (depth == 2) {
1895 if (invert == 0)
1896 pixd = pixConvert1To2(NULL, pixs, 0, 3);
1897 else /* invert bits */
1898 pixd = pixConvert1To2(NULL, pixs, 3, 0);
1899 } else if (depth == 4) {
1900 if (invert == 0)
1901 pixd = pixConvert1To4(NULL, pixs, 0, 15);
1902 else /* invert bits */
1903 pixd = pixConvert1To4(NULL, pixs, 15, 0);
1904 } else if (depth == 8) {
1905 if (invert == 0)
1906 pixd = pixConvert1To8(NULL, pixs, 0, 255);
1907 else /* invert bits */
1908 pixd = pixConvert1To8(NULL, pixs, 255, 0);
1909 } else if (depth == 16) {
1910 if (invert == 0)
1911 pixd = pixConvert1To16(NULL, pixs, 0, 0xffff);
1912 else /* invert bits */
1913 pixd = pixConvert1To16(NULL, pixs, 0xffff, 0);
1914 } else {
1915 if (invert == 0)
1916 pixd = pixConvert1To32(NULL, pixs, 0, 0xffffffff);
1917 else /* invert bits */
1918 pixd = pixConvert1To32(NULL, pixs, 0xffffffff, 0);
1919 }
1920
1921 pixCopyInputFormat(pixd, pixs);
1922 return pixd;
1923 }
1924
1925
1926 /*!
1927 * \brief pixConvert1To16()
1928 *
1929 * \param[in] pixd [optional] 16 bpp, can be null
1930 * \param[in] pixs 1 bpp
1931 * \param[in] val0 16 bit value to be used for 0s in pixs
1932 * \param[in] val1 16 bit value to be used for 1s in pixs
1933 * \return pixd 16 bpp
1934 *
1935 * <pre>
1936 * Notes:
1937 * (1) If pixd is null, a new pix is made.
1938 * (2) If pixd is not null, it must be of equal width and height
1939 * as pixs. It is always returned.
1940 * </pre>
1941 */
1942 PIX *
pixConvert1To16(PIX * pixd,PIX * pixs,l_uint16 val0,l_uint16 val1)1943 pixConvert1To16(PIX *pixd,
1944 PIX *pixs,
1945 l_uint16 val0,
1946 l_uint16 val1)
1947 {
1948 l_int32 w, h, i, j, dibit, ndibits, wpls, wpld;
1949 l_uint16 val[2];
1950 l_uint32 index;
1951 l_uint32 *tab, *datas, *datad, *lines, *lined;
1952
1953 PROCNAME("pixConvert1To16");
1954
1955 if (!pixs)
1956 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1957 if (pixGetDepth(pixs) != 1)
1958 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1959
1960 pixGetDimensions(pixs, &w, &h, NULL);
1961 if (pixd) {
1962 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
1963 return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
1964 if (pixGetDepth(pixd) != 16)
1965 return (PIX *)ERROR_PTR("pixd not 16 bpp", procName, pixd);
1966 } else {
1967 if ((pixd = pixCreate(w, h, 16)) == NULL)
1968 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1969 }
1970 pixCopyResolution(pixd, pixs);
1971 pixCopyInputFormat(pixd, pixs);
1972
1973 /* Use a table to convert 2 src bits at a time */
1974 tab = (l_uint32 *)LEPT_CALLOC(4, sizeof(l_uint32));
1975 val[0] = val0;
1976 val[1] = val1;
1977 for (index = 0; index < 4; index++) {
1978 tab[index] = (val[(index >> 1) & 1] << 16) | val[index & 1];
1979 }
1980
1981 datas = pixGetData(pixs);
1982 wpls = pixGetWpl(pixs);
1983 datad = pixGetData(pixd);
1984 wpld = pixGetWpl(pixd);
1985 ndibits = (w + 1) / 2;
1986 for (i = 0; i < h; i++) {
1987 lines = datas + i * wpls;
1988 lined = datad + i * wpld;
1989 for (j = 0; j < ndibits; j++) {
1990 dibit = GET_DATA_DIBIT(lines, j);
1991 lined[j] = tab[dibit];
1992 }
1993 }
1994
1995 LEPT_FREE(tab);
1996 return pixd;
1997 }
1998
1999
2000 /*!
2001 * \brief pixConvert1To32()
2002 *
2003 * \param[in] pixd [optional] 32 bpp, can be null
2004 * \param[in] pixs 1 bpp
2005 * \param[in] val0 32 bit value to be used for 0s in pixs
2006 * \param[in] val1 32 bit value to be used for 1s in pixs
2007 * \return pixd 32 bpp
2008 *
2009 * <pre>
2010 * Notes:
2011 * (1) If pixd is null, a new pix is made.
2012 * (2) If pixd is not null, it must be of equal width and height
2013 * as pixs. It is always returned.
2014 * </pre>
2015 */
2016 PIX *
pixConvert1To32(PIX * pixd,PIX * pixs,l_uint32 val0,l_uint32 val1)2017 pixConvert1To32(PIX *pixd,
2018 PIX *pixs,
2019 l_uint32 val0,
2020 l_uint32 val1)
2021 {
2022 l_int32 w, h, i, j, wpls, wpld, bit;
2023 l_uint32 val[2];
2024 l_uint32 *datas, *datad, *lines, *lined;
2025
2026 PROCNAME("pixConvert1To32");
2027
2028 if (!pixs)
2029 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2030 if (pixGetDepth(pixs) != 1)
2031 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
2032
2033 pixGetDimensions(pixs, &w, &h, NULL);
2034 if (pixd) {
2035 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
2036 return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
2037 if (pixGetDepth(pixd) != 32)
2038 return (PIX *)ERROR_PTR("pixd not 32 bpp", procName, pixd);
2039 } else {
2040 if ((pixd = pixCreate(w, h, 32)) == NULL)
2041 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2042 }
2043 pixCopyResolution(pixd, pixs);
2044 pixCopyInputFormat(pixd, pixs);
2045
2046 val[0] = val0;
2047 val[1] = val1;
2048 datas = pixGetData(pixs);
2049 wpls = pixGetWpl(pixs);
2050 datad = pixGetData(pixd);
2051 wpld = pixGetWpl(pixd);
2052 for (i = 0; i < h; i++) {
2053 lines = datas + i * wpls;
2054 lined = datad + i * wpld;
2055 for (j = 0; j <w; j++) {
2056 bit = GET_DATA_BIT(lines, j);
2057 lined[j] = val[bit];
2058 }
2059 }
2060
2061 return pixd;
2062 }
2063
2064
2065 /*---------------------------------------------------------------------------*
2066 * Conversion from 1 bpp to 2 bpp *
2067 *---------------------------------------------------------------------------*/
2068 /*!
2069 * \brief pixConvert1To2Cmap()
2070 *
2071 * \param[in] pixs 1 bpp
2072 * \return pixd 2 bpp, cmapped
2073 *
2074 * <pre>
2075 * Notes:
2076 * (1) Input 0 is mapped to (255, 255, 255); 1 is mapped to (0, 0, 0)
2077 * </pre>
2078 */
2079 PIX *
pixConvert1To2Cmap(PIX * pixs)2080 pixConvert1To2Cmap(PIX *pixs)
2081 {
2082 PIX *pixd;
2083 PIXCMAP *cmap;
2084
2085 PROCNAME("pixConvert1To2Cmap");
2086
2087 if (!pixs)
2088 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2089 if (pixGetDepth(pixs) != 1)
2090 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
2091
2092 if ((pixd = pixConvert1To2(NULL, pixs, 0, 1)) == NULL)
2093 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2094 cmap = pixcmapCreate(2);
2095 pixcmapAddColor(cmap, 255, 255, 255);
2096 pixcmapAddColor(cmap, 0, 0, 0);
2097 pixSetColormap(pixd, cmap);
2098 pixCopyInputFormat(pixd, pixs);
2099
2100 return pixd;
2101 }
2102
2103
2104 /*!
2105 * \brief pixConvert1To2()
2106 *
2107 * \param[in] pixd [optional] 2 bpp, can be null
2108 * \param[in] pixs 1 bpp
2109 * \param[in] val0 2 bit value to be used for 0s in pixs
2110 * \param[in] val1 2 bit value to be used for 1s in pixs
2111 * \return pixd 2 bpp
2112 *
2113 * <pre>
2114 * Notes:
2115 * (1) If pixd is null, a new pix is made.
2116 * (2) If pixd is not null, it must be of equal width and height
2117 * as pixs. It is always returned.
2118 * (3) A simple unpacking might use val0 = 0 and val1 = 3.
2119 * (4) If you want a colormapped pixd, use pixConvert1To2Cmap().
2120 * </pre>
2121 */
2122 PIX *
pixConvert1To2(PIX * pixd,PIX * pixs,l_int32 val0,l_int32 val1)2123 pixConvert1To2(PIX *pixd,
2124 PIX *pixs,
2125 l_int32 val0,
2126 l_int32 val1)
2127 {
2128 l_int32 w, h, i, j, byteval, nbytes, wpls, wpld;
2129 l_uint8 val[2];
2130 l_uint32 index;
2131 l_uint16 *tab;
2132 l_uint32 *datas, *datad, *lines, *lined;
2133
2134 PROCNAME("pixConvert1To2");
2135
2136 if (!pixs)
2137 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
2138 if (pixGetDepth(pixs) != 1)
2139 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
2140
2141 pixGetDimensions(pixs, &w, &h, NULL);
2142 if (pixd) {
2143 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
2144 return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
2145 if (pixGetDepth(pixd) != 2)
2146 return (PIX *)ERROR_PTR("pixd not 2 bpp", procName, pixd);
2147 } else {
2148 if ((pixd = pixCreate(w, h, 2)) == NULL)
2149 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2150 }
2151 pixCopyResolution(pixd, pixs);
2152 pixCopyInputFormat(pixd, pixs);
2153
2154 /* Use a table to convert 8 src bits to 16 dest bits */
2155 tab = (l_uint16 *)LEPT_CALLOC(256, sizeof(l_uint16));
2156 val[0] = val0;
2157 val[1] = val1;
2158 for (index = 0; index < 256; index++) {
2159 tab[index] = (val[(index >> 7) & 1] << 14) |
2160 (val[(index >> 6) & 1] << 12) |
2161 (val[(index >> 5) & 1] << 10) |
2162 (val[(index >> 4) & 1] << 8) |
2163 (val[(index >> 3) & 1] << 6) |
2164 (val[(index >> 2) & 1] << 4) |
2165 (val[(index >> 1) & 1] << 2) | val[index & 1];
2166 }
2167
2168 datas = pixGetData(pixs);
2169 wpls = pixGetWpl(pixs);
2170 datad = pixGetData(pixd);
2171 wpld = pixGetWpl(pixd);
2172 nbytes = (w + 7) / 8;
2173 for (i = 0; i < h; i++) {
2174 lines = datas + i * wpls;
2175 lined = datad + i * wpld;
2176 for (j = 0; j < nbytes; j++) {
2177 byteval = GET_DATA_BYTE(lines, j);
2178 SET_DATA_TWO_BYTES(lined, j, tab[byteval]);
2179 }
2180 }
2181
2182 LEPT_FREE(tab);
2183 return pixd;
2184 }
2185
2186
2187 /*---------------------------------------------------------------------------*
2188 * Conversion from 1 bpp to 4 bpp *
2189 *---------------------------------------------------------------------------*/
2190 /*!
2191 * \brief pixConvert1To4Cmap()
2192 *
2193 * \param[in] pixs 1 bpp
2194 * \return pixd 4 bpp, cmapped
2195 *
2196 * <pre>
2197 * Notes:
2198 * (1) Input 0 is mapped to (255, 255, 255); 1 is mapped to (0, 0, 0)
2199 * </pre>
2200 */
2201 PIX *
pixConvert1To4Cmap(PIX * pixs)2202 pixConvert1To4Cmap(PIX *pixs)
2203 {
2204 PIX *pixd;
2205 PIXCMAP *cmap;
2206
2207 PROCNAME("pixConvert1To4Cmap");
2208
2209 if (!pixs)
2210 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2211 if (pixGetDepth(pixs) != 1)
2212 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
2213
2214 if ((pixd = pixConvert1To4(NULL, pixs, 0, 1)) == NULL)
2215 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2216 cmap = pixcmapCreate(4);
2217 pixcmapAddColor(cmap, 255, 255, 255);
2218 pixcmapAddColor(cmap, 0, 0, 0);
2219 pixSetColormap(pixd, cmap);
2220 pixCopyInputFormat(pixd, pixs);
2221
2222 return pixd;
2223 }
2224
2225
2226 /*!
2227 * \brief pixConvert1To4()
2228 *
2229 * \param[in] pixd [optional] 4 bpp, can be null
2230 * \param[in] pixs 1 bpp
2231 * \param[in] val0 4 bit value to be used for 0s in pixs
2232 * \param[in] val1 4 bit value to be used for 1s in pixs
2233 * \return pixd 4 bpp
2234 *
2235 * <pre>
2236 * Notes:
2237 * (1) If pixd is null, a new pix is made.
2238 * (2) If pixd is not null, it must be of equal width and height
2239 * as pixs. It is always returned.
2240 * (3) A simple unpacking might use val0 = 0 and val1 = 15, or v.v.
2241 * (4) If you want a colormapped pixd, use pixConvert1To4Cmap().
2242 * </pre>
2243 */
2244 PIX *
pixConvert1To4(PIX * pixd,PIX * pixs,l_int32 val0,l_int32 val1)2245 pixConvert1To4(PIX *pixd,
2246 PIX *pixs,
2247 l_int32 val0,
2248 l_int32 val1)
2249 {
2250 l_int32 w, h, i, j, byteval, nbytes, wpls, wpld;
2251 l_uint8 val[2];
2252 l_uint32 index;
2253 l_uint32 *tab, *datas, *datad, *lines, *lined;
2254
2255 PROCNAME("pixConvert1To4");
2256
2257 if (!pixs)
2258 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
2259 if (pixGetDepth(pixs) != 1)
2260 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
2261
2262 pixGetDimensions(pixs, &w, &h, NULL);
2263 if (pixd) {
2264 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
2265 return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
2266 if (pixGetDepth(pixd) != 4)
2267 return (PIX *)ERROR_PTR("pixd not 4 bpp", procName, pixd);
2268 } else {
2269 if ((pixd = pixCreate(w, h, 4)) == NULL)
2270 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2271 }
2272 pixCopyResolution(pixd, pixs);
2273 pixCopyInputFormat(pixd, pixs);
2274
2275 /* Use a table to convert 8 src bits to 32 bit dest word */
2276 tab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
2277 val[0] = val0;
2278 val[1] = val1;
2279 for (index = 0; index < 256; index++) {
2280 tab[index] = (val[(index >> 7) & 1] << 28) |
2281 (val[(index >> 6) & 1] << 24) |
2282 (val[(index >> 5) & 1] << 20) |
2283 (val[(index >> 4) & 1] << 16) |
2284 (val[(index >> 3) & 1] << 12) |
2285 (val[(index >> 2) & 1] << 8) |
2286 (val[(index >> 1) & 1] << 4) | val[index & 1];
2287 }
2288
2289 datas = pixGetData(pixs);
2290 wpls = pixGetWpl(pixs);
2291 datad = pixGetData(pixd);
2292 wpld = pixGetWpl(pixd);
2293 nbytes = (w + 7) / 8;
2294 for (i = 0; i < h; i++) {
2295 lines = datas + i * wpls;
2296 lined = datad + i * wpld;
2297 for (j = 0; j < nbytes; j++) {
2298 byteval = GET_DATA_BYTE(lines, j);
2299 lined[j] = tab[byteval];
2300 }
2301 }
2302
2303 LEPT_FREE(tab);
2304 return pixd;
2305 }
2306
2307
2308 /*---------------------------------------------------------------------------*
2309 * Conversion from 1, 2 and 4 bpp to 8 bpp *
2310 *---------------------------------------------------------------------------*/
2311 /*!
2312 * \brief pixConvert1To8Cmap()
2313 *
2314 * \param[in] pixs 1 bpp
2315 * \return pixd 8 bpp, cmapped
2316 *
2317 * <pre>
2318 * Notes:
2319 * (1) Input 0 is mapped to (255, 255, 255); 1 is mapped to (0, 0, 0)
2320 * </pre>
2321 */
2322 PIX *
pixConvert1To8Cmap(PIX * pixs)2323 pixConvert1To8Cmap(PIX *pixs)
2324 {
2325 PIX *pixd;
2326 PIXCMAP *cmap;
2327
2328 PROCNAME("pixConvert1To8Cmap");
2329
2330 if (!pixs)
2331 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2332 if (pixGetDepth(pixs) != 1)
2333 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
2334
2335 if ((pixd = pixConvert1To8(NULL, pixs, 0, 1)) == NULL)
2336 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2337 cmap = pixcmapCreate(8);
2338 pixcmapAddColor(cmap, 255, 255, 255);
2339 pixcmapAddColor(cmap, 0, 0, 0);
2340 pixSetColormap(pixd, cmap);
2341 pixCopyInputFormat(pixd, pixs);
2342 return pixd;
2343 }
2344
2345
2346 /*!
2347 * \brief pixConvert1To8()
2348 *
2349 * \param[in] pixd [optional] 8 bpp, can be null
2350 * \param[in] pixs 1 bpp
2351 * \param[in] val0 8 bit value to be used for 0s in pixs
2352 * \param[in] val1 8 bit value to be used for 1s in pixs
2353 * \return pixd 8 bpp
2354 *
2355 * <pre>
2356 * Notes:
2357 * (1) If pixd is null, a new pix is made.
2358 * (2) If pixd is not null, it must be of equal width and height
2359 * as pixs. It is always returned.
2360 * (3) A simple unpacking might use val0 = 0 and val1 = 255, or v.v.
2361 * (4) To have a colormap associated with the 8 bpp pixd,
2362 * use pixConvert1To8Cmap().
2363 * </pre>
2364 */
2365 PIX *
pixConvert1To8(PIX * pixd,PIX * pixs,l_uint8 val0,l_uint8 val1)2366 pixConvert1To8(PIX *pixd,
2367 PIX *pixs,
2368 l_uint8 val0,
2369 l_uint8 val1)
2370 {
2371 l_int32 w, h, i, j, qbit, nqbits, wpls, wpld;
2372 l_uint8 val[2];
2373 l_uint32 index;
2374 l_uint32 *tab, *datas, *datad, *lines, *lined;
2375
2376 PROCNAME("pixConvert1To8");
2377
2378 if (!pixs)
2379 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
2380 if (pixGetDepth(pixs) != 1)
2381 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
2382
2383 pixGetDimensions(pixs, &w, &h, NULL);
2384 if (pixd) {
2385 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
2386 return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
2387 if (pixGetDepth(pixd) != 8)
2388 return (PIX *)ERROR_PTR("pixd not 8 bpp", procName, pixd);
2389 } else {
2390 if ((pixd = pixCreate(w, h, 8)) == NULL)
2391 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2392 }
2393 pixCopyResolution(pixd, pixs);
2394 pixCopyInputFormat(pixd, pixs);
2395
2396 /* Use a table to convert 4 src bits at a time */
2397 tab = (l_uint32 *)LEPT_CALLOC(16, sizeof(l_uint32));
2398 val[0] = val0;
2399 val[1] = val1;
2400 for (index = 0; index < 16; index++) {
2401 tab[index] = (val[(index >> 3) & 1] << 24) |
2402 (val[(index >> 2) & 1] << 16) |
2403 (val[(index >> 1) & 1] << 8) | val[index & 1];
2404 }
2405
2406 datas = pixGetData(pixs);
2407 wpls = pixGetWpl(pixs);
2408 datad = pixGetData(pixd);
2409 wpld = pixGetWpl(pixd);
2410 nqbits = (w + 3) / 4;
2411 for (i = 0; i < h; i++) {
2412 lines = datas + i * wpls;
2413 lined = datad + i * wpld;
2414 for (j = 0; j < nqbits; j++) {
2415 qbit = GET_DATA_QBIT(lines, j);
2416 lined[j] = tab[qbit];
2417 }
2418 }
2419
2420 LEPT_FREE(tab);
2421 return pixd;
2422 }
2423
2424
2425 /*!
2426 * \brief pixConvert2To8()
2427 *
2428 * \param[in] pixs 2 bpp
2429 * \param[in] val0 8 bit value to be used for 00 in pixs
2430 * \param[in] val1 8 bit value to be used for 01 in pixs
2431 * \param[in] val2 8 bit value to be used for 10 in pixs
2432 * \param[in] val3 8 bit value to be used for 11 in pixs
2433 * \param[in] cmapflag TRUE if pixd is to have a colormap; FALSE otherwise
2434 * \return pixd 8 bpp, or NULL on error
2435 *
2436 * <pre>
2437 * Notes:
2438 * ~ A simple unpacking might use val0 = 0,
2439 * val1 = 85 (0x55), val2 = 170 (0xaa), val3 = 255.
2440 * ~ If cmapflag is TRUE:
2441 * ~ The 8 bpp image is made with a colormap.
2442 * ~ If pixs has a colormap, the input values are ignored and
2443 * the 8 bpp image is made using the colormap
2444 * ~ If pixs does not have a colormap, the input values are
2445 * used to build the colormap.
2446 * ~ If cmapflag is FALSE:
2447 * ~ The 8 bpp image is made without a colormap.
2448 * ~ If pixs has a colormap, the input values are ignored,
2449 * the colormap is removed, and the values stored in the 8 bpp
2450 * image are from the colormap.
2451 * ~ If pixs does not have a colormap, the input values are
2452 * used to populate the 8 bpp image.
2453 * </pre>
2454 */
2455 PIX *
pixConvert2To8(PIX * pixs,l_uint8 val0,l_uint8 val1,l_uint8 val2,l_uint8 val3,l_int32 cmapflag)2456 pixConvert2To8(PIX *pixs,
2457 l_uint8 val0,
2458 l_uint8 val1,
2459 l_uint8 val2,
2460 l_uint8 val3,
2461 l_int32 cmapflag)
2462 {
2463 l_int32 w, h, i, j, nbytes, wpls, wpld, dibit, byte;
2464 l_uint8 val[4];
2465 l_uint32 index;
2466 l_uint32 *tab, *datas, *datad, *lines, *lined;
2467 PIX *pixd;
2468 PIXCMAP *cmaps, *cmapd;
2469
2470 PROCNAME("pixConvert2To8");
2471
2472 if (!pixs)
2473 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2474 if (pixGetDepth(pixs) != 2)
2475 return (PIX *)ERROR_PTR("pixs not 2 bpp", procName, NULL);
2476
2477 cmaps = pixGetColormap(pixs);
2478 if (cmaps && cmapflag == FALSE)
2479 return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
2480
2481 pixGetDimensions(pixs, &w, &h, NULL);
2482 if ((pixd = pixCreate(w, h, 8)) == NULL)
2483 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2484 pixCopyResolution(pixd, pixs);
2485 pixCopyInputFormat(pixd, pixs);
2486 datas = pixGetData(pixs);
2487 wpls = pixGetWpl(pixs);
2488 datad = pixGetData(pixd);
2489 wpld = pixGetWpl(pixd);
2490
2491 if (cmapflag == TRUE) { /* pixd will have a colormap */
2492 if (cmaps) { /* use the existing colormap from pixs */
2493 cmapd = pixcmapConvertTo8(cmaps);
2494 } else { /* make a colormap from the input values */
2495 cmapd = pixcmapCreate(8);
2496 pixcmapAddColor(cmapd, val0, val0, val0);
2497 pixcmapAddColor(cmapd, val1, val1, val1);
2498 pixcmapAddColor(cmapd, val2, val2, val2);
2499 pixcmapAddColor(cmapd, val3, val3, val3);
2500 }
2501 pixSetColormap(pixd, cmapd);
2502 for (i = 0; i < h; i++) {
2503 lines = datas + i * wpls;
2504 lined = datad + i * wpld;
2505 for (j = 0; j < w; j++) {
2506 dibit = GET_DATA_DIBIT(lines, j);
2507 SET_DATA_BYTE(lined, j, dibit);
2508 }
2509 }
2510 return pixd;
2511 }
2512
2513 /* Last case: no colormap in either pixs or pixd.
2514 * Use input values and build a table to convert 1 src byte
2515 * (4 src pixels) at a time */
2516 tab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
2517 val[0] = val0;
2518 val[1] = val1;
2519 val[2] = val2;
2520 val[3] = val3;
2521 for (index = 0; index < 256; index++) {
2522 tab[index] = (val[(index >> 6) & 3] << 24) |
2523 (val[(index >> 4) & 3] << 16) |
2524 (val[(index >> 2) & 3] << 8) | val[index & 3];
2525 }
2526
2527 nbytes = (w + 3) / 4;
2528 for (i = 0; i < h; i++) {
2529 lines = datas + i * wpls;
2530 lined = datad + i * wpld;
2531 for (j = 0; j < nbytes; j++) {
2532 byte = GET_DATA_BYTE(lines, j);
2533 lined[j] = tab[byte];
2534 }
2535 }
2536
2537 LEPT_FREE(tab);
2538 return pixd;
2539 }
2540
2541
2542 /*!
2543 * \brief pixConvert4To8()
2544 *
2545 * \param[in] pixs 4 bpp
2546 * \param[in] cmapflag TRUE if pixd is to have a colormap; FALSE otherwise
2547 * \return pixd 8 bpp, or NULL on error
2548 *
2549 * <pre>
2550 * Notes:
2551 * ~ If cmapflag is TRUE:
2552 * ~ pixd is made with a colormap.
2553 * ~ If pixs has a colormap, it is copied and the colormap
2554 * index values are placed in pixd.
2555 * ~ If pixs does not have a colormap, a colormap with linear
2556 * trc is built and the pixel values in pixs are placed in
2557 * pixd as colormap index values.
2558 * ~ If cmapflag is FALSE:
2559 * ~ pixd is made without a colormap.
2560 * ~ If pixs has a colormap, it is removed and the values stored
2561 * in pixd are from the colormap (converted to gray).
2562 * ~ If pixs does not have a colormap, the pixel values in pixs
2563 * are used, with shift replication, to populate pixd.
2564 * </pre>
2565 */
2566 PIX *
pixConvert4To8(PIX * pixs,l_int32 cmapflag)2567 pixConvert4To8(PIX *pixs,
2568 l_int32 cmapflag)
2569 {
2570 l_int32 w, h, i, j, wpls, wpld, byte, qbit;
2571 l_uint32 *datas, *datad, *lines, *lined;
2572 PIX *pixd;
2573 PIXCMAP *cmaps, *cmapd;
2574
2575 PROCNAME("pixConvert4To8");
2576
2577 if (!pixs)
2578 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2579 if (pixGetDepth(pixs) != 4)
2580 return (PIX *)ERROR_PTR("pixs not 4 bpp", procName, NULL);
2581
2582 cmaps = pixGetColormap(pixs);
2583 if (cmaps && cmapflag == FALSE)
2584 return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
2585
2586 pixGetDimensions(pixs, &w, &h, NULL);
2587 if ((pixd = pixCreate(w, h, 8)) == NULL)
2588 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2589 pixCopyResolution(pixd, pixs);
2590 pixCopyInputFormat(pixd, pixs);
2591 datas = pixGetData(pixs);
2592 wpls = pixGetWpl(pixs);
2593 datad = pixGetData(pixd);
2594 wpld = pixGetWpl(pixd);
2595
2596 if (cmapflag == TRUE) { /* pixd will have a colormap */
2597 if (cmaps) { /* use the existing colormap from pixs */
2598 cmapd = pixcmapConvertTo8(cmaps);
2599 } else { /* make a colormap with a linear trc */
2600 cmapd = pixcmapCreate(8);
2601 for (i = 0; i < 16; i++)
2602 pixcmapAddColor(cmapd, 17 * i, 17 * i, 17 * i);
2603 }
2604 pixSetColormap(pixd, cmapd);
2605 for (i = 0; i < h; i++) {
2606 lines = datas + i * wpls;
2607 lined = datad + i * wpld;
2608 for (j = 0; j < w; j++) {
2609 qbit = GET_DATA_QBIT(lines, j);
2610 SET_DATA_BYTE(lined, j, qbit);
2611 }
2612 }
2613 return pixd;
2614 }
2615
2616 /* Last case: no colormap in either pixs or pixd.
2617 * Replicate the qbit value into 8 bits. */
2618 for (i = 0; i < h; i++) {
2619 lines = datas + i * wpls;
2620 lined = datad + i * wpld;
2621 for (j = 0; j < w; j++) {
2622 qbit = GET_DATA_QBIT(lines, j);
2623 byte = (qbit << 4) | qbit;
2624 SET_DATA_BYTE(lined, j, byte);
2625 }
2626 }
2627 return pixd;
2628 }
2629
2630
2631
2632 /*---------------------------------------------------------------------------*
2633 * Unpacking conversion from 8 bpp to 16 bpp *
2634 *---------------------------------------------------------------------------*/
2635 /*!
2636 * \brief pixConvert8To16()
2637 *
2638 * \param[in] pixs 8 bpp; colormap removed to gray
2639 * \param[in] leftshift number of bits: 0 is no shift;
2640 * 8 replicates in MSB and LSB of dest
2641 * \return pixd 16 bpp, or NULL on error
2642 *
2643 * <pre>
2644 * Notes:
2645 * (1) For left shift of 8, the 8 bit value is replicated in both
2646 * the MSB and the LSB of the pixels in pixd. That way, we get
2647 * proportional mapping, with a correct map from 8 bpp white
2648 * (0xff) to 16 bpp white (0xffff).
2649 * </pre>
2650 */
2651 PIX *
pixConvert8To16(PIX * pixs,l_int32 leftshift)2652 pixConvert8To16(PIX *pixs,
2653 l_int32 leftshift)
2654 {
2655 l_int32 i, j, w, h, d, wplt, wpld, val;
2656 l_uint32 *datat, *datad, *linet, *lined;
2657 PIX *pixt, *pixd;
2658
2659 PROCNAME("pixConvert8To16");
2660
2661 if (!pixs)
2662 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2663 pixGetDimensions(pixs, &w, &h, &d);
2664 if (d != 8)
2665 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
2666 if (leftshift < 0 || leftshift > 8)
2667 return (PIX *)ERROR_PTR("leftshift not in [0 ... 8]", procName, NULL);
2668
2669 if (pixGetColormap(pixs) != NULL)
2670 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
2671 else
2672 pixt = pixClone(pixs);
2673
2674 pixd = pixCreate(w, h, 16);
2675 pixCopyResolution(pixd, pixs);
2676 pixCopyInputFormat(pixd, pixs);
2677 datat = pixGetData(pixt);
2678 datad = pixGetData(pixd);
2679 wplt = pixGetWpl(pixt);
2680 wpld = pixGetWpl(pixd);
2681 for (i = 0; i < h; i++) {
2682 linet = datat + i * wplt;
2683 lined = datad + i * wpld;
2684 for (j = 0; j < w; j++) {
2685 val = GET_DATA_BYTE(linet, j);
2686 if (leftshift == 8)
2687 val = val | (val << leftshift);
2688 else
2689 val <<= leftshift;
2690 SET_DATA_TWO_BYTES(lined, j, val);
2691 }
2692 }
2693
2694 pixDestroy(&pixt);
2695 return pixd;
2696 }
2697
2698
2699 /*---------------------------------------------------------------------------*
2700 * Top-level conversion to 2 bpp *
2701 *---------------------------------------------------------------------------*/
2702 /*!
2703 * \brief pixConvertTo2()
2704 *
2705 * \param[in] pixs 1, 2, 4, 8, 32 bpp; colormap OK but will be removed
2706 * \return pixd 2 bpp, or NULL on error
2707 *
2708 * <pre>
2709 * Notes:
2710 * (1) This is a top-level function, with simple default values
2711 * used in pixConvertTo8() if unpacking is necessary.
2712 * (2) Any existing colormap is removed; the result is always gray.
2713 * (3) If the input image has 2 bpp and no colormap, the operation is
2714 * lossless and a copy is returned.
2715 * </pre>
2716 */
2717 PIX *
pixConvertTo2(PIX * pixs)2718 pixConvertTo2(PIX *pixs)
2719 {
2720 l_int32 d;
2721 PIX *pix1, *pix2, *pix3, *pixd;
2722
2723 PROCNAME("pixConvertTo2");
2724
2725 if (!pixs)
2726 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2727 d = pixGetDepth(pixs);
2728 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 32)
2729 return (PIX *)ERROR_PTR("depth not {1,2,4,8,32}", procName, NULL);
2730
2731 if (pixGetColormap(pixs) != NULL) {
2732 pix1 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
2733 d = pixGetDepth(pix1);
2734 } else {
2735 pix1 = pixCopy(NULL, pixs);
2736 }
2737 if (d == 32)
2738 pix2 = pixConvertTo8(pix1, FALSE);
2739 else
2740 pix2 = pixClone(pix1);
2741 pixDestroy(&pix1);
2742 if (d == 1) {
2743 pixd = pixConvert1To2(NULL, pix2, 3, 0);
2744 } else if (d == 2) {
2745 pixd = pixClone(pix2);
2746 } else if (d == 4) {
2747 pix3 = pixConvert4To8(pix2, FALSE); /* unpack to 8 */
2748 pixd = pixConvert8To2(pix3);
2749 pixDestroy(&pix3);
2750 } else { /* d == 8 */
2751 pixd = pixConvert8To2(pix2);
2752 }
2753 pixDestroy(&pix2);
2754 return pixd;
2755 }
2756
2757
2758 /*!
2759 * \brief pixConvert8To2()
2760 *
2761 * \param[in] pix 8 bpp; colormap OK
2762 * \return pixd 2 bpp, or NULL on error
2763 *
2764 * <pre>
2765 * Notes:
2766 * (1) Any existing colormap is removed to gray.
2767 * </pre>
2768 */
2769 PIX *
pixConvert8To2(PIX * pix)2770 pixConvert8To2(PIX *pix)
2771 {
2772 l_int32 i, j, w, h, wpls, wpld;
2773 l_uint32 word;
2774 l_uint32 *datas, *lines, *datad, *lined;
2775 PIX *pixs, *pixd;
2776
2777 PROCNAME("pixConvert8To2");
2778
2779 if (!pix || pixGetDepth(pix) != 8)
2780 return (PIX *)ERROR_PTR("pix undefined or not 8 bpp", procName, NULL);
2781
2782 if (pixGetColormap(pix) != NULL)
2783 pixs = pixRemoveColormap(pix, REMOVE_CMAP_TO_GRAYSCALE);
2784 else
2785 pixs = pixClone(pix);
2786 pixGetDimensions(pixs, &w, &h, NULL);
2787 datas = pixGetData(pixs);
2788 wpls = pixGetWpl(pixs);
2789 pixd = pixCreate(w, h, 2);
2790 datad = pixGetData(pixd);
2791 wpld = pixGetWpl(pixd);
2792 for (i = 0; i < h; i++) {
2793 lines = datas + i * wpls;
2794 lined = datad + i * wpld;
2795 for (j = 0; j < wpls; j++) { /* march through 4 pixels at a time */
2796 word = lines[j] & 0xc0c0c0c0; /* top 2 bits of each byte */
2797 word = (word >> 24) | ((word & 0xff0000) >> 18) |
2798 ((word & 0xff00) >> 12) | ((word & 0xff) >> 6);
2799 SET_DATA_BYTE(lined, j, word); /* only LS byte is filled */
2800 }
2801 }
2802 pixDestroy(&pixs);
2803 return pixd;
2804 }
2805
2806
2807 /*---------------------------------------------------------------------------*
2808 * Top-level conversion to 4 bpp *
2809 *---------------------------------------------------------------------------*/
2810 /*!
2811 * \brief pixConvertTo4()
2812 *
2813 * \param[in] pixs 1, 2, 4, 8, 32 bpp; colormap OK but will be removed
2814 * \return pixd 4 bpp, or NULL on error
2815 *
2816 * <pre>
2817 * Notes:
2818 * (1) This is a top-level function, with simple default values
2819 * used in pixConvertTo8() if unpacking is necessary.
2820 * (2) Any existing colormap is removed; the result is always gray.
2821 * (3) If the input image has 4 bpp and no colormap, the operation is
2822 * lossless and a copy is returned.
2823 * </pre>
2824 */
2825 PIX *
pixConvertTo4(PIX * pixs)2826 pixConvertTo4(PIX *pixs)
2827 {
2828 l_int32 d;
2829 PIX *pix1, *pix2, *pix3, *pixd;
2830
2831 PROCNAME("pixConvertTo4");
2832
2833 if (!pixs)
2834 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2835 d = pixGetDepth(pixs);
2836 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 32)
2837 return (PIX *)ERROR_PTR("depth not {1,2,4,8,32}", procName, NULL);
2838
2839 if (pixGetColormap(pixs) != NULL) {
2840 pix1 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
2841 d = pixGetDepth(pix1);
2842 } else {
2843 pix1 = pixCopy(NULL, pixs);
2844 }
2845 if (d == 32)
2846 pix2 = pixConvertTo8(pix1, FALSE);
2847 else
2848 pix2 = pixClone(pix1);
2849 pixDestroy(&pix1);
2850 if (d == 1) {
2851 pixd = pixConvert1To4(NULL, pix2, 15, 0);
2852 } else if (d == 2) {
2853 pix3 = pixConvert2To8(pix2, 0, 0x55, 0xaa, 0xff, FALSE);
2854 pixd = pixConvert8To4(pix3);
2855 pixDestroy(&pix3);
2856 } else if (d == 4) {
2857 pixd = pixClone(pix2);
2858 } else { /* d == 8 */
2859 pixd = pixConvert8To4(pix2);
2860 }
2861 pixDestroy(&pix2);
2862 return pixd;
2863 }
2864
2865
2866 /*!
2867 * \brief pixConvert8To4()
2868 *
2869 * \param[in] pix 8 bpp; colormap OK
2870 * \return pixd 4 bpp, or NULL on error
2871 *
2872 * <pre>
2873 * Notes:
2874 * (1) Any existing colormap is removed to gray.
2875 * </pre>
2876 */
2877 PIX *
pixConvert8To4(PIX * pix)2878 pixConvert8To4(PIX *pix)
2879 {
2880 l_int32 i, j, w, h, wpls, wpld, val;
2881 l_uint32 *datas, *lines, *datad, *lined;
2882 PIX *pixs, *pixd;
2883
2884 PROCNAME("pixConvert8To4");
2885
2886 if (!pix || pixGetDepth(pix) != 8)
2887 return (PIX *)ERROR_PTR("pix undefined or not 8 bpp", procName, NULL);
2888
2889 if (pixGetColormap(pix) != NULL)
2890 pixs = pixRemoveColormap(pix, REMOVE_CMAP_TO_GRAYSCALE);
2891 else
2892 pixs = pixClone(pix);
2893 pixGetDimensions(pixs, &w, &h, NULL);
2894 datas = pixGetData(pixs);
2895 wpls = pixGetWpl(pixs);
2896 pixd = pixCreate(w, h, 4);
2897 datad = pixGetData(pixd);
2898 wpld = pixGetWpl(pixd);
2899 for (i = 0; i < h; i++) {
2900 lines = datas + i * wpls;
2901 lined = datad + i * wpld;
2902 for (j = 0; j < w; j++) {
2903 val = GET_DATA_BYTE(lines, j);
2904 val = val >> 4; /* take top 4 bits */
2905 SET_DATA_QBIT(lined, j, val);
2906 }
2907 }
2908 pixDestroy(&pixs);
2909 return pixd;
2910 }
2911
2912
2913 /*---------------------------------------------------------------------------*
2914 * Top-level conversion to 1 bpp *
2915 *---------------------------------------------------------------------------*/
2916 /*!
2917 * \brief pixConvertTo1()
2918 *
2919 * \param[in] pixs 1, 2, 4, 8, 16 or 32 bpp
2920 * \param[in] threshold for final binarization, relative to 8 bpp
2921 * \return pixd 1 bpp, or NULL on error
2922 *
2923 * <pre>
2924 * Notes:
2925 * (1) This is a top-level function, with simple default values
2926 * used in pixConvertTo8() if unpacking is necessary.
2927 * (2) Any existing colormap is removed.
2928 * (3) If the input image has 1 bpp and no colormap, the operation is
2929 * lossless and a copy is returned.
2930 * </pre>
2931 */
2932 PIX *
pixConvertTo1(PIX * pixs,l_int32 threshold)2933 pixConvertTo1(PIX *pixs,
2934 l_int32 threshold)
2935 {
2936 l_int32 d, color0, color1, rval, gval, bval;
2937 PIX *pixg, *pixd;
2938 PIXCMAP *cmap;
2939
2940 PROCNAME("pixConvertTo1");
2941
2942 if (!pixs)
2943 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2944 d = pixGetDepth(pixs);
2945 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
2946 return (PIX *)ERROR_PTR("depth not {1,2,4,8,16,32}", procName, NULL);
2947
2948 cmap = pixGetColormap(pixs);
2949 if (d == 1) {
2950 if (!cmap) {
2951 return pixCopy(NULL, pixs);
2952 } else { /* strip the colormap off, and invert if reasonable
2953 for standard binary photometry. */
2954 pixcmapGetColor(cmap, 0, &rval, &gval, &bval);
2955 color0 = rval + gval + bval;
2956 pixcmapGetColor(cmap, 1, &rval, &gval, &bval);
2957 color1 = rval + gval + bval;
2958 pixd = pixCopy(NULL, pixs);
2959 pixDestroyColormap(pixd);
2960 if (color1 > color0)
2961 pixInvert(pixd, pixd);
2962 return pixd;
2963 }
2964 }
2965
2966 /* For all other depths, use 8 bpp as an intermediary */
2967 pixg = pixConvertTo8(pixs, FALSE);
2968 pixd = pixThresholdToBinary(pixg, threshold);
2969 pixDestroy(&pixg);
2970 return pixd;
2971 }
2972
2973
2974 /*!
2975 * \brief pixConvertTo1BySampling()
2976 *
2977 * \param[in] pixs 1, 2, 4, 8, 16 or 32 bpp
2978 * \param[in] factor submsampling factor; integer >= 1
2979 * \param[in] threshold for final binarization, relative to 8 bpp
2980 * \return pixd 1 bpp, or NULL on error
2981 *
2982 * <pre>
2983 * Notes:
2984 * (1) This is a quick and dirty, top-level converter.
2985 * (2) See pixConvertTo1() for default values.
2986 * </pre>
2987 */
2988 PIX *
pixConvertTo1BySampling(PIX * pixs,l_int32 factor,l_int32 threshold)2989 pixConvertTo1BySampling(PIX *pixs,
2990 l_int32 factor,
2991 l_int32 threshold)
2992 {
2993 l_float32 scalefactor;
2994 PIX *pixt, *pixd;
2995
2996 PROCNAME("pixConvertTo1BySampling");
2997
2998 if (!pixs)
2999 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3000 if (factor < 1)
3001 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
3002
3003 scalefactor = 1. / (l_float32)factor;
3004 pixt = pixScaleBySampling(pixs, scalefactor, scalefactor);
3005 pixd = pixConvertTo1(pixt, threshold);
3006
3007 pixDestroy(&pixt);
3008 return pixd;
3009 }
3010
3011
3012 /*---------------------------------------------------------------------------*
3013 * Top-level conversion to 8 bpp *
3014 *---------------------------------------------------------------------------*/
3015 /*!
3016 * \brief pixConvertTo8()
3017 *
3018 * \param[in] pixs 1, 2, 4, 8, 16 or 32 bpp
3019 * \param[in] cmapflag TRUE if pixd is to have a colormap; FALSE otherwise
3020 * \return pixd 8 bpp, or NULL on error
3021 *
3022 * <pre>
3023 * Notes:
3024 * (1) This is a top-level function, with simple default values
3025 * for unpacking.
3026 * (2) The result, pixd, is made with a colormap if specified.
3027 * It is always a new image -- never a clone. For example,
3028 * if d == 8, and cmapflag matches the existence of a cmap
3029 * in pixs, the operation is lossless and it returns a copy.
3030 * (3) The default values used are:
3031 * ~ 1 bpp: val0 = 255, val1 = 0
3032 * ~ 2 bpp: 4 bpp: even increments over dynamic range
3033 * ~ 8 bpp: lossless if cmap matches cmapflag
3034 * ~ 16 bpp: use most significant byte
3035 * (4) If 32 bpp RGB, this is converted to gray. If you want
3036 * to do color quantization, you must specify the type
3037 * explicitly, using the color quantization code.
3038 * </pre>
3039 */
3040 PIX *
pixConvertTo8(PIX * pixs,l_int32 cmapflag)3041 pixConvertTo8(PIX *pixs,
3042 l_int32 cmapflag)
3043 {
3044 l_int32 d;
3045 PIX *pixd;
3046 PIXCMAP *cmap;
3047
3048 PROCNAME("pixConvertTo8");
3049
3050 if (!pixs)
3051 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3052 d = pixGetDepth(pixs);
3053 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
3054 return (PIX *)ERROR_PTR("depth not {1,2,4,8,16,32}", procName, NULL);
3055
3056 if (d == 1) {
3057 if (cmapflag)
3058 return pixConvert1To8Cmap(pixs);
3059 else
3060 return pixConvert1To8(NULL, pixs, 255, 0);
3061 } else if (d == 2) {
3062 return pixConvert2To8(pixs, 0, 85, 170, 255, cmapflag);
3063 } else if (d == 4) {
3064 return pixConvert4To8(pixs, cmapflag);
3065 } else if (d == 8) {
3066 cmap = pixGetColormap(pixs);
3067 if ((cmap && cmapflag) || (!cmap && !cmapflag)) {
3068 return pixCopy(NULL, pixs);
3069 } else if (cmap) { /* !cmapflag */
3070 return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
3071 } else { /* !cmap && cmapflag; add colormap to pixd */
3072 pixd = pixCopy(NULL, pixs);
3073 pixAddGrayColormap8(pixd);
3074 return pixd;
3075 }
3076 } else if (d == 16) {
3077 pixd = pixConvert16To8(pixs, L_MS_BYTE);
3078 if (cmapflag)
3079 pixAddGrayColormap8(pixd);
3080 return pixd;
3081 } else { /* d == 32 */
3082 pixd = pixConvertRGBToLuminance(pixs);
3083 if (cmapflag)
3084 pixAddGrayColormap8(pixd);
3085 return pixd;
3086 }
3087 }
3088
3089
3090 /*!
3091 * \brief pixConvertTo8BySampling()
3092 *
3093 * \param[in] pixs 1, 2, 4, 8, 16 or 32 bpp
3094 * \param[in] factor submsampling factor; integer >= 1
3095 * \param[in] cmapflag TRUE if pixd is to have a colormap; FALSE otherwise
3096 * \return pixd 8 bpp, or NULL on error
3097 *
3098 * <pre>
3099 * Notes:
3100 * (1) This is a fast, quick/dirty, top-level converter.
3101 * (2) See pixConvertTo8() for default values.
3102 * </pre>
3103 */
3104 PIX *
pixConvertTo8BySampling(PIX * pixs,l_int32 factor,l_int32 cmapflag)3105 pixConvertTo8BySampling(PIX *pixs,
3106 l_int32 factor,
3107 l_int32 cmapflag)
3108 {
3109 l_float32 scalefactor;
3110 PIX *pixt, *pixd;
3111
3112 PROCNAME("pixConvertTo8BySampling");
3113
3114 if (!pixs)
3115 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3116 if (factor < 1)
3117 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
3118
3119 scalefactor = 1. / (l_float32)factor;
3120 pixt = pixScaleBySampling(pixs, scalefactor, scalefactor);
3121 pixd = pixConvertTo8(pixt, cmapflag);
3122
3123 pixDestroy(&pixt);
3124 return pixd;
3125 }
3126
3127
3128 /*!
3129 * \brief pixConvertTo8Colormap()
3130 *
3131 * \param[in] pixs 1, 2, 4, 8, 16 or 32 bpp
3132 * \param[in] dither 1 to dither if necessary; 0 otherwise
3133 * \return pixd 8 bpp, cmapped, or NULL on error
3134 *
3135 * <pre>
3136 * Notes:
3137 * (1) This is a top-level function, with simple default values
3138 * for unpacking.
3139 * (2) The result, pixd, is always made with a colormap.
3140 * (3) If d == 8, the operation is lossless and it returns a copy.
3141 * (4) The default values used for increasing depth are:
3142 * ~ 1 bpp: val0 = 255, val1 = 0
3143 * ~ 2 bpp: 4 bpp: even increments over dynamic range
3144 * (5) For 16 bpp, use the most significant byte.
3145 * (6) For 32 bpp RGB, use octcube quantization with optional dithering.
3146 * </pre>
3147 */
3148 PIX *
pixConvertTo8Colormap(PIX * pixs,l_int32 dither)3149 pixConvertTo8Colormap(PIX *pixs,
3150 l_int32 dither)
3151 {
3152 l_int32 d;
3153
3154 PROCNAME("pixConvertTo8Colormap");
3155
3156 if (!pixs)
3157 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3158 d = pixGetDepth(pixs);
3159 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
3160 return (PIX *)ERROR_PTR("depth not {1,2,4,8,16,32}", procName, NULL);
3161
3162 if (d != 32)
3163 return pixConvertTo8(pixs, 1);
3164
3165 return pixConvertRGBToColormap(pixs, dither);
3166 }
3167
3168
3169 /*---------------------------------------------------------------------------*
3170 * Top-level conversion to 16 bpp *
3171 *---------------------------------------------------------------------------*/
3172 /*!
3173 * \brief pixConvertTo16()
3174 *
3175 * \param[in] pixs 1, 8 bpp
3176 * \return pixd 16 bpp, or NULL on error
3177 *
3178 * Usage: Top-level function, with simple default values for unpacking.
3179 * 1 bpp: val0 = 0xffff, val1 = 0
3180 * 8 bpp: replicates the 8 bit value in both the MSB and LSB
3181 * of the 16 bit pixel.
3182 */
3183 PIX *
pixConvertTo16(PIX * pixs)3184 pixConvertTo16(PIX *pixs)
3185 {
3186 l_int32 d;
3187
3188 PROCNAME("pixConvertTo16");
3189
3190 if (!pixs)
3191 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3192
3193 d = pixGetDepth(pixs);
3194 if (d == 1)
3195 return pixConvert1To16(NULL, pixs, 0xffff, 0);
3196 else if (d == 8)
3197 return pixConvert8To16(pixs, 8);
3198 else
3199 return (PIX *)ERROR_PTR("src depth not 1 or 8 bpp", procName, NULL);
3200 }
3201
3202
3203
3204 /*---------------------------------------------------------------------------*
3205 * Top-level conversion to 32 bpp *
3206 *---------------------------------------------------------------------------*/
3207 /*!
3208 * \brief pixConvertTo32()
3209 *
3210 * \param[in] pixs 1, 2, 4, 8, 16 or 32 bpp
3211 * \return pixd 32 bpp, or NULL on error
3212 *
3213 * Usage: Top-level function, with simple default values for unpacking.
3214 * 1 bpp: val0 = 255, val1 = 0
3215 * and then replication into R, G and B components
3216 * 2 bpp: if colormapped, use the colormap values; otherwise,
3217 * use val0 = 0, val1 = 0x55, val2 = 0xaa, val3 = 255
3218 * and replicate gray into R, G and B components
3219 * 4 bpp: if colormapped, use the colormap values; otherwise,
3220 * replicate 2 nybs into a byte, and then into R,G,B components
3221 * 8 bpp: if colormapped, use the colormap values; otherwise,
3222 * replicate gray values into R, G and B components
3223 * 16 bpp: replicate MSB into R, G and B components
3224 * 24 bpp: unpack the pixels, maintaining word alignment on each scanline
3225 * 32 bpp: makes a copy
3226 *
3227 * <pre>
3228 * Notes:
3229 * (1) Never returns a clone of pixs.
3230 * </pre>
3231 */
3232 PIX *
pixConvertTo32(PIX * pixs)3233 pixConvertTo32(PIX *pixs)
3234 {
3235 l_int32 d;
3236 PIX *pix1, *pixd;
3237
3238 PROCNAME("pixConvertTo32");
3239
3240 if (!pixs)
3241 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3242
3243 d = pixGetDepth(pixs);
3244 if (d == 1) {
3245 return pixConvert1To32(NULL, pixs, 0xffffffff, 0);
3246 } else if (d == 2) {
3247 pix1 = pixConvert2To8(pixs, 0, 85, 170, 255, TRUE);
3248 pixd = pixConvert8To32(pix1);
3249 pixDestroy(&pix1);
3250 return pixd;
3251 } else if (d == 4) {
3252 pix1 = pixConvert4To8(pixs, TRUE);
3253 pixd = pixConvert8To32(pix1);
3254 pixDestroy(&pix1);
3255 return pixd;
3256 } else if (d == 8) {
3257 return pixConvert8To32(pixs);
3258 } else if (d == 16) {
3259 pix1 = pixConvert16To8(pixs, L_MS_BYTE);
3260 pixd = pixConvert8To32(pix1);
3261 pixDestroy(&pix1);
3262 return pixd;
3263 } else if (d == 24) {
3264 return pixConvert24To32(pixs);
3265 } else if (d == 32) {
3266 return pixCopy(NULL, pixs);
3267 } else {
3268 return (PIX *)ERROR_PTR("depth not 1, 2, 4, 8, 16, 32 bpp",
3269 procName, NULL);
3270 }
3271 }
3272
3273
3274 /*!
3275 * \brief pixConvertTo32BySampling()
3276 *
3277 * \param[in] pixs 1, 2, 4, 8, 16 or 32 bpp
3278 * \param[in] factor submsampling factor; integer >= 1
3279 * \return pixd 32 bpp, or NULL on error
3280 *
3281 * <pre>
3282 * Notes:
3283 * (1) This is a fast, quick/dirty, top-level converter.
3284 * (2) See pixConvertTo32() for default values.
3285 * </pre>
3286 */
3287 PIX *
pixConvertTo32BySampling(PIX * pixs,l_int32 factor)3288 pixConvertTo32BySampling(PIX *pixs,
3289 l_int32 factor)
3290 {
3291 l_float32 scalefactor;
3292 PIX *pix1, *pixd;
3293
3294 PROCNAME("pixConvertTo32BySampling");
3295
3296 if (!pixs)
3297 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3298 if (factor < 1)
3299 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
3300
3301 scalefactor = 1. / (l_float32)factor;
3302 pix1 = pixScaleBySampling(pixs, scalefactor, scalefactor);
3303 pixd = pixConvertTo32(pix1);
3304
3305 pixDestroy(&pix1);
3306 return pixd;
3307 }
3308
3309
3310 /*!
3311 * \brief pixConvert8To32()
3312 *
3313 * \param[in] pixs 8 bpp
3314 * \return 32 bpp rgb pix, or NULL on error
3315 *
3316 * <pre>
3317 * Notes:
3318 * (1) If there is no colormap, replicates the gray value
3319 * into the 3 MSB of the dest pixel.
3320 * </pre>
3321 */
3322 PIX *
pixConvert8To32(PIX * pixs)3323 pixConvert8To32(PIX *pixs)
3324 {
3325 l_int32 i, j, w, h, wpls, wpld, val;
3326 l_uint32 *datas, *datad, *lines, *lined;
3327 l_uint32 *tab;
3328 PIX *pixd;
3329
3330 PROCNAME("pixConvert8To32");
3331
3332 if (!pixs)
3333 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3334 if (pixGetDepth(pixs) != 8)
3335 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
3336
3337 if (pixGetColormap(pixs))
3338 return pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
3339
3340 pixGetDimensions(pixs, &w, &h, NULL);
3341 datas = pixGetData(pixs);
3342 wpls = pixGetWpl(pixs);
3343 if ((pixd = pixCreate(w, h, 32)) == NULL)
3344 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
3345 pixCopyResolution(pixd, pixs);
3346 pixCopyInputFormat(pixd, pixs);
3347 datad = pixGetData(pixd);
3348 wpld = pixGetWpl(pixd);
3349
3350 /* Replication table gray --> rgb */
3351 tab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
3352 for (i = 0; i < 256; i++)
3353 tab[i] = (i << 24) | (i << 16) | (i << 8);
3354
3355 /* Replicate 1 --> 4 bytes (alpha byte not set) */
3356 for (i = 0; i < h; i++) {
3357 lines = datas + i * wpls;
3358 lined = datad + i * wpld;
3359 for (j = 0; j < w; j++) {
3360 val = GET_DATA_BYTE(lines, j);
3361 lined[j] = tab[val];
3362 }
3363 }
3364
3365 LEPT_FREE(tab);
3366 return pixd;
3367 }
3368
3369
3370 /*---------------------------------------------------------------------------*
3371 * Top-level conversion to 8 or 32 bpp, without colormap *
3372 *---------------------------------------------------------------------------*/
3373 /*!
3374 * \brief pixConvertTo8Or32()
3375 *
3376 * \param[in] pixs 1, 2, 4, 8, 16, with or without colormap;
3377 * or 32 bpp rgb
3378 * \param[in] copyflag L_CLONE or L_COPY
3379 * \param[in] warnflag 1 to issue warning if colormap is removed; else 0
3380 * \return pixd 8 bpp grayscale or 32 bpp rgb, or NULL on error
3381 *
3382 * <pre>
3383 * Notes:
3384 * (1) If there is a colormap, the colormap is removed to 8 or 32 bpp,
3385 * depending on whether the colors in the colormap are all gray.
3386 * (2) If the input is either rgb or 8 bpp without a colormap,
3387 * this returns either a clone or a copy, depending on %copyflag.
3388 * (3) Otherwise, the pix is converted to 8 bpp grayscale.
3389 * In all cases, pixd does not have a colormap.
3390 * </pre>
3391 */
3392 PIX *
pixConvertTo8Or32(PIX * pixs,l_int32 copyflag,l_int32 warnflag)3393 pixConvertTo8Or32(PIX *pixs,
3394 l_int32 copyflag,
3395 l_int32 warnflag)
3396 {
3397 l_int32 d;
3398 PIX *pixd;
3399
3400 PROCNAME("pixConvertTo8Or32");
3401
3402 if (!pixs)
3403 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3404 if (copyflag != L_CLONE && copyflag != L_COPY)
3405 return (PIX *)ERROR_PTR("invalid copyflag", procName, NULL);
3406
3407 d = pixGetDepth(pixs);
3408 if (pixGetColormap(pixs)) {
3409 if (warnflag) L_WARNING("pix has colormap; removing\n", procName);
3410 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
3411 } else if (d == 8 || d == 32) {
3412 if (copyflag == L_CLONE)
3413 pixd = pixClone(pixs);
3414 else /* copyflag == L_COPY */
3415 pixd = pixCopy(NULL, pixs);
3416 } else {
3417 pixd = pixConvertTo8(pixs, 0);
3418 }
3419
3420 /* Sanity check on result */
3421 d = pixGetDepth(pixd);
3422 if (d != 8 && d != 32) {
3423 pixDestroy(&pixd);
3424 return (PIX *)ERROR_PTR("depth not 8 or 32 bpp", procName, NULL);
3425 }
3426
3427 return pixd;
3428 }
3429
3430
3431 /*---------------------------------------------------------------------------*
3432 * Conversion between 24 bpp and 32 bpp rgb *
3433 *---------------------------------------------------------------------------*/
3434 /*!
3435 * \brief pixConvert24To32()
3436 *
3437 * \param[in] pixs 24 bpp rgb
3438 * \return pixd 32 bpp rgb, or NULL on error
3439 *
3440 * <pre>
3441 * Notes:
3442 * (1) 24 bpp rgb pix are not supported in leptonica, except for a small
3443 * number of formatted write operations. The data is a byte array,
3444 * with pixels in order r,g,b, and padded to 32 bit boundaries
3445 * in each line.
3446 * (2) Because 24 bpp rgb pix are conveniently generated by programs
3447 * such as xpdf (which has SplashBitmaps that store the raster
3448 * data in consecutive 24-bit rgb pixels), it is useful to provide
3449 * 24 bpp pix that simply incorporate that data. The only things
3450 * we can do with these are:
3451 * (a) write them to file in png, jpeg, tiff and pnm
3452 * (b) interconvert between 24 and 32 bpp in memory (for testing).
3453 * </pre>
3454 */
3455 PIX *
pixConvert24To32(PIX * pixs)3456 pixConvert24To32(PIX *pixs)
3457 {
3458 l_uint8 *lines;
3459 l_int32 w, h, d, i, j, wpls, wpld, rval, gval, bval;
3460 l_uint32 pixel;
3461 l_uint32 *datas, *datad, *lined;
3462 PIX *pixd;
3463
3464 PROCNAME("pixConvert24to32");
3465
3466 if (!pixs)
3467 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3468 pixGetDimensions(pixs, &w, &h, &d);
3469 if (d != 24)
3470 return (PIX *)ERROR_PTR("pixs not 24 bpp", procName, NULL);
3471
3472 pixd = pixCreateNoInit(w, h, 32);
3473 datas = pixGetData(pixs);
3474 datad = pixGetData(pixd);
3475 wpls = pixGetWpl(pixs);
3476 wpld = pixGetWpl(pixd);
3477 for (i = 0; i < h; i++) {
3478 lines = (l_uint8 *)(datas + i * wpls);
3479 lined = datad + i * wpld;
3480 for (j = 0; j < w; j++) {
3481 rval = *lines++;
3482 gval = *lines++;
3483 bval = *lines++;
3484 composeRGBPixel(rval, gval, bval, &pixel);
3485 lined[j] = pixel;
3486 }
3487 }
3488 pixCopyResolution(pixd, pixs);
3489 pixCopyInputFormat(pixd, pixs);
3490 return pixd;
3491 }
3492
3493
3494 /*!
3495 * \brief pixConvert32To24()
3496 *
3497 * \param[in] pixs 32 bpp rgb
3498 * \return pixd 24 bpp rgb, or NULL on error
3499 *
3500 * <pre>
3501 * Notes:
3502 * (1) See pixconvert24To32().
3503 * </pre>
3504 */
3505 PIX *
pixConvert32To24(PIX * pixs)3506 pixConvert32To24(PIX *pixs)
3507 {
3508 l_uint8 *rgbdata8;
3509 l_int32 w, h, d, i, j, wpls, wpld, rval, gval, bval;
3510 l_uint32 *datas, *lines, *rgbdata;
3511 PIX *pixd;
3512
3513 PROCNAME("pixConvert32to24");
3514
3515 if (!pixs)
3516 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3517 pixGetDimensions(pixs, &w, &h, &d);
3518 if (d != 32)
3519 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
3520
3521 datas = pixGetData(pixs);
3522 wpls = pixGetWpl(pixs);
3523 pixd = pixCreateNoInit(w, h, 24);
3524 rgbdata = pixGetData(pixd);
3525 wpld = pixGetWpl(pixd);
3526 for (i = 0; i < h; i++) {
3527 lines = datas + i * wpls;
3528 rgbdata8 = (l_uint8 *)(rgbdata + i * wpld);
3529 for (j = 0; j < w; j++) {
3530 extractRGBValues(lines[j], &rval, &gval, &bval);
3531 *rgbdata8++ = rval;
3532 *rgbdata8++ = gval;
3533 *rgbdata8++ = bval;
3534 }
3535 }
3536 pixCopyResolution(pixd, pixs);
3537 pixCopyInputFormat(pixd, pixs);
3538 return pixd;
3539 }
3540
3541
3542 /*---------------------------------------------------------------------------*
3543 * Conversion between 32 bpp (1 spp) and 16 or 8 bpp *
3544 *---------------------------------------------------------------------------*/
3545 /*!
3546 * \brief pixConvert32To16()
3547 *
3548 * \param[in] pixs 32 bpp, single component
3549 * \param[in] type L_LS_TWO_BYTES, L_MS_TWO_BYTES, L_CLIP_TO_FFFF
3550 * \return pixd 16 bpp , or NULL on error
3551 *
3552 * <pre>
3553 * Notes:
3554 * (1) The data in pixs is typically used for labelling.
3555 * It is an array of l_uint32 values, not rgb or rgba.
3556 * </pre>
3557 */
3558 PIX *
pixConvert32To16(PIX * pixs,l_int32 type)3559 pixConvert32To16(PIX *pixs,
3560 l_int32 type)
3561 {
3562 l_uint16 dword;
3563 l_int32 w, h, i, j, wpls, wpld;
3564 l_uint32 sword;
3565 l_uint32 *datas, *lines, *datad, *lined;
3566 PIX *pixd;
3567
3568 PROCNAME("pixConvert32to16");
3569
3570 if (!pixs || pixGetDepth(pixs) != 32)
3571 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
3572 if (type != L_LS_TWO_BYTES && type != L_MS_TWO_BYTES &&
3573 type != L_CLIP_TO_FFFF)
3574 return (PIX *)ERROR_PTR("invalid type", procName, NULL);
3575
3576 pixGetDimensions(pixs, &w, &h, NULL);
3577 if ((pixd = pixCreate(w, h, 16)) == NULL)
3578 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
3579 pixCopyResolution(pixd, pixs);
3580 pixCopyInputFormat(pixd, pixs);
3581 wpls = pixGetWpl(pixs);
3582 datas = pixGetData(pixs);
3583 wpld = pixGetWpl(pixd);
3584 datad = pixGetData(pixd);
3585
3586 for (i = 0; i < h; i++) {
3587 lines = datas + i * wpls;
3588 lined = datad + i * wpld;
3589 if (type == L_LS_TWO_BYTES) {
3590 for (j = 0; j < wpls; j++) {
3591 sword = *(lines + j);
3592 dword = sword & 0xffff;
3593 SET_DATA_TWO_BYTES(lined, j, dword);
3594 }
3595 } else if (type == L_MS_TWO_BYTES) {
3596 for (j = 0; j < wpls; j++) {
3597 sword = *(lines + j);
3598 dword = sword >> 16;
3599 SET_DATA_TWO_BYTES(lined, j, dword);
3600 }
3601 } else { /* type == L_CLIP_TO_FFFF */
3602 for (j = 0; j < wpls; j++) {
3603 sword = *(lines + j);
3604 dword = (sword >> 16) ? 0xffff : (sword & 0xffff);
3605 SET_DATA_TWO_BYTES(lined, j, dword);
3606 }
3607 }
3608 }
3609
3610 return pixd;
3611 }
3612
3613
3614 /*!
3615 * \brief pixConvert32To8()
3616 *
3617 * \param[in] pixs 32 bpp, single component
3618 * \param[in] type16 L_LS_TWO_BYTES, L_MS_TWO_BYTES, L_CLIP_TO_FFFF
3619 * \param[in] type8 L_LS_BYTE, L_MS_BYTE, L_CLIP_TO_FF
3620 * \return pixd 8 bpp, or NULL on error
3621 */
3622 PIX *
pixConvert32To8(PIX * pixs,l_int32 type16,l_int32 type8)3623 pixConvert32To8(PIX *pixs,
3624 l_int32 type16,
3625 l_int32 type8)
3626 {
3627 PIX *pix1, *pixd;
3628
3629 PROCNAME("pixConvert32to8");
3630
3631 if (!pixs || pixGetDepth(pixs) != 32)
3632 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
3633 if (type16 != L_LS_TWO_BYTES && type16 != L_MS_TWO_BYTES &&
3634 type16 != L_CLIP_TO_FFFF)
3635 return (PIX *)ERROR_PTR("invalid type16", procName, NULL);
3636 if (type8 != L_LS_BYTE && type8 != L_MS_BYTE && type8 != L_CLIP_TO_FF)
3637 return (PIX *)ERROR_PTR("invalid type8", procName, NULL);
3638
3639 pix1 = pixConvert32To16(pixs, type16);
3640 pixd = pixConvert16To8(pix1, type8);
3641 pixDestroy(&pix1);
3642 return pixd;
3643 }
3644
3645
3646 /*---------------------------------------------------------------------------*
3647 * Removal of alpha component by blending with white background *
3648 *---------------------------------------------------------------------------*/
3649 /*!
3650 * \brief pixRemoveAlpha()
3651 *
3652 * \param[in] pixs any depth
3653 * \return pixd if 32 bpp rgba, pixs blended over a white background;
3654 * a clone of pixs otherwise, and NULL on error
3655 *
3656 * <pre>
3657 * Notes:
3658 * (1) This is a wrapper on pixAlphaBlendUniform()
3659 * </pre>
3660 */
3661 PIX *
pixRemoveAlpha(PIX * pixs)3662 pixRemoveAlpha(PIX *pixs)
3663 {
3664 PROCNAME("pixRemoveAlpha");
3665
3666 if (!pixs)
3667 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3668
3669 if (pixGetDepth(pixs) == 32 && pixGetSpp(pixs) == 4)
3670 return pixAlphaBlendUniform(pixs, 0xffffff00);
3671 else
3672 return pixClone(pixs);
3673 }
3674
3675
3676 /*---------------------------------------------------------------------------*
3677 * Addition of alpha component to 1 bpp *
3678 *---------------------------------------------------------------------------*/
3679 /*!
3680 * \brief pixAddAlphaTo1bpp()
3681 *
3682 * \param[in] pixd [optional] 1 bpp, can be null or equal to pixs
3683 * pixs 1 bpp
3684 * \return pixd 1 bpp with colormap and non-opaque alpha,
3685 * or NULL on error
3686 *
3687 * <pre>
3688 * Notes:
3689 * (1) We don't use 1 bpp colormapped images with alpha in leptonica,
3690 * but we support generating them (here), writing to png, and reading
3691 * the png. On reading, they are converted to 32 bpp RGBA.
3692 * (2) The background (0) pixels in pixs become fully transparent, and the
3693 * foreground (1) pixels are fully opaque. Thus, pixd is a 1 bpp
3694 * representation of a stencil, that can be used to paint over pixels
3695 * of a backing image that are masked by the foreground in pixs.
3696 * </pre>
3697 */
3698 PIX *
pixAddAlphaTo1bpp(PIX * pixd,PIX * pixs)3699 pixAddAlphaTo1bpp(PIX *pixd,
3700 PIX *pixs)
3701 {
3702 PIXCMAP *cmap;
3703
3704 PROCNAME("pixAddAlphaTo1bpp");
3705
3706 if (!pixs || (pixGetDepth(pixs) != 1))
3707 return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
3708 if (pixd && (pixd != pixs))
3709 return (PIX *)ERROR_PTR("pixd defined but != pixs", procName, NULL);
3710
3711 pixd = pixCopy(pixd, pixs);
3712 cmap = pixcmapCreate(1);
3713 pixSetColormap(pixd, cmap);
3714 pixcmapAddRGBA(cmap, 255, 255, 255, 0); /* 0 ==> white + transparent */
3715 pixcmapAddRGBA(cmap, 0, 0, 0, 255); /* 1 ==> black + opaque */
3716 return pixd;
3717 }
3718
3719
3720 /*---------------------------------------------------------------------------*
3721 * Lossless depth conversion (unpacking) *
3722 *---------------------------------------------------------------------------*/
3723 /*!
3724 * \brief pixConvertLossless()
3725 *
3726 * \param[in] pixs 1, 2, 4, 8 bpp, not cmapped
3727 * \param[in] d destination depth: 2, 4 or 8
3728 * \return pixd 2, 4 or 8 bpp, or NULL on error
3729 *
3730 * <pre>
3731 * Notes:
3732 * (1) This is a lossless unpacking (depth-increasing)
3733 * conversion. If ds is the depth of pixs, then
3734 * ~ if d < ds, returns NULL
3735 * ~ if d == ds, returns a copy
3736 * ~ if d > ds, does the unpacking conversion
3737 * (2) If pixs has a colormap, this is an error.
3738 * </pre>
3739 */
3740 PIX *
pixConvertLossless(PIX * pixs,l_int32 d)3741 pixConvertLossless(PIX *pixs,
3742 l_int32 d)
3743 {
3744 l_int32 w, h, ds, wpls, wpld, i, j, val;
3745 l_uint32 *datas, *datad, *lines, *lined;
3746 PIX *pixd;
3747
3748 PROCNAME("pixConvertLossless");
3749
3750 if (!pixs)
3751 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3752 if (pixGetColormap(pixs))
3753 return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
3754 if (d != 2 && d != 4 && d != 8)
3755 return (PIX *)ERROR_PTR("invalid dest depth", procName, NULL);
3756
3757 pixGetDimensions(pixs, &w, &h, &ds);
3758 if (d < ds)
3759 return (PIX *)ERROR_PTR("depth > d", procName, NULL);
3760 else if (d == ds)
3761 return pixCopy(NULL, pixs);
3762
3763 if ((pixd = pixCreate(w, h, d)) == NULL)
3764 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
3765 pixCopyResolution(pixd, pixs);
3766 pixCopyInputFormat(pixd, pixs);
3767
3768 /* Unpack the bits */
3769 datas = pixGetData(pixs);
3770 wpls = pixGetWpl(pixs);
3771 datad = pixGetData(pixd);
3772 wpld = pixGetWpl(pixd);
3773 for (i = 0; i < h; i++) {
3774 lines = datas + i * wpls;
3775 lined = datad + i * wpld;
3776 switch (ds)
3777 {
3778 case 1:
3779 for (j = 0; j < w; j++) {
3780 val = GET_DATA_BIT(lines, j);
3781 if (d == 8)
3782 SET_DATA_BYTE(lined, j, val);
3783 else if (d == 4)
3784 SET_DATA_QBIT(lined, j, val);
3785 else /* d == 2 */
3786 SET_DATA_DIBIT(lined, j, val);
3787 }
3788 break;
3789 case 2:
3790 for (j = 0; j < w; j++) {
3791 val = GET_DATA_DIBIT(lines, j);
3792 if (d == 8)
3793 SET_DATA_BYTE(lined, j, val);
3794 else /* d == 4 */
3795 SET_DATA_QBIT(lined, j, val);
3796 }
3797 break;
3798 case 4:
3799 for (j = 0; j < w; j++) {
3800 val = GET_DATA_DIBIT(lines, j);
3801 SET_DATA_BYTE(lined, j, val);
3802 }
3803 break;
3804 }
3805 }
3806
3807 return pixd;
3808 }
3809
3810
3811 /*---------------------------------------------------------------------------*
3812 * Conversion for printing in PostScript *
3813 *---------------------------------------------------------------------------*/
3814 /*!
3815 * \brief pixConvertForPSWrap()
3816 *
3817 * \param[in] pixs 1, 2, 4, 8, 16, 32 bpp
3818 * \return pixd 1, 8, or 32 bpp, or NULL on error
3819 *
3820 * <pre>
3821 * Notes:
3822 * (1) For wrapping in PostScript, we convert pixs to
3823 * 1 bpp, 8 bpp (gray) and 32 bpp (RGB color).
3824 * (2) Colormaps are removed. For pixs with colormaps, the
3825 * images are converted to either 8 bpp gray or 32 bpp
3826 * RGB, depending on whether the colormap has color content.
3827 * (3) Images without colormaps, that are not 1 bpp or 32 bpp,
3828 * are converted to 8 bpp gray.
3829 * </pre>
3830 */
3831 PIX *
pixConvertForPSWrap(PIX * pixs)3832 pixConvertForPSWrap(PIX *pixs)
3833 {
3834 l_int32 d;
3835 PIX *pixd;
3836 PIXCMAP *cmap;
3837
3838 PROCNAME("pixConvertForPSWrap");
3839
3840 if (!pixs)
3841 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3842
3843 cmap = pixGetColormap(pixs);
3844 d = pixGetDepth(pixs);
3845 switch (d)
3846 {
3847 case 1:
3848 case 32:
3849 pixd = pixClone(pixs);
3850 break;
3851 case 2:
3852 if (cmap)
3853 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
3854 else
3855 pixd = pixConvert2To8(pixs, 0, 0x55, 0xaa, 0xff, FALSE);
3856 break;
3857 case 4:
3858 if (cmap)
3859 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
3860 else
3861 pixd = pixConvert4To8(pixs, FALSE);
3862 break;
3863 case 8:
3864 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
3865 break;
3866 case 16:
3867 pixd = pixConvert16To8(pixs, L_MS_BYTE);
3868 break;
3869 default:
3870 fprintf(stderr, "depth not in {1, 2, 4, 8, 16, 32}");
3871 return NULL;
3872 }
3873
3874 return pixd;
3875 }
3876
3877
3878 /*---------------------------------------------------------------------------*
3879 * Scaling conversion to subpixel RGB *
3880 *---------------------------------------------------------------------------*/
3881 /*!
3882 * \brief pixConvertToSubpixelRGB()
3883 *
3884 * \param[in] pixs 8 bpp grayscale, 32 bpp rgb, or colormapped
3885 * \param[in] scalex, scaley anisotropic scaling permitted between
3886 * source and destination
3887 * \param[in] order of subpixel rgb color components in
3888 * composition of pixd:
3889 * L_SUBPIXEL_ORDER_RGB, L_SUBPIXEL_ORDER_BGR,
3890 * L_SUBPIXEL_ORDER_VRGB, L_SUBPIXEL_ORDER_VBGR
3891 * \return pixd 32 bpp, or NULL on error
3892 *
3893 * <pre>
3894 * Notes:
3895 * (1) If pixs has a colormap, it is removed based on its contents
3896 * to either 8 bpp gray or rgb.
3897 * (2) For horizontal subpixel splitting, the input image
3898 * is rescaled by %scaley vertically and by 3.0 times
3899 * %scalex horizontally. Then each horizontal triplet
3900 * of pixels is mapped back to a single rgb pixel, with the
3901 * r, g and b values being assigned based on the pixel triplet.
3902 * For gray triplets, the r, g, and b values are set equal to
3903 * the three gray values. For color triplets, the r, g and b
3904 * values are set equal to the components from the appropriate
3905 * subpixel. Vertical subpixel splitting is handled similarly.
3906 * (3) See pixConvertGrayToSubpixelRGB() and
3907 * pixConvertColorToSubpixelRGB() for further details.
3908 * </pre>
3909 */
3910 PIX *
pixConvertToSubpixelRGB(PIX * pixs,l_float32 scalex,l_float32 scaley,l_int32 order)3911 pixConvertToSubpixelRGB(PIX *pixs,
3912 l_float32 scalex,
3913 l_float32 scaley,
3914 l_int32 order)
3915 {
3916 l_int32 d;
3917 PIX *pix1, *pixd;
3918 PIXCMAP *cmap;
3919
3920 PROCNAME("pixConvertToSubpixelRGB");
3921
3922 if (!pixs)
3923 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3924 d = pixGetDepth(pixs);
3925 cmap = pixGetColormap(pixs);
3926 if (d != 8 && d != 32 && !cmap)
3927 return (PIX *)ERROR_PTR("pix not 8 or 32 bpp and not cmapped",
3928 procName, NULL);
3929 if (scalex <= 0.0 || scaley <= 0.0)
3930 return (PIX *)ERROR_PTR("scale factors must be > 0", procName, NULL);
3931 if (order != L_SUBPIXEL_ORDER_RGB && order != L_SUBPIXEL_ORDER_BGR &&
3932 order != L_SUBPIXEL_ORDER_VRGB && order != L_SUBPIXEL_ORDER_VBGR)
3933 return (PIX *)ERROR_PTR("invalid subpixel order", procName, NULL);
3934 if ((pix1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC)) == NULL)
3935 return (PIX *)ERROR_PTR("pix1 not made", procName, NULL);
3936
3937 d = pixGetDepth(pix1);
3938 pixd = NULL;
3939 if (d == 8)
3940 pixd = pixConvertGrayToSubpixelRGB(pix1, scalex, scaley, order);
3941 else if (d == 32)
3942 pixd = pixConvertColorToSubpixelRGB(pix1, scalex, scaley, order);
3943 else
3944 L_ERROR("invalid depth %d\n", procName, d);
3945
3946 pixDestroy(&pix1);
3947 return pixd;
3948 }
3949
3950
3951 /*!
3952 * \brief pixConvertGrayToSubpixelRGB()
3953 *
3954 * \param[in] pixs 8 bpp or colormapped
3955 * \param[in] scalex, scaley
3956 * \param[in] order of subpixel rgb color components in
3957 * composition of pixd:
3958 * L_SUBPIXEL_ORDER_RGB, L_SUBPIXEL_ORDER_BGR,
3959 * L_SUBPIXEL_ORDER_VRGB, L_SUBPIXEL_ORDER_VBGR
3960 * \return pixd 32 bpp, or NULL on error
3961 *
3962 * <pre>
3963 * Notes:
3964 * (1) If pixs has a colormap, it is removed to 8 bpp.
3965 * (2) For horizontal subpixel splitting, the input gray image
3966 * is rescaled by %scaley vertically and by 3.0 times
3967 * %scalex horizontally. Then each horizontal triplet
3968 * of pixels is mapped back to a single rgb pixel, with the
3969 * r, g and b values being assigned from the triplet of gray values.
3970 * Similar operations are used for vertical subpixel splitting.
3971 * (3) This is a form of subpixel rendering that tends to give the
3972 * resulting text a sharper and somewhat chromatic display.
3973 * For horizontal subpixel splitting, the observable difference
3974 * between %order=L_SUBPIXEL_ORDER_RGB and
3975 * %order=L_SUBPIXEL_ORDER_BGR is reduced by optical diffusers
3976 * in the display that make the pixel color appear to emerge
3977 * from the entire pixel.
3978 * </pre>
3979 */
3980 PIX *
pixConvertGrayToSubpixelRGB(PIX * pixs,l_float32 scalex,l_float32 scaley,l_int32 order)3981 pixConvertGrayToSubpixelRGB(PIX *pixs,
3982 l_float32 scalex,
3983 l_float32 scaley,
3984 l_int32 order)
3985 {
3986 l_int32 w, h, d, wd, hd, wplt, wpld, i, j, rval, gval, bval, direction;
3987 l_uint32 *datat, *datad, *linet, *lined;
3988 PIX *pix1, *pix2, *pixd;
3989 PIXCMAP *cmap;
3990
3991 PROCNAME("pixConvertGrayToSubpixelRGB");
3992
3993 if (!pixs)
3994 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3995 d = pixGetDepth(pixs);
3996 cmap = pixGetColormap(pixs);
3997 if (d != 8 && !cmap)
3998 return (PIX *)ERROR_PTR("pix not 8 bpp & not cmapped", procName, NULL);
3999 if (scalex <= 0.0 || scaley <= 0.0)
4000 return (PIX *)ERROR_PTR("scale factors must be > 0", procName, NULL);
4001 if (order != L_SUBPIXEL_ORDER_RGB && order != L_SUBPIXEL_ORDER_BGR &&
4002 order != L_SUBPIXEL_ORDER_VRGB && order != L_SUBPIXEL_ORDER_VBGR)
4003 return (PIX *)ERROR_PTR("invalid subpixel order", procName, NULL);
4004
4005 direction =
4006 (order == L_SUBPIXEL_ORDER_RGB || order == L_SUBPIXEL_ORDER_BGR)
4007 ? L_HORIZ : L_VERT;
4008 pix1 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
4009 if (direction == L_HORIZ)
4010 pix2 = pixScale(pix1, 3.0 * scalex, scaley);
4011 else /* L_VERT */
4012 pix2 = pixScale(pix1, scalex, 3.0 * scaley);
4013
4014 pixGetDimensions(pix2, &w, &h, NULL);
4015 wd = (direction == L_HORIZ) ? w / 3 : w;
4016 hd = (direction == L_VERT) ? h / 3 : h;
4017 pixd = pixCreate(wd, hd, 32);
4018 datad = pixGetData(pixd);
4019 wpld = pixGetWpl(pixd);
4020 datat = pixGetData(pix2);
4021 wplt = pixGetWpl(pix2);
4022 if (direction == L_HORIZ) {
4023 for (i = 0; i < hd; i++) {
4024 linet = datat + i * wplt;
4025 lined = datad + i * wpld;
4026 for (j = 0; j < wd; j++) {
4027 rval = GET_DATA_BYTE(linet, 3 * j);
4028 gval = GET_DATA_BYTE(linet, 3 * j + 1);
4029 bval = GET_DATA_BYTE(linet, 3 * j + 2);
4030 if (order == L_SUBPIXEL_ORDER_RGB)
4031 composeRGBPixel(rval, gval, bval, &lined[j]);
4032 else /* order BGR */
4033 composeRGBPixel(bval, gval, rval, &lined[j]);
4034 }
4035 }
4036 } else { /* L_VERT */
4037 for (i = 0; i < hd; i++) {
4038 linet = datat + 3 * i * wplt;
4039 lined = datad + i * wpld;
4040 for (j = 0; j < wd; j++) {
4041 rval = GET_DATA_BYTE(linet, j);
4042 gval = GET_DATA_BYTE(linet + wplt, j);
4043 bval = GET_DATA_BYTE(linet + 2 * wplt, j);
4044 if (order == L_SUBPIXEL_ORDER_VRGB)
4045 composeRGBPixel(rval, gval, bval, &lined[j]);
4046 else /* order VBGR */
4047 composeRGBPixel(bval, gval, rval, &lined[j]);
4048 }
4049 }
4050 }
4051
4052 pixDestroy(&pix1);
4053 pixDestroy(&pix2);
4054 return pixd;
4055 }
4056
4057
4058 /*!
4059 * \brief pixConvertColorToSubpixelRGB()
4060 *
4061 * \param[in] pixs 32 bpp or colormapped
4062 * \param[in] scalex, scaley
4063 * \param[in] order of subpixel rgb color components in
4064 * composition of pixd:
4065 * L_SUBPIXEL_ORDER_RGB, L_SUBPIXEL_ORDER_BGR,
4066 * L_SUBPIXEL_ORDER_VRGB, L_SUBPIXEL_ORDER_VBGR
4067 * \return pixd 32 bpp, or NULL on error
4068 *
4069 * <pre>
4070 * Notes:
4071 * (1) If pixs has a colormap, it is removed to 32 bpp rgb.
4072 * If the colormap has no color, pixConvertGrayToSubpixelRGB()
4073 * should be called instead, because it will give the same result
4074 * more efficiently. The function pixConvertToSubpixelRGB()
4075 * will do the best thing for all cases.
4076 * (2) For horizontal subpixel splitting, the input rgb image
4077 * is rescaled by %scaley vertically and by 3.0 times
4078 * %scalex horizontally. Then for each horizontal triplet
4079 * of pixels, the r component of the final pixel is selected
4080 * from the r component of the appropriate pixel in the triplet,
4081 * and likewise for g and b. Vertical subpixel splitting is
4082 * handled similarly.
4083 * </pre>
4084 */
4085 PIX *
pixConvertColorToSubpixelRGB(PIX * pixs,l_float32 scalex,l_float32 scaley,l_int32 order)4086 pixConvertColorToSubpixelRGB(PIX *pixs,
4087 l_float32 scalex,
4088 l_float32 scaley,
4089 l_int32 order)
4090 {
4091 l_int32 w, h, d, wd, hd, wplt, wpld, i, j, rval, gval, bval, direction;
4092 l_uint32 *datat, *datad, *linet, *lined;
4093 PIX *pix1, *pix2, *pixd;
4094 PIXCMAP *cmap;
4095
4096 PROCNAME("pixConvertColorToSubpixelRGB");
4097
4098 if (!pixs)
4099 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
4100 d = pixGetDepth(pixs);
4101 cmap = pixGetColormap(pixs);
4102 if (d != 32 && !cmap)
4103 return (PIX *)ERROR_PTR("pix not 32 bpp & not cmapped", procName, NULL);
4104 if (scalex <= 0.0 || scaley <= 0.0)
4105 return (PIX *)ERROR_PTR("scale factors must be > 0", procName, NULL);
4106 if (order != L_SUBPIXEL_ORDER_RGB && order != L_SUBPIXEL_ORDER_BGR &&
4107 order != L_SUBPIXEL_ORDER_VRGB && order != L_SUBPIXEL_ORDER_VBGR)
4108 return (PIX *)ERROR_PTR("invalid subpixel order", procName, NULL);
4109
4110 direction =
4111 (order == L_SUBPIXEL_ORDER_RGB || order == L_SUBPIXEL_ORDER_BGR)
4112 ? L_HORIZ : L_VERT;
4113 pix1 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
4114 if (direction == L_HORIZ)
4115 pix2 = pixScale(pix1, 3.0 * scalex, scaley);
4116 else /* L_VERT */
4117 pix2 = pixScale(pix1, scalex, 3.0 * scaley);
4118
4119 pixGetDimensions(pix2, &w, &h, NULL);
4120 wd = (direction == L_HORIZ) ? w / 3 : w;
4121 hd = (direction == L_VERT) ? h / 3 : h;
4122 pixd = pixCreate(wd, hd, 32);
4123 pixCopyInputFormat(pixd, pixs);
4124 datad = pixGetData(pixd);
4125 wpld = pixGetWpl(pixd);
4126 datat = pixGetData(pix2);
4127 wplt = pixGetWpl(pix2);
4128 if (direction == L_HORIZ) {
4129 for (i = 0; i < hd; i++) {
4130 linet = datat + i * wplt;
4131 lined = datad + i * wpld;
4132 for (j = 0; j < wd; j++) {
4133 if (order == L_SUBPIXEL_ORDER_RGB) {
4134 extractRGBValues(linet[3 * j], &rval, NULL, NULL);
4135 extractRGBValues(linet[3 * j + 1], NULL, &gval, NULL);
4136 extractRGBValues(linet[3 * j + 2], NULL, NULL, &bval);
4137 } else { /* order BGR */
4138 extractRGBValues(linet[3 * j], NULL, NULL, &bval);
4139 extractRGBValues(linet[3 * j + 1], NULL, &gval, NULL);
4140 extractRGBValues(linet[3 * j + 2], &rval, NULL, NULL);
4141 }
4142 composeRGBPixel(rval, gval, bval, &lined[j]);
4143 }
4144 }
4145 } else { /* L_VERT */
4146 for (i = 0; i < hd; i++) {
4147 linet = datat + 3 * i * wplt;
4148 lined = datad + i * wpld;
4149 for (j = 0; j < wd; j++) {
4150 if (order == L_SUBPIXEL_ORDER_VRGB) {
4151 extractRGBValues(linet[j], &rval, NULL, NULL);
4152 extractRGBValues((linet + wplt)[j], NULL, &gval, NULL);
4153 extractRGBValues((linet + 2 * wplt)[j], NULL, NULL, &bval);
4154 } else { /* order VBGR */
4155 extractRGBValues(linet[j], NULL, NULL, &bval);
4156 extractRGBValues((linet + wplt)[j], NULL, &gval, NULL);
4157 extractRGBValues((linet + 2 * wplt)[j], &rval, NULL, NULL);
4158 }
4159 composeRGBPixel(rval, gval, bval, &lined[j]);
4160 }
4161 }
4162 }
4163
4164 if (pixGetSpp(pixs) == 4)
4165 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
4166
4167 pixDestroy(&pix1);
4168 pixDestroy(&pix2);
4169 return pixd;
4170 }
4171
4172
4173 /*---------------------------------------------------------------------*
4174 * Setting neutral point for min/max boost conversion to gray *
4175 *---------------------------------------------------------------------*/
4176 /*!
4177 * \brief l_setNeutralBoostVal()
4178 *
4179 * \param[in] val between 1 and 255; typical value is 180
4180 * \return void
4181 *
4182 * <pre>
4183 * Notes:
4184 * (1) This raises or lowers the selected min or max RGB component value,
4185 * depending on if that component is above or below this value.
4186 * </pre>
4187 */
4188 void
l_setNeutralBoostVal(l_int32 val)4189 l_setNeutralBoostVal(l_int32 val)
4190 {
4191 PROCNAME("l_setNeutralBoostVal");
4192
4193 if (val <= 0) {
4194 L_ERROR("invalid reference value for neutral boost\n", procName);
4195 return;
4196 }
4197 var_NEUTRAL_BOOST_VAL = val;
4198 }
4199