comparison mupdf-source/thirdparty/leptonica/src/pixconv.c @ 2:b50eed0cc0ef upstream

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