1 /*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 - This software is distributed in the hope that it will be
4 - useful, but with NO WARRANTY OF ANY KIND.
5 - No author or distributor accepts responsibility to anyone for the
6 - consequences of using this software, or for whether it serves any
7 - particular purpose or works at all, unless he or she says so in
8 - writing. Everyone is granted permission to copy, modify and
9 - redistribute this source code, for commercial or non-commercial
10 - purposes, with the following restrictions: (1) the origin of this
11 - source code must not be misrepresented; (2) modified versions must
12 - be plainly marked as such; and (3) this notice may not be removed
13 - or altered from any source or modified source distribution.
14 *====================================================================*/
15
16 /*
17 * pixconv.c
18 *
19 * These functions convert between images of different types
20 * without scaling.
21 *
22 * Conversion from 8 bpp grayscale to 1, 2, 4 and 8 bpp
23 * PIX *pixThreshold8()
24 *
25 * Conversion from colormap to full color or grayscale
26 * PIX *pixRemoveColormap()
27 *
28 * Add colormap losslessly (8 to 8)
29 * l_int32 pixAddGrayColormap8()
30 * PIX *pixAddMinimalGrayColormap8()
31 *
32 * Conversion from RGB color to grayscale
33 * PIX *pixConvertRGBToLuminance()
34 * PIX *pixConvertRGBToGray()
35 * PIX *pixConvertRGBToGrayFast()
36 * PIX *pixConvertRGBToGrayMinMax()
37 *
38 * Conversion from grayscale to colormap
39 * PIX *pixConvertGrayToColormap() -- 2, 4, 8 bpp
40 * PIX *pixConvertGrayToColormap8() -- 8 bpp only
41 *
42 * Colorizing conversion from grayscale to color
43 * PIX *pixColorizeGray() -- 8 bpp or cmapped
44 *
45 * Conversion from RGB color to colormap
46 * PIX *pixConvertRGBToColormap()
47 *
48 * Quantization for relatively small number of colors in source
49 * l_int32 pixQuantizeIfFewColors()
50 *
51 * Conversion from 16 bpp to 8 bpp
52 * PIX *pixConvert16To8()
53 *
54 * Conversion from grayscale to false color
55 * PIX *pixConvertGrayToFalseColor()
56 *
57 * Unpacking conversion from 1 bpp to 2, 4, 8, 16 and 32 bpp
58 * PIX *pixUnpackBinary()
59 * PIX *pixConvert1To16()
60 * PIX *pixConvert1To32()
61 *
62 * Unpacking conversion from 1 bpp to 2 bpp
63 * PIX *pixConvert1To2Cmap()
64 * PIX *pixConvert1To2()
65 *
66 * Unpacking conversion from 1 bpp to 4 bpp
67 * PIX *pixConvert1To4Cmap()
68 * PIX *pixConvert1To4()
69 *
70 * Unpacking conversion from 1, 2 and 4 bpp to 8 bpp
71 * PIX *pixConvert1To8()
72 * PIX *pixConvert2To8()
73 * PIX *pixConvert4To8()
74 *
75 * Unpacking conversion from 8 bpp to 16 bpp
76 * PIX *pixConvert8To16()
77 *
78 * Top-level conversion to 1 bpp
79 * PIX *pixConvertTo1()
80 * PIX *pixConvertTo1BySampling()
81 *
82 * Top-level conversion to 8 bpp
83 * PIX *pixConvertTo8()
84 * PIX *pixConvertTo8BySampling()
85 *
86 * Top-level conversion to 16 bpp
87 * PIX *pixConvertTo16()
88 *
89 * Top-level conversion to 32 bpp (RGB)
90 * PIX *pixConvertTo32() ***
91 * PIX *pixConvertTo32BySampling() ***
92 * PIX *pixConvert8To32() ***
93 *
94 * Top-level conversion to 8 or 32 bpp, without colormap
95 * PIX *pixConvertTo8Or32
96 *
97 * Lossless depth conversion (unpacking)
98 * PIX *pixConvertLossless()
99 *
100 * Conversion for printing in PostScript
101 * PIX *pixConvertForPSWrap()
102 *
103 * Colorspace conversion between RGB and HSV
104 * PIX *pixConvertRGBToHSV()
105 * PIX *pixConvertHSVToRGB()
106 * l_int32 convertRGBToHSV()
107 * l_int32 convertHSVToRGB()
108 * PIX *pixConvertRGBToHue()
109 * PIX *pixConvertRGBToSaturation()
110 * PIX *pixConvertRGBToValue()
111 *
112 *
113 * *** indicates implicit assumption about RGB component ordering
114 */
115
116 #include <stdio.h>
117 #include <stdlib.h>
118 #include <string.h>
119 #include <math.h>
120 #include "allheaders.h"
121
122 /* These numbers are ad-hoc, but at least they add up
123 to 1. Unlike, for example, the weighting factor for
124 conversion of RGB to luminance, or more specifically
125 to Y in the YUV colorspace. Those numbers come
126 from the International Telecommunications Union, via ITU-R
127 (and formerly ITU CCIR 601). */
128 static const l_float32 L_RED_WEIGHT = 0.3;
129 static const l_float32 L_GREEN_WEIGHT = 0.5;
130 static const l_float32 L_BLUE_WEIGHT = 0.2;
131
132
133 #ifndef NO_CONSOLE_IO
134 #define DEBUG_CONVERT_TO_COLORMAP 0
135 #define DEBUG_UNROLLING 0
136 #endif /* ~NO_CONSOLE_IO */
137
138
139 /*-------------------------------------------------------------*
140 * Conversion from 8 bpp grayscale to 1, 2 4 and 8 bpp *
141 *-------------------------------------------------------------*/
142 /*!
143 * pixThreshold8()
144 *
145 * Input: pix (8 bpp grayscale)
146 * d (destination depth: 1, 2, 4 or 8)
147 * nlevels (number of levels to be used for colormap)
148 * cmapflag (1 if makes colormap; 0 otherwise)
149 * Return: pixd (thresholded with standard dest thresholds),
150 * or null on error
151 *
152 * Notes:
153 * (1) This uses, by default, equally spaced "target" values
154 * that depend on the number of levels, with thresholds
155 * halfway between. For N levels, with separation (N-1)/255,
156 * there are N-1 fixed thresholds.
157 * (2) For 1 bpp destination, the number of levels can only be 2
158 * and if a cmap is made, black is (0,0,0) and white
159 * is (255,255,255), which is opposite to the convention
160 * without a colormap.
161 * (3) For 1, 2 and 4 bpp, the nlevels arg is used if a colormap
162 * is made; otherwise, we take the most significant bits
163 * from the src that will fit in the dest.
164 * (4) For 8 bpp, the input pixs is quantized to nlevels. The
165 * dest quantized with that mapping, either through a colormap
166 * table or directly with 8 bit values.
167 * (5) Typically you should not use make a colormap for 1 bpp dest.
168 * (6) This is not dithering. Each pixel is treated independently.
169 */
170 PIX *
pixThreshold8(PIX * pixs,l_int32 d,l_int32 nlevels,l_int32 cmapflag)171 pixThreshold8(PIX *pixs,
172 l_int32 d,
173 l_int32 nlevels,
174 l_int32 cmapflag)
175 {
176 PIX *pixd;
177 PIXCMAP *cmap;
178
179 PROCNAME("pixThreshold8");
180
181 if (!pixs)
182 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
183 if (pixGetDepth(pixs) != 8)
184 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
185 if (cmapflag && nlevels < 2)
186 return (PIX *)ERROR_PTR("nlevels must be at least 2", procName, NULL);
187
188 switch (d) {
189 case 1:
190 pixd = pixThresholdToBinary(pixs, 128);
191 if (cmapflag) {
192 cmap = pixcmapCreateLinear(1, 2);
193 pixSetColormap(pixd, cmap);
194 }
195 break;
196 case 2:
197 pixd = pixThresholdTo2bpp(pixs, nlevels, cmapflag);
198 break;
199 case 4:
200 pixd = pixThresholdTo4bpp(pixs, nlevels, cmapflag);
201 break;
202 case 8:
203 pixd = pixThresholdOn8bpp(pixs, nlevels, cmapflag);
204 break;
205 default:
206 return (PIX *)ERROR_PTR("d must be in {1,2,4,8}", procName, NULL);
207 }
208
209 if (!pixd)
210 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
211 return pixd;
212 }
213
214
215 /*-------------------------------------------------------------*
216 * Conversion from colormapped pix *
217 *-------------------------------------------------------------*/
218 /*!
219 * pixRemoveColormap()
220 *
221 * Input: pixs (see restrictions below)
222 * type (REMOVE_CMAP_TO_BINARY,
223 * REMOVE_CMAP_TO_GRAYSCALE,
224 * REMOVE_CMAP_TO_FULL_COLOR,
225 * REMOVE_CMAP_BASED_ON_SRC)
226 * Return: new pix, or null on error
227 *
228 * Notes:
229 * (1) If there is no colormap, a clone is returned.
230 * (2) Otherwise, the input pixs is restricted to 1, 2, 4 or 8 bpp.
231 * (3) Use REMOVE_CMAP_TO_BINARY only on 1 bpp pix.
232 * (4) For grayscale conversion from RGB, use a weighted average
233 * of RGB values, and always return an 8 bpp pix, regardless
234 * of whether the input pixs depth is 2, 4 or 8 bpp.
235 */
236 PIX *
pixRemoveColormap(PIX * pixs,l_int32 type)237 pixRemoveColormap(PIX *pixs,
238 l_int32 type)
239 {
240 l_int32 sval, rval, gval, bval;
241 l_int32 i, j, k, w, h, d, wpls, wpld, ncolors, count;
242 l_int32 colorfound;
243 l_int32 *rmap, *gmap, *bmap, *graymap;
244 l_uint32 *datas, *lines, *datad, *lined, *lut;
245 l_uint32 sword, dword;
246 PIXCMAP *cmap;
247 PIX *pixd;
248
249 PROCNAME("pixRemoveColormap");
250
251 if (!pixs)
252 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
253 if ((cmap = pixGetColormap(pixs)) == NULL)
254 return pixClone(pixs);
255
256 if (type != REMOVE_CMAP_TO_BINARY &&
257 type != REMOVE_CMAP_TO_GRAYSCALE &&
258 type != REMOVE_CMAP_TO_FULL_COLOR &&
259 type != REMOVE_CMAP_BASED_ON_SRC) {
260 L_WARNING("Invalid type; converting based on src", procName);
261 type = REMOVE_CMAP_BASED_ON_SRC;
262 }
263
264 pixGetDimensions(pixs, &w, &h, &d);
265 if (d != 1 && d != 2 && d != 4 && d != 8)
266 return (PIX *)ERROR_PTR("pixs must be {1,2,4,8} bpp", procName, NULL);
267
268 if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap))
269 return (PIX *)ERROR_PTR("colormap arrays not made", procName, NULL);
270
271 if (d != 1 && type == REMOVE_CMAP_TO_BINARY) {
272 L_WARNING("not 1 bpp; can't remove cmap to binary", procName);
273 type = REMOVE_CMAP_BASED_ON_SRC;
274 }
275
276 if (type == REMOVE_CMAP_BASED_ON_SRC) {
277 /* select output type depending on colormap */
278 pixcmapHasColor(cmap, &colorfound);
279 if (!colorfound) {
280 if (d == 1)
281 type = REMOVE_CMAP_TO_BINARY;
282 else
283 type = REMOVE_CMAP_TO_GRAYSCALE;
284 }
285 else
286 type = REMOVE_CMAP_TO_FULL_COLOR;
287 }
288
289 ncolors = pixcmapGetCount(cmap);
290 datas = pixGetData(pixs);
291 wpls = pixGetWpl(pixs);
292 if (type == REMOVE_CMAP_TO_BINARY) {
293 if ((pixd = pixCopy(NULL, pixs)) == NULL)
294 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
295 pixcmapGetColor(cmap, 0, &rval, &gval, &bval);
296 if (rval == 0) /* photometrically inverted from standard */
297 pixInvert(pixd, pixd);
298 pixDestroyColormap(pixd);
299 }
300 else if (type == REMOVE_CMAP_TO_GRAYSCALE) {
301 if ((pixd = pixCreate(w, h, 8)) == NULL)
302 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
303 pixCopyResolution(pixd, pixs);
304 datad = pixGetData(pixd);
305 wpld = pixGetWpl(pixd);
306 if ((graymap = (l_int32 *)CALLOC(ncolors, sizeof(l_int32))) == NULL)
307 return (PIX *)ERROR_PTR("calloc fail for graymap", procName, NULL);
308 for (i = 0; i < pixcmapGetCount(cmap); i++) {
309 graymap[i] = (rmap[i] + 2 * gmap[i] + bmap[i]) / 4;
310 }
311 for (i = 0; i < h; i++) {
312 lines = datas + i * wpls;
313 lined = datad + i * wpld;
314 switch (d) /* depth test above; no default permitted */
315 {
316 case 8:
317 /* Unrolled 4x */
318 for (j = 0, count = 0; j + 3 < w; j += 4, count++) {
319 sword = lines[count];
320 dword = (graymap[(sword >> 24) & 0xff] << 24) |
321 (graymap[(sword >> 16) & 0xff] << 16) |
322 (graymap[(sword >> 8) & 0xff] << 8) |
323 graymap[sword & 0xff];
324 lined[count] = dword;
325 }
326 /* Cleanup partial word */
327 for (; j < w; j++) {
328 sval = GET_DATA_BYTE(lines, j);
329 gval = graymap[sval];
330 SET_DATA_BYTE(lined, j, gval);
331 }
332 #if DEBUG_UNROLLING
333 #define CHECK_VALUE(a, b, c) if (GET_DATA_BYTE(a, b) != c) { \
334 fprintf(stderr, "Error: mismatch at %d, %d vs %d\n", \
335 j, GET_DATA_BYTE(a, b), c); }
336 for (j = 0; j < w; j++) {
337 sval = GET_DATA_BYTE(lines, j);
338 gval = graymap[sval];
339 CHECK_VALUE(lined, j, gval);
340 }
341 #endif
342 break;
343 case 4:
344 /* Unrolled 8x */
345 for (j = 0, count = 0; j + 7 < w; j += 8, count++) {
346 sword = lines[count];
347 dword = (graymap[(sword >> 28) & 0xf] << 24) |
348 (graymap[(sword >> 24) & 0xf] << 16) |
349 (graymap[(sword >> 20) & 0xf] << 8) |
350 graymap[(sword >> 16) & 0xf];
351 lined[2 * count] = dword;
352 dword = (graymap[(sword >> 12) & 0xf] << 24) |
353 (graymap[(sword >> 8) & 0xf] << 16) |
354 (graymap[(sword >> 4) & 0xf] << 8) |
355 graymap[sword & 0xf];
356 lined[2 * count + 1] = dword;
357 }
358 /* Cleanup partial word */
359 for (; j < w; j++) {
360 sval = GET_DATA_QBIT(lines, j);
361 gval = graymap[sval];
362 SET_DATA_BYTE(lined, j, gval);
363 }
364 #if DEBUG_UNROLLING
365 for (j = 0; j < w; j++) {
366 sval = GET_DATA_QBIT(lines, j);
367 gval = graymap[sval];
368 CHECK_VALUE(lined, j, gval);
369 }
370 #endif
371 break;
372 case 2:
373 /* Unrolled 16x */
374 for (j = 0, count = 0; j + 15 < w; j += 16, count++) {
375 sword = lines[count];
376 dword = (graymap[(sword >> 30) & 0x3] << 24) |
377 (graymap[(sword >> 28) & 0x3] << 16) |
378 (graymap[(sword >> 26) & 0x3] << 8) |
379 graymap[(sword >> 24) & 0x3];
380 lined[4 * count] = dword;
381 dword = (graymap[(sword >> 22) & 0x3] << 24) |
382 (graymap[(sword >> 20) & 0x3] << 16) |
383 (graymap[(sword >> 18) & 0x3] << 8) |
384 graymap[(sword >> 16) & 0x3];
385 lined[4 * count + 1] = dword;
386 dword = (graymap[(sword >> 14) & 0x3] << 24) |
387 (graymap[(sword >> 12) & 0x3] << 16) |
388 (graymap[(sword >> 10) & 0x3] << 8) |
389 graymap[(sword >> 8) & 0x3];
390 lined[4 * count + 2] = dword;
391 dword = (graymap[(sword >> 6) & 0x3] << 24) |
392 (graymap[(sword >> 4) & 0x3] << 16) |
393 (graymap[(sword >> 2) & 0x3] << 8) |
394 graymap[sword & 0x3];
395 lined[4 * count + 3] = dword;
396 }
397 /* Cleanup partial word */
398 for (; j < w; j++) {
399 sval = GET_DATA_DIBIT(lines, j);
400 gval = graymap[sval];
401 SET_DATA_BYTE(lined, j, gval);
402 }
403 #if DEBUG_UNROLLING
404 for (j = 0; j < w; j++) {
405 sval = GET_DATA_DIBIT(lines, j);
406 gval = graymap[sval];
407 CHECK_VALUE(lined, j, gval);
408 }
409 #endif
410 break;
411 case 1:
412 /* Unrolled 8x */
413 for (j = 0, count = 0; j + 31 < w; j += 32, count++) {
414 sword = lines[count];
415 for (k = 0; k < 4; k++) {
416 /* The top byte is always the relevant one */
417 dword = (graymap[(sword >> 31) & 0x1] << 24) |
418 (graymap[(sword >> 30) & 0x1] << 16) |
419 (graymap[(sword >> 29) & 0x1] << 8) |
420 graymap[(sword >> 28) & 0x1];
421 lined[8 * count + 2 * k] = dword;
422 dword = (graymap[(sword >> 27) & 0x1] << 24) |
423 (graymap[(sword >> 26) & 0x1] << 16) |
424 (graymap[(sword >> 25) & 0x1] << 8) |
425 graymap[(sword >> 24) & 0x1];
426 lined[8 * count + 2 * k + 1] = dword;
427 sword <<= 8; /* Move up the next byte */
428 }
429 }
430 /* Cleanup partial word */
431 for (; j < w; j++) {
432 sval = GET_DATA_BIT(lines, j);
433 gval = graymap[sval];
434 SET_DATA_BYTE(lined, j, gval);
435 }
436 #if DEBUG_UNROLLING
437 for (j = 0; j < w; j++) {
438 sval = GET_DATA_BIT(lines, j);
439 gval = graymap[sval];
440 CHECK_VALUE(lined, j, gval);
441 }
442 #undef CHECK_VALUE
443 #endif
444 break;
445 default:
446 return NULL;
447 }
448 }
449 if (graymap)
450 FREE(graymap);
451 }
452 else { /* type == REMOVE_CMAP_TO_FULL_COLOR */
453 if ((pixd = pixCreate(w, h, 32)) == NULL)
454 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
455 pixCopyResolution(pixd, pixs);
456 datad = pixGetData(pixd);
457 wpld = pixGetWpl(pixd);
458 if ((lut = (l_uint32 *)CALLOC(ncolors, sizeof(l_uint32))) == NULL)
459 return (PIX *)ERROR_PTR("calloc fail for lut", procName, NULL);
460 for (i = 0; i < ncolors; i++)
461 composeRGBPixel(rmap[i], gmap[i], bmap[i], lut + i);
462
463 for (i = 0; i < h; i++) {
464 lines = datas + i * wpls;
465 lined = datad + i * wpld;
466 for (j = 0; j < w; j++) {
467 if (d == 8)
468 sval = GET_DATA_BYTE(lines, j);
469 else if (d == 4)
470 sval = GET_DATA_QBIT(lines, j);
471 else if (d == 2)
472 sval = GET_DATA_DIBIT(lines, j);
473 else if (d == 1)
474 sval = GET_DATA_BIT(lines, j);
475 else
476 return NULL;
477 if (sval >= ncolors)
478 L_WARNING("pixel value out of bounds", procName);
479 else
480 lined[j] = lut[sval];
481 }
482 }
483 FREE(lut);
484 }
485
486 FREE(rmap);
487 FREE(gmap);
488 FREE(bmap);
489 return pixd;
490 }
491
492
493 /*-------------------------------------------------------------*
494 * Add colormap losslessly (8 to 8) *
495 *-------------------------------------------------------------*/
496 /*!
497 * pixAddGrayColormap8()
498 *
499 * Input: pixs (8 bpp)
500 * Return: 0 if OK, 1 on error
501 *
502 * Notes:
503 * (1) If pixs has a colormap, this is a no-op.
504 */
505 l_int32
pixAddGrayColormap8(PIX * pixs)506 pixAddGrayColormap8(PIX *pixs)
507 {
508 PIXCMAP *cmap;
509
510 PROCNAME("pixAddGrayColormap8");
511
512 if (!pixs || pixGetDepth(pixs) != 8)
513 return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
514 if (pixGetColormap(pixs))
515 return 0;
516
517 cmap = pixcmapCreateLinear(8, 256);
518 pixSetColormap(pixs, cmap);
519 return 0;
520 }
521
522
523 /*!
524 * pixAddMinimalGrayColormap8()
525 *
526 * Input: pixs (8 bpp)
527 * Return: 0 if OK, 1 on error
528 *
529 * Notes:
530 * (1) This generates a colormapped version of the input image
531 * that has the same number of colormap entries as the
532 * input image has unique gray levels.
533 */
534 PIX *
pixAddMinimalGrayColormap8(PIX * pixs)535 pixAddMinimalGrayColormap8(PIX *pixs)
536 {
537 l_int32 ncolors, w, h, i, j, wplt, wpld, index, val;
538 l_int32 *inta, *revmap;
539 l_uint32 *datat, *datad, *linet, *lined;
540 PIX *pixt, *pixd;
541 PIXCMAP *cmap;
542
543 PROCNAME("pixAddMinimalGrayColormap8");
544
545 if (!pixs || pixGetDepth(pixs) != 8)
546 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
547
548 /* Eliminate the easy cases */
549 pixNumColors(pixs, 1, &ncolors);
550 cmap = pixGetColormap(pixs);
551 if (cmap) {
552 if (pixcmapGetCount(cmap) == ncolors) /* irreducible */
553 return pixCopy(NULL, pixs);
554 else
555 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
556 }
557 else {
558 if (ncolors == 256) {
559 pixt = pixCopy(NULL, pixs);
560 pixAddGrayColormap8(pixt);
561 return pixt;
562 }
563 pixt = pixClone(pixs);
564 }
565
566 /* Find the gray levels and make a reverse map */
567 pixGetDimensions(pixt, &w, &h, NULL);
568 datat = pixGetData(pixt);
569 wplt = pixGetWpl(pixt);
570 inta = (l_int32 *)CALLOC(256, sizeof(l_int32));
571 for (i = 0; i < h; i++) {
572 linet = datat + i * wplt;
573 for (j = 0; j < w; j++) {
574 val = GET_DATA_BYTE(linet, j);
575 inta[val] = 1;
576 }
577 }
578 cmap = pixcmapCreate(8);
579 revmap = (l_int32 *)CALLOC(256, sizeof(l_int32));
580 for (i = 0, index = 0; i < 256; i++) {
581 if (inta[i]) {
582 pixcmapAddColor(cmap, i, i, i);
583 revmap[i] = index++;
584 }
585 }
586
587 /* Set all pixels in pixd to the colormap index */
588 pixd = pixCreateTemplate(pixt);
589 pixSetColormap(pixd, cmap);
590 pixCopyResolution(pixd, pixs);
591 datad = pixGetData(pixd);
592 wpld = pixGetWpl(pixd);
593 for (i = 0; i < h; i++) {
594 linet = datat + i * wplt;
595 lined = datad + i * wpld;
596 for (j = 0; j < w; j++) {
597 val = GET_DATA_BYTE(linet, j);
598 SET_DATA_BYTE(lined, j, revmap[val]);
599 }
600 }
601
602 pixDestroy(&pixt);
603 FREE(inta);
604 FREE(revmap);
605 return pixd;
606 }
607
608
609 /*-------------------------------------------------------------*
610 * Conversion from RGB color to grayscale *
611 *-------------------------------------------------------------*/
612 /*!
613 * pixConvertRGBToLuminance()
614 *
615 * Input: pix (32 bpp RGB)
616 * Return: 8 bpp pix, or null on error
617 *
618 * Notes:
619 * (1) Use a standard luminance conversion.
620 */
621 PIX *
pixConvertRGBToLuminance(PIX * pixs)622 pixConvertRGBToLuminance(PIX *pixs)
623 {
624 return pixConvertRGBToGray(pixs, 0.0, 0.0, 0.0);
625 }
626
627
628 /*!
629 * pixConvertRGBToGray()
630 *
631 * Input: pix (32 bpp RGB)
632 * rwt, gwt, bwt (non-negative; these should add to 1.0,
633 * or use 0.0 for default)
634 * Return: 8 bpp pix, or null on error
635 *
636 * Notes:
637 * (1) Use a weighted average of the RGB values.
638 */
639 PIX *
pixConvertRGBToGray(PIX * pixs,l_float32 rwt,l_float32 gwt,l_float32 bwt)640 pixConvertRGBToGray(PIX *pixs,
641 l_float32 rwt,
642 l_float32 gwt,
643 l_float32 bwt)
644 {
645 l_int32 i, j, w, h, wpls, wpld, rval, gval, bval, val;
646 l_uint32 *datas, *lines, *datad, *lined;
647 l_float32 sum;
648 PIX *pixd;
649
650 PROCNAME("pixConvertRGBToGray");
651
652 if (!pixs)
653 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
654 if (pixGetDepth(pixs) != 32)
655 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
656 if (rwt < 0.0 || gwt < 0.0 || bwt < 0.0)
657 return (PIX *)ERROR_PTR("weights not all >= 0.0", procName, NULL);
658
659 /* Make sure the sum of weights is 1.0; otherwise, you can get
660 * overflow in the gray value. */
661 if (rwt == 0.0 && gwt == 0.0 && bwt == 0.0) {
662 rwt = L_RED_WEIGHT;
663 gwt = L_GREEN_WEIGHT;
664 bwt = L_BLUE_WEIGHT;
665 }
666 sum = rwt + gwt + bwt;
667 if (L_ABS(sum - 1.0) > 0.0001) { /* maintain ratios with sum == 1.0 */
668 L_WARNING("weights don't sum to 1; maintaining ratios", procName);
669 rwt = rwt / sum;
670 gwt = gwt / sum;
671 bwt = bwt / sum;
672 }
673
674 pixGetDimensions(pixs, &w, &h, NULL);
675 datas = pixGetData(pixs);
676 wpls = pixGetWpl(pixs);
677 if ((pixd = pixCreate(w, h, 8)) == NULL)
678 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
679 pixCopyResolution(pixd, pixs);
680 datad = pixGetData(pixd);
681 wpld = pixGetWpl(pixd);
682
683 for (i = 0; i < h; i++) {
684 lines = datas + i * wpls;
685 lined = datad + i * wpld;
686 for (j = 0; j < w; j++) {
687 extractRGBValues(lines[j], &rval, &gval, &bval);
688 val = (l_int32)(rwt * rval + gwt * gval + bwt * bval + 0.5);
689 SET_DATA_BYTE(lined, j, val);
690 }
691 }
692
693 return pixd;
694 }
695
696
697 /*!
698 * pixConvertRGBToGrayFast()
699 *
700 * Input: pix (32 bpp RGB)
701 * Return: 8 bpp pix, or null on error
702 *
703 * Notes:
704 * (1) This function should be used if speed of conversion
705 * is paramount, and the green channel can be used as
706 * a fair representative of the RGB intensity. It is
707 * several times faster than pixConvertRGBToGray().
708 * (2) To combine RGB to gray conversion with subsampling,
709 * use pixScaleRGBToGrayFast() instead.
710 */
711 PIX *
pixConvertRGBToGrayFast(PIX * pixs)712 pixConvertRGBToGrayFast(PIX *pixs)
713 {
714 l_int32 i, j, w, h, wpls, wpld, val;
715 l_uint32 *datas, *lines, *datad, *lined;
716 PIX *pixd;
717
718 PROCNAME("pixConvertRGBToGrayFast");
719
720 if (!pixs)
721 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
722 if (pixGetDepth(pixs) != 32)
723 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
724
725 pixGetDimensions(pixs, &w, &h, NULL);
726 datas = pixGetData(pixs);
727 wpls = pixGetWpl(pixs);
728 if ((pixd = pixCreate(w, h, 8)) == NULL)
729 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
730 pixCopyResolution(pixd, pixs);
731 datad = pixGetData(pixd);
732 wpld = pixGetWpl(pixd);
733
734 for (i = 0; i < h; i++) {
735 lines = datas + i * wpls;
736 lined = datad + i * wpld;
737 for (j = 0; j < w; j++, lines++) {
738 val = ((*lines) >> L_GREEN_SHIFT) & 0xff;
739 SET_DATA_BYTE(lined, j, val);
740 }
741 }
742
743 return pixd;
744 }
745
746
747 /*!
748 * pixConvertRGBToGrayMinMax()
749 *
750 * Input: pix (32 bpp RGB)
751 * type (L_CHOOSE_MIN or L_CHOOSE_MAX)
752 * Return: 8 bpp pix, or null on error
753 *
754 * Notes:
755 * (1) @type chooses among the 3 color components for each pixel
756 * (2) This is useful when looking for the maximum deviation
757 * of a component from either 0 or 255. For finding the
758 * deviation of a single component, it is more sensitive
759 * than using a weighted average.
760 */
761 PIX *
pixConvertRGBToGrayMinMax(PIX * pixs,l_int32 type)762 pixConvertRGBToGrayMinMax(PIX *pixs,
763 l_int32 type)
764 {
765 l_int32 i, j, w, h, wpls, wpld, rval, gval, bval, val;
766 l_uint32 *datas, *lines, *datad, *lined;
767 PIX *pixd;
768
769 PROCNAME("pixConvertRGBToGrayMinMax");
770
771 if (!pixs)
772 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
773 if (pixGetDepth(pixs) != 32)
774 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
775 if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX)
776 return (PIX *)ERROR_PTR("invalid type", procName, NULL);
777
778 pixGetDimensions(pixs, &w, &h, NULL);
779 datas = pixGetData(pixs);
780 wpls = pixGetWpl(pixs);
781 if ((pixd = pixCreate(w, h, 8)) == NULL)
782 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
783 pixCopyResolution(pixd, pixs);
784 datad = pixGetData(pixd);
785 wpld = pixGetWpl(pixd);
786
787 for (i = 0; i < h; i++) {
788 lines = datas + i * wpls;
789 lined = datad + i * wpld;
790 for (j = 0; j < w; j++) {
791 extractRGBValues(lines[j], &rval, &gval, &bval);
792 if (type == L_CHOOSE_MIN) {
793 val = L_MIN(rval, gval);
794 val = L_MIN(val, bval);
795 }
796 else { /* type == L_CHOOSE_MAX */
797 val = L_MAX(rval, gval);
798 val = L_MAX(val, bval);
799 }
800 SET_DATA_BYTE(lined, j, val);
801 }
802 }
803
804 return pixd;
805 }
806
807
808
809 /*---------------------------------------------------------------------------*
810 * Conversion from grayscale to colormap *
811 *---------------------------------------------------------------------------*/
812 /*!
813 * pixConvertGrayToColormap()
814 *
815 * Input: pixs (2, 4 or 8 bpp grayscale)
816 * Return: pixd (2, 4 or 8 bpp with colormap), or null on error
817 *
818 * Notes:
819 * (1) This is a simple interface for adding a colormap to a
820 * 2, 4 or 8 bpp grayscale image without causing any
821 * quantization. There is some similarity to operations
822 * in grayquant.c, such as pixThresholdOn8bpp(), where
823 * the emphasis is on quantization with an arbitrary number
824 * of levels, and a colormap is an option.
825 * (2) Returns a copy if pixs already has a colormap.
826 * (3) For 8 bpp src, this is a lossless transformation.
827 * (4) For 2 and 4 bpp src, this generates a colormap that
828 * assumes full coverage of the gray space, with equally spaced
829 * levels: 4 levels for d = 2 and 16 levels for d = 4.
830 * (5) In all cases, the depth of the dest is the same as the src.
831 */
832 PIX *
pixConvertGrayToColormap(PIX * pixs)833 pixConvertGrayToColormap(PIX *pixs)
834 {
835 l_int32 d;
836 PIX *pixd;
837 PIXCMAP *cmap;
838
839 PROCNAME("pixConvertGrayToColormap");
840
841 if (!pixs)
842 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
843 d = pixGetDepth(pixs);
844 if (d != 2 && d != 4 && d != 8)
845 return (PIX *)ERROR_PTR("pixs not 2, 4 or 8 bpp", procName, NULL);
846
847 if (pixGetColormap(pixs)) {
848 L_WARNING("pixs already has a colormap", procName);
849 return pixCopy(NULL, pixs);
850 }
851
852 if (d == 8) /* lossless conversion */
853 return pixConvertGrayToColormap8(pixs, 2);
854
855 /* Build a cmap with equally spaced target values over the
856 * full 8 bpp range. */
857 pixd = pixCopy(NULL, pixs);
858 cmap = pixcmapCreateLinear(d, 1 << d);
859 pixSetColormap(pixd, cmap);
860 return pixd;
861 }
862
863
864 /*!
865 * pixConvertGrayToColormap8()
866 *
867 * Input: pixs (8 bpp grayscale)
868 * mindepth (of pixd; valid values are 2, 4 and 8)
869 * Return: pixd (2, 4 or 8 bpp with colormap), or null on error
870 *
871 * Notes:
872 * (1) Returns a copy if pixs already has a colormap.
873 * (2) This is a lossless transformation; there is no quantization.
874 * We compute the number of different gray values in pixs,
875 * and construct a colormap that has exactly these values.
876 * (3) 'mindepth' is the minimum depth of pixd. If mindepth == 8,
877 * pixd will always be 8 bpp. Let the number of different
878 * gray values in pixs be ngray. If mindepth == 4, we attempt
879 * to save pixd as a 4 bpp image, but if ngray > 16,
880 * pixd must be 8 bpp. Likewise, if mindepth == 2,
881 * the depth of pixd will be 2 if ngray <= 4 and 4 if ngray > 4
882 * but <= 16.
883 */
884 PIX *
pixConvertGrayToColormap8(PIX * pixs,l_int32 mindepth)885 pixConvertGrayToColormap8(PIX *pixs,
886 l_int32 mindepth)
887 {
888 l_int32 ncolors, w, h, depth, i, j, wpls, wpld;
889 l_int32 index, num, val, newval;
890 l_int32 array[256];
891 l_uint32 *lines, *lined, *datas, *datad;
892 NUMA *na;
893 PIX *pixd;
894 PIXCMAP *cmap;
895
896 PROCNAME("pixConvertGrayToColormap8");
897
898 if (!pixs)
899 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
900 if (pixGetDepth(pixs) != 8)
901 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
902 if (mindepth != 2 && mindepth != 4 && mindepth != 8) {
903 L_WARNING("invalid value of mindepth; setting to 8", procName);
904 mindepth = 8;
905 }
906
907 if (pixGetColormap(pixs)) {
908 L_WARNING("pixs already has a colormap", procName);
909 return pixCopy(NULL, pixs);
910 }
911
912 na = pixGetGrayHistogram(pixs, 1);
913 numaGetCountRelativeToZero(na, L_GREATER_THAN_ZERO, &ncolors);
914 if (mindepth == 8 || ncolors > 16)
915 depth = 8;
916 else if (mindepth == 4 || ncolors > 4)
917 depth = 4;
918 else
919 depth = 2;
920
921 pixGetDimensions(pixs, &w, &h, NULL);
922 pixd = pixCreate(w, h, depth);
923 cmap = pixcmapCreate(depth);
924 pixSetColormap(pixd, cmap);
925 pixCopyResolution(pixd, pixs);
926
927 index = 0;
928 for (i = 0; i < 256; i++) {
929 numaGetIValue(na, i, &num);
930 if (num > 0) {
931 pixcmapAddColor(cmap, i, i, i);
932 array[i] = index;
933 index++;
934 }
935 }
936
937 datas = pixGetData(pixs);
938 wpls = pixGetWpl(pixs);
939 datad = pixGetData(pixd);
940 wpld = pixGetWpl(pixd);
941 for (i = 0; i < h; i++) {
942 lines = datas + i * wpls;
943 lined = datad + i * wpld;
944 for (j = 0; j < w; j++) {
945 val = GET_DATA_BYTE(lines, j);
946 newval = array[val];
947 if (depth == 2)
948 SET_DATA_DIBIT(lined, j, newval);
949 else if (depth == 4)
950 SET_DATA_QBIT(lined, j, newval);
951 else /* depth == 8 */
952 SET_DATA_BYTE(lined, j, newval);
953 }
954 }
955
956 numaDestroy(&na);
957 return pixd;
958 }
959
960
961 /*---------------------------------------------------------------------------*
962 * Colorizing conversion from grayscale to color *
963 *---------------------------------------------------------------------------*/
964 /*!
965 * pixColorizeGray()
966 *
967 * Input: pixs (8 bpp gray; 2, 4 or 8 bpp colormapped)
968 * color (32 bit rgba pixel)
969 * cmapflag (1 for result to have colormap; 0 for RGB)
970 * Return: pixd (8 bpp colormapped or 32 bpp rgb), or null on error
971 *
972 * Notes:
973 * (1) This applies the specific color to the grayscale image.
974 * (2) If pixs already has a colormap, it is removed to gray
975 * before colorizing.
976 */
977 PIX *
pixColorizeGray(PIX * pixs,l_uint32 color,l_int32 cmapflag)978 pixColorizeGray(PIX *pixs,
979 l_uint32 color,
980 l_int32 cmapflag)
981 {
982 l_int32 i, j, w, h, wplt, wpld, val8;
983 l_uint32 *datad, *datat, *lined, *linet, *tab;
984 PIX *pixt, *pixd;
985 PIXCMAP *cmap;
986
987 PROCNAME("pixColorizeGray");
988
989 if (!pixs)
990 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
991 if (pixGetDepth(pixs) != 8 && !pixGetColormap(pixs))
992 return (PIX *)ERROR_PTR("pixs not 8 bpp or cmapped", procName, NULL);
993
994 if (pixGetColormap(pixs))
995 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
996 else
997 pixt = pixClone(pixs);
998
999 cmap = pixcmapGrayToColor(color);
1000 if (cmapflag) {
1001 pixd = pixCopy(NULL, pixt);
1002 pixSetColormap(pixd, cmap);
1003 pixDestroy(&pixt);
1004 return pixd;
1005 }
1006
1007 /* Make an RGB pix */
1008 pixcmapToRGBTable(cmap, &tab, NULL);
1009 pixGetDimensions(pixt, &w, &h, NULL);
1010 pixd = pixCreate(w, h, 32);
1011 pixCopyResolution(pixd, pixs);
1012 datad = pixGetData(pixd);
1013 wpld = pixGetWpl(pixd);
1014 datat = pixGetData(pixt);
1015 wplt = pixGetWpl(pixt);
1016 for (i = 0; i < h; i++) {
1017 lined = datad + i * wpld;
1018 linet = datat + i * wplt;
1019 for (j = 0; j < w; j++) {
1020 val8 = GET_DATA_BYTE(linet, j);
1021 lined[j] = tab[val8];
1022 }
1023 }
1024
1025 pixDestroy(&pixt);
1026 pixcmapDestroy(&cmap);
1027 FREE(tab);
1028 return pixd;
1029 }
1030
1031
1032 /*---------------------------------------------------------------------------*
1033 * Conversion from RGB color to colormap *
1034 *---------------------------------------------------------------------------*/
1035 /*!
1036 * pixConvertRGBToColormap()
1037 *
1038 * Input: pixs (32 bpp rgb)
1039 * ditherflag (1 to dither, 0 otherwise)
1040 * Return: pixd (2, 4 or 8 bpp with colormap), or null on error
1041 *
1042 * Notes:
1043 * (1) This function has two relatively simple modes of color
1044 * quantization:
1045 * (a) If the image is made orthographically and has not more
1046 * than 256 'colors' at the level 4 octcube leaves,
1047 * it is quantized nearly exactly. The ditherflag
1048 * is ignored.
1049 * (b) Most natural images have more than 256 different colors;
1050 * in that case we use adaptive octree quantization,
1051 * with dithering if requested.
1052 * (2) If there are not more than 256 occupied level 4 octcubes,
1053 * the color in the colormap that represents all pixels in
1054 * one of those octcubes is given by the first pixel that
1055 * falls into that octcube.
1056 * (3) If there are more than 256 colors, we use adaptive octree
1057 * color quantization.
1058 * (4) Dithering gives better visual results on images where
1059 * there is a color wash (a slow variation of color), but it
1060 * is about twice as slow and results in significantly larger
1061 * files when losslessly compressed (e.g., into png).
1062 */
1063 PIX *
pixConvertRGBToColormap(PIX * pixs,l_int32 ditherflag)1064 pixConvertRGBToColormap(PIX *pixs,
1065 l_int32 ditherflag)
1066 {
1067 l_int32 ncolors;
1068 NUMA *na;
1069 PIX *pixd;
1070
1071 PROCNAME("pixConvertRGBToColormap");
1072
1073 if (!pixs)
1074 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1075 if (pixGetDepth(pixs) != 32)
1076 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
1077
1078 /* Get the histogram and count the number of occupied level 4
1079 * leaf octcubes. We don't yet know if this is the number of
1080 * actual colors, but if it's not, all pixels falling into
1081 * the same leaf octcube will be assigned to the color of the
1082 * first pixel that lands there. */
1083 na = pixOctcubeHistogram(pixs, 4, &ncolors);
1084
1085 /* If there are too many occupied leaf octcubes to be
1086 * represented directly in a colormap, fall back to octree
1087 * quantization with dithering. */
1088 if (ncolors > 256) {
1089 L_INFO("More than 256 colors; using octree quant with dithering",
1090 procName);
1091 numaDestroy(&na);
1092 return pixOctreeColorQuant(pixs, 240, ditherflag);
1093 }
1094
1095 /* There are not more than 256 occupied leaf octcubes.
1096 * Quantize to those octcubes. */
1097 pixd = pixFewColorsOctcubeQuant2(pixs, 4, na, ncolors, NULL);
1098 numaDestroy(&na);
1099 return pixd;
1100 }
1101
1102
1103 /*---------------------------------------------------------------------------*
1104 * Quantization for relatively small number of colors in source *
1105 *---------------------------------------------------------------------------*/
1106 /*!
1107 * pixQuantizeIfFewColors()
1108 *
1109 * Input: pixs (8 bpp gray or 32 bpp rgb)
1110 * maxcolors (max number of colors allowed to be returned
1111 * from pixColorsForQuantization(); use 0 for default)
1112 * mingraycolors (min number of gray levels that a grayscale
1113 * image is quantized to; use 0 for default)
1114 * octlevel (for octcube quantization: 3 or 4)
1115 * &pixd (2, 4 or 8 bpp quantized; null if too many colors)
1116 * Return: 0 if OK, 1 on error or if pixs can't be quantized into
1117 * a small number of colors.
1118 *
1119 * Notes:
1120 * (1) This is a wrapper that tests if the pix can be quantized
1121 * with good quality using a small number of colors. If so,
1122 * it does the quantization, defining a colormap and using
1123 * pixels whose value is an index into the colormap.
1124 * (2) If the image has color, it is quantized with 8 bpp pixels.
1125 * If the image is essentially grayscale, the pixels are
1126 * either 4 or 8 bpp, depending on the size of the required
1127 * colormap.
1128 * (3) @octlevel = 3 works well for most images. However, for best
1129 * quality, at a cost of more colors in the colormap, use
1130 * @octlevel = 4.
1131 * (4) If the image already has a colormap, it returns a clone.
1132 */
1133 l_int32
pixQuantizeIfFewColors(PIX * pixs,l_int32 maxcolors,l_int32 mingraycolors,l_int32 octlevel,PIX ** ppixd)1134 pixQuantizeIfFewColors(PIX *pixs,
1135 l_int32 maxcolors,
1136 l_int32 mingraycolors,
1137 l_int32 octlevel,
1138 PIX **ppixd)
1139 {
1140 l_int32 d, ncolors, iscolor, graycolors;
1141 PIX *pixg, *pixd;
1142
1143 PROCNAME("pixQuantizeIfFewColors");
1144
1145 if (!ppixd)
1146 return ERROR_INT("&pixd not defined", procName, 1);
1147 *ppixd = NULL;
1148 if (!pixs)
1149 return ERROR_INT("pixs not defined", procName, 1);
1150 d = pixGetDepth(pixs);
1151 if (d != 8 && d != 32)
1152 return ERROR_INT("pixs not defined", procName, 1);
1153 if (pixGetColormap(pixs) != NULL) {
1154 *ppixd = pixClone(pixs);
1155 return 0;
1156 }
1157 if (maxcolors <= 0)
1158 maxcolors = 15; /* default */
1159 if (maxcolors > 50)
1160 L_WARNING("maxcolors > 50; very large!", procName);
1161 if (mingraycolors <= 0)
1162 mingraycolors = 10; /* default */
1163 if (mingraycolors > 30)
1164 L_WARNING("mingraycolors > 30; very large!", procName);
1165 if (octlevel != 3 && octlevel != 4) {
1166 L_WARNING("invalid octlevel; setting to 3", procName);
1167 octlevel = 3;
1168 }
1169
1170 /* Test the number of colors. For color, the octcube leaves
1171 * are at level 4. */
1172 pixColorsForQuantization(pixs, 0, &ncolors, &iscolor, 0);
1173 if (ncolors > maxcolors)
1174 return ERROR_INT("too many colors", procName, 1);
1175
1176 /* Quantize!
1177 * (1) For color:
1178 * If octlevel == 4, try to quantize to an octree where
1179 * the octcube leaves are at level 4. If that fails,
1180 * back off to level 3.
1181 * If octlevel == 3, quantize to level 3 directly.
1182 * For level 3, the quality is usually good enough and there
1183 * is negligible chance of getting more than 256 colors.
1184 * (2) For grayscale, multiply ncolors by 1.5 for extra quality,
1185 * but use at least mingraycolors. */
1186 if (iscolor) {
1187 pixd = pixFewColorsOctcubeQuant1(pixs, octlevel);
1188 if (!pixd) { /* backoff */
1189 pixd = pixFewColorsOctcubeQuant1(pixs, octlevel - 1);
1190 if (octlevel == 3) /* shouldn't happen */
1191 L_WARNING("quantized at level 2; low quality", procName);
1192 }
1193 }
1194 else { /* image is really grayscale */
1195 if (d == 32)
1196 pixg = pixConvertRGBToLuminance(pixs);
1197 else
1198 pixg = pixClone(pixs);
1199 graycolors = L_MAX(mingraycolors, (l_int32)(1.5 * ncolors));
1200 if (graycolors < 16)
1201 pixd = pixThresholdTo4bpp(pixg, graycolors, 1);
1202 else
1203 pixd = pixThresholdOn8bpp(pixg, graycolors, 1);
1204 pixDestroy(&pixg);
1205 }
1206 *ppixd = pixd;
1207
1208 if (!pixd)
1209 return ERROR_INT("pixd not made", procName, 1);
1210 else
1211 return 0;
1212 }
1213
1214
1215
1216 /*---------------------------------------------------------------------------*
1217 * Conversion from 16 bpp to 8 bpp *
1218 *---------------------------------------------------------------------------*/
1219 /*!
1220 * pixConvert16To8()
1221 *
1222 * Input: pixs (16 bpp)
1223 * whichbyte (1 for MSB, 0 for LSB)
1224 * Return: pixd (8 bpp), or null on error
1225 *
1226 * Notes:
1227 * (1) For each dest pixel, use either the MSB or LSB of each src pixel.
1228 */
1229 PIX *
pixConvert16To8(PIX * pixs,l_int32 whichbyte)1230 pixConvert16To8(PIX *pixs,
1231 l_int32 whichbyte)
1232 {
1233 l_uint16 dsword;
1234 l_int32 w, h, wpls, wpld, i, j;
1235 l_uint32 sword;
1236 l_uint32 *datas, *datad, *lines, *lined;
1237 PIX *pixd;
1238
1239 PROCNAME("pixConvert16To8");
1240
1241 if (!pixs)
1242 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1243 if (pixGetDepth(pixs) != 16)
1244 return (PIX *)ERROR_PTR("pixs not 16 bpp", procName, NULL);
1245
1246 pixGetDimensions(pixs, &w, &h, NULL);
1247 if ((pixd = pixCreate(w, h, 8)) == NULL)
1248 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1249 pixCopyResolution(pixd, pixs);
1250 wpls = pixGetWpl(pixs);
1251 datas = pixGetData(pixs);
1252 wpld = pixGetWpl(pixd);
1253 datad = pixGetData(pixd);
1254
1255 /* Convert 2 pixels at a time */
1256 for (i = 0; i < h; i++) {
1257 lines = datas + i * wpls;
1258 lined = datad + i * wpld;
1259 if (whichbyte == 0) { /* LSB */
1260 for (j = 0; j < wpls; j++) {
1261 sword = *(lines + j);
1262 dsword = ((sword >> 8) & 0xff00) | (sword & 0xff);
1263 SET_DATA_TWO_BYTES(lined, j, dsword);
1264 }
1265 }
1266 else { /* MSB */
1267 for (j = 0; j < wpls; j++) {
1268 sword = *(lines + j);
1269 dsword = ((sword >> 16) & 0xff00) | ((sword >> 8) & 0xff);
1270 SET_DATA_TWO_BYTES(lined, j, dsword);
1271 }
1272 }
1273 }
1274
1275 return pixd;
1276 }
1277
1278
1279
1280 /*---------------------------------------------------------------------------*
1281 * Conversion from grayscale to false color
1282 *---------------------------------------------------------------------------*/
1283 /*!
1284 * pixConvertGrayToFalseColor()
1285 *
1286 * Input: pixs (8 or 16 bpp grayscale)
1287 * gamma factor (0.0 or 1.0 for default; > 1.0 for brighter;
1288 * 2.0 is quite nice)
1289 * Return: pixd (8 bpp with colormap), or null on error
1290 *
1291 * Notes:
1292 * (1) For 8 bpp input, this simply adds a colormap to the input image.
1293 * (2) For 16 bpp input, it first converts to 8 bpp and then
1294 * adds the colormap.
1295 * (3) The colormap is modeled after the Matlab "jet" configuration.
1296 */
1297 PIX *
pixConvertGrayToFalseColor(PIX * pixs,l_float32 gamma)1298 pixConvertGrayToFalseColor(PIX *pixs,
1299 l_float32 gamma)
1300 {
1301 l_int32 d, i, rval, bval, gval;
1302 l_int32 *curve;
1303 l_float32 invgamma, x;
1304 PIX *pixd;
1305 PIXCMAP *cmap;
1306
1307 PROCNAME("pixConvertGrayToFalseColor");
1308
1309 if (!pixs)
1310 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1311 d = pixGetDepth(pixs);
1312 if (d != 8 && d != 16)
1313 return (PIX *)ERROR_PTR("pixs not 8 or 16 bpp", procName, NULL);
1314
1315 if (d == 16)
1316 pixd = pixConvert16To8(pixs, 1);
1317 else { /* d == 8 */
1318 if (pixGetColormap(pixs))
1319 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1320 else
1321 pixd = pixCopy(NULL, pixs);
1322 }
1323 if (!pixd)
1324 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1325 if ((cmap = pixcmapCreate(8)) == NULL)
1326 return (PIX *)ERROR_PTR("cmap not made", procName, NULL);
1327 pixSetColormap(pixd, cmap);
1328 pixCopyResolution(pixd, pixs);
1329
1330 /* Generate curve for transition part of color map */
1331 if ((curve = (l_int32 *)CALLOC(64, sizeof(l_int32)))== NULL)
1332 return (PIX *)ERROR_PTR("curve not made", procName, NULL);
1333 if (gamma == 0.0) gamma = 1.0;
1334 invgamma = 1. / gamma;
1335 for (i = 0; i < 64; i++) {
1336 x = (l_float32)i / 64.;
1337 curve[i] = (l_int32)(255. * powf(x, invgamma) + 0.5);
1338 }
1339
1340 for (i = 0; i < 256; i++) {
1341 if (i < 32) {
1342 rval = 0;
1343 gval = 0;
1344 bval = curve[i + 32];
1345 }
1346 else if (i < 96) { /* 32 - 95 */
1347 rval = 0;
1348 gval = curve[i - 32];
1349 bval = 255;
1350 }
1351 else if (i < 160) { /* 96 - 159 */
1352 rval = curve[i - 96];
1353 gval = 255;
1354 bval = curve[159 - i];
1355 }
1356 else if (i < 224) { /* 160 - 223 */
1357 rval = 255;
1358 gval = curve[223 - i];
1359 bval = 0;
1360 }
1361 else { /* 224 - 255 */
1362 rval = curve[287 - i];
1363 gval = 0;
1364 bval = 0;
1365 }
1366 pixcmapAddColor(cmap, rval, gval, bval);
1367 }
1368
1369 FREE(curve);
1370 return pixd;
1371 }
1372
1373
1374 /*---------------------------------------------------------------------------*
1375 * Unpacking conversion from 1 bpp to 2, 4, 8, 16 and 32 bpp *
1376 *---------------------------------------------------------------------------*/
1377 /*!
1378 * pixUnpackBinary()
1379 *
1380 * Input: pixs (1 bpp)
1381 * depth (of destination: 2, 4, 8, 16 or 32 bpp)
1382 * invert (0: binary 0 --> grayscale 0
1383 * binary 1 --> grayscale 0xff...
1384 * 1: binary 0 --> grayscale 0xff...
1385 * binary 1 --> grayscale 0)
1386 * Return: pixd (2, 4, 8, 16 or 32 bpp), or null on error
1387 *
1388 * Notes:
1389 * (1) This function calls special cases of pixConvert1To*(),
1390 * for 2, 4, 8, 16 and 32 bpp destinations.
1391 */
1392 PIX *
pixUnpackBinary(PIX * pixs,l_int32 depth,l_int32 invert)1393 pixUnpackBinary(PIX *pixs,
1394 l_int32 depth,
1395 l_int32 invert)
1396 {
1397 PIX *pixd;
1398
1399 PROCNAME("pixUnpackBinary");
1400
1401 if (!pixs)
1402 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1403 if (pixGetDepth(pixs) != 1)
1404 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1405 if (depth != 2 && depth != 4 && depth != 8 && depth != 16 && depth != 32)
1406 return (PIX *)ERROR_PTR("depth not 2, 4, 8, 16 or 32 bpp",
1407 procName, NULL);
1408
1409 if (depth == 2) {
1410 if (invert == 0)
1411 pixd = pixConvert1To2(NULL, pixs, 0, 3);
1412 else /* invert bits */
1413 pixd = pixConvert1To2(NULL, pixs, 3, 0);
1414 }
1415 else if (depth == 4) {
1416 if (invert == 0)
1417 pixd = pixConvert1To4(NULL, pixs, 0, 15);
1418 else /* invert bits */
1419 pixd = pixConvert1To4(NULL, pixs, 15, 0);
1420 }
1421 else if (depth == 8) {
1422 if (invert == 0)
1423 pixd = pixConvert1To8(NULL, pixs, 0, 255);
1424 else /* invert bits */
1425 pixd = pixConvert1To8(NULL, pixs, 255, 0);
1426 }
1427 else if (depth == 16) {
1428 if (invert == 0)
1429 pixd = pixConvert1To16(NULL, pixs, 0, 0xffff);
1430 else /* invert bits */
1431 pixd = pixConvert1To16(NULL, pixs, 0xffff, 0);
1432 }
1433 else {
1434 if (invert == 0)
1435 pixd = pixConvert1To32(NULL, pixs, 0, 0xffffffff);
1436 else /* invert bits */
1437 pixd = pixConvert1To32(NULL, pixs, 0xffffffff, 0);
1438 }
1439
1440 return pixd;
1441 }
1442
1443
1444 /*!
1445 * pixConvert1To16()
1446 *
1447 * Input: pixd (<optional> 16 bpp, can be null)
1448 * pixs (1 bpp)
1449 * val0 (16 bit value to be used for 0s in pixs)
1450 * val1 (16 bit value to be used for 1s in pixs)
1451 * Return: pixd (16 bpp)
1452 *
1453 * Notes:
1454 * (1) If pixd is null, a new pix is made.
1455 * (2) If pixd is not null, it must be of equal width and height
1456 * as pixs. It is always returned.
1457 */
1458 PIX *
pixConvert1To16(PIX * pixd,PIX * pixs,l_uint16 val0,l_uint16 val1)1459 pixConvert1To16(PIX *pixd,
1460 PIX *pixs,
1461 l_uint16 val0,
1462 l_uint16 val1)
1463 {
1464 l_int32 w, h, i, j, dibit, ndibits, wpls, wpld;
1465 l_uint16 val[2];
1466 l_uint32 index;
1467 l_uint32 *tab, *datas, *datad, *lines, *lined;
1468
1469 PROCNAME("pixConvert1To16");
1470
1471 if (!pixs)
1472 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1473 if (pixGetDepth(pixs) != 1)
1474 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1475
1476 w = pixGetWidth(pixs);
1477 h = pixGetHeight(pixs);
1478 if (pixd) {
1479 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
1480 return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
1481 if (pixGetDepth(pixd) != 16)
1482 return (PIX *)ERROR_PTR("pixd not 16 bpp", procName, pixd);
1483 }
1484 else {
1485 if ((pixd = pixCreate(w, h, 16)) == NULL)
1486 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1487 }
1488 pixCopyResolution(pixd, pixs);
1489
1490 /* Use a table to convert 2 src bits at a time */
1491 if ((tab = (l_uint32 *)CALLOC(4, sizeof(l_uint32))) == NULL)
1492 return (PIX *)ERROR_PTR("tab not made", procName, NULL);
1493 val[0] = val0;
1494 val[1] = val1;
1495 for (index = 0; index < 4; index++) {
1496 tab[index] = (val[(index >> 1) & 1] << 16) | val[index & 1];
1497 }
1498
1499 datas = pixGetData(pixs);
1500 wpls = pixGetWpl(pixs);
1501 datad = pixGetData(pixd);
1502 wpld = pixGetWpl(pixd);
1503 ndibits = (w + 1) / 2;
1504 for (i = 0; i < h; i++) {
1505 lines = datas + i * wpls;
1506 lined = datad + i * wpld;
1507 for (j = 0; j < ndibits; j++) {
1508 dibit = GET_DATA_DIBIT(lines, j);
1509 lined[j] = tab[dibit];
1510 }
1511 }
1512
1513 FREE(tab);
1514 return pixd;
1515 }
1516
1517
1518 /*!
1519 * pixConvert1To32()
1520 *
1521 * Input: pixd (<optional> 32 bpp, can be null)
1522 * pixs (1 bpp)
1523 * val0 (32 bit value to be used for 0s in pixs)
1524 * val1 (32 bit value to be used for 1s in pixs)
1525 * Return: pixd (32 bpp)
1526 *
1527 * Notes:
1528 * (1) If pixd is null, a new pix is made.
1529 * (2) If pixd is not null, it must be of equal width and height
1530 * as pixs. It is always returned.
1531 */
1532 PIX *
pixConvert1To32(PIX * pixd,PIX * pixs,l_uint32 val0,l_uint32 val1)1533 pixConvert1To32(PIX *pixd,
1534 PIX *pixs,
1535 l_uint32 val0,
1536 l_uint32 val1)
1537 {
1538 l_int32 w, h, i, j, wpls, wpld, bit;
1539 l_uint32 val[2];
1540 l_uint32 *datas, *datad, *lines, *lined;
1541
1542 PROCNAME("pixConvert1To32");
1543
1544 if (!pixs)
1545 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1546 if (pixGetDepth(pixs) != 1)
1547 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1548
1549 pixGetDimensions(pixs, &w, &h, NULL);
1550 if (pixd) {
1551 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
1552 return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
1553 if (pixGetDepth(pixd) != 32)
1554 return (PIX *)ERROR_PTR("pixd not 32 bpp", procName, pixd);
1555 }
1556 else {
1557 if ((pixd = pixCreate(w, h, 32)) == NULL)
1558 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1559 }
1560 pixCopyResolution(pixd, pixs);
1561
1562 val[0] = val0;
1563 val[1] = val1;
1564 datas = pixGetData(pixs);
1565 wpls = pixGetWpl(pixs);
1566 datad = pixGetData(pixd);
1567 wpld = pixGetWpl(pixd);
1568 for (i = 0; i < h; i++) {
1569 lines = datas + i * wpls;
1570 lined = datad + i * wpld;
1571 for (j = 0; j <w; j++) {
1572 bit = GET_DATA_BIT(lines, j);
1573 lined[j] = val[bit];
1574 }
1575 }
1576
1577 return pixd;
1578 }
1579
1580
1581 /*---------------------------------------------------------------------------*
1582 * Conversion from 1 bpp to 2 bpp *
1583 *---------------------------------------------------------------------------*/
1584 /*!
1585 * pixConvert1To2Cmap()
1586 *
1587 * Input: pixs (1 bpp)
1588 * Return: pixd (2 bpp, cmapped)
1589 *
1590 * Notes:
1591 * (1) Input 0 is mapped to (255, 255, 255); 1 is mapped to (0, 0, 0)
1592 */
1593 PIX *
pixConvert1To2Cmap(PIX * pixs)1594 pixConvert1To2Cmap(PIX *pixs)
1595 {
1596 PIX *pixd;
1597 PIXCMAP *cmap;
1598
1599 PROCNAME("pixConvert1To2Cmap");
1600
1601 if (!pixs)
1602 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1603 if (pixGetDepth(pixs) != 1)
1604 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1605
1606 if ((pixd = pixConvert1To2(NULL, pixs, 0, 1)) == NULL)
1607 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1608 cmap = pixcmapCreate(2);
1609 pixcmapAddColor(cmap, 255, 255, 255);
1610 pixcmapAddColor(cmap, 0, 0, 0);
1611 pixSetColormap(pixd, cmap);
1612
1613 return pixd;
1614 }
1615
1616
1617 /*!
1618 * pixConvert1To2()
1619 *
1620 * Input: pixd (<optional> 2 bpp, can be null)
1621 * pixs (1 bpp)
1622 * val0 (2 bit value to be used for 0s in pixs)
1623 * val1 (2 bit value to be used for 1s in pixs)
1624 * Return: pixd (2 bpp)
1625 *
1626 * Notes:
1627 * (1) If pixd is null, a new pix is made.
1628 * (2) If pixd is not null, it must be of equal width and height
1629 * as pixs. It is always returned.
1630 * (3) A simple unpacking might use val0 = 0 and val1 = 3.
1631 * (4) If you want a colormapped pixd, use pixConvert1To2Cmap().
1632 */
1633 PIX *
pixConvert1To2(PIX * pixd,PIX * pixs,l_int32 val0,l_int32 val1)1634 pixConvert1To2(PIX *pixd,
1635 PIX *pixs,
1636 l_int32 val0,
1637 l_int32 val1)
1638 {
1639 l_int32 w, h, i, j, byteval, nbytes, wpls, wpld;
1640 l_uint8 val[2];
1641 l_uint32 index;
1642 l_uint16 *tab;
1643 l_uint32 *datas, *datad, *lines, *lined;
1644
1645 PROCNAME("pixConvert1To2");
1646
1647 if (!pixs)
1648 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1649 if (pixGetDepth(pixs) != 1)
1650 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
1651
1652 pixGetDimensions(pixs, &w, &h, NULL);
1653 if (pixd) {
1654 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
1655 return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
1656 if (pixGetDepth(pixd) != 2)
1657 return (PIX *)ERROR_PTR("pixd not 2 bpp", procName, pixd);
1658 }
1659 else {
1660 if ((pixd = pixCreate(w, h, 2)) == NULL)
1661 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1662 }
1663 pixCopyResolution(pixd, pixs);
1664
1665 /* Use a table to convert 8 src bits to 16 dest bits */
1666 if ((tab = (l_uint16 *)CALLOC(256, sizeof(l_uint16))) == NULL)
1667 return (PIX *)ERROR_PTR("tab not made", procName, NULL);
1668 val[0] = val0;
1669 val[1] = val1;
1670 for (index = 0; index < 256; index++) {
1671 tab[index] = (val[(index >> 7) & 1] << 14) |
1672 (val[(index >> 6) & 1] << 12) |
1673 (val[(index >> 5) & 1] << 10) |
1674 (val[(index >> 4) & 1] << 8) |
1675 (val[(index >> 3) & 1] << 6) |
1676 (val[(index >> 2) & 1] << 4) |
1677 (val[(index >> 1) & 1] << 2) | val[index & 1];
1678 }
1679
1680 datas = pixGetData(pixs);
1681 wpls = pixGetWpl(pixs);
1682 datad = pixGetData(pixd);
1683 wpld = pixGetWpl(pixd);
1684 nbytes = (w + 7) / 8;
1685 for (i = 0; i < h; i++) {
1686 lines = datas + i * wpls;
1687 lined = datad + i * wpld;
1688 for (j = 0; j < nbytes; j++) {
1689 byteval = GET_DATA_BYTE(lines, j);
1690 SET_DATA_TWO_BYTES(lined, j, tab[byteval]);
1691 }
1692 }
1693
1694 FREE(tab);
1695 return pixd;
1696 }
1697
1698
1699 /*---------------------------------------------------------------------------*
1700 * Conversion from 1 bpp to 4 bpp *
1701 *---------------------------------------------------------------------------*/
1702 /*!
1703 * pixConvert1To4Cmap()
1704 *
1705 * Input: pixs (1 bpp)
1706 * Return: pixd (4 bpp, cmapped)
1707 *
1708 * Notes:
1709 * (1) Input 0 is mapped to (255, 255, 255); 1 is mapped to (0, 0, 0)
1710 */
1711 PIX *
pixConvert1To4Cmap(PIX * pixs)1712 pixConvert1To4Cmap(PIX *pixs)
1713 {
1714 PIX *pixd;
1715 PIXCMAP *cmap;
1716
1717 PROCNAME("pixConvert1To4Cmap");
1718
1719 if (!pixs)
1720 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1721 if (pixGetDepth(pixs) != 1)
1722 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
1723
1724 if ((pixd = pixConvert1To4(NULL, pixs, 0, 1)) == NULL)
1725 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1726 cmap = pixcmapCreate(4);
1727 pixcmapAddColor(cmap, 255, 255, 255);
1728 pixcmapAddColor(cmap, 0, 0, 0);
1729 pixSetColormap(pixd, cmap);
1730
1731 return pixd;
1732 }
1733
1734
1735 /*!
1736 * pixConvert1To4()
1737 *
1738 * Input: pixd (<optional> 4 bpp, can be null)
1739 * pixs (1 bpp)
1740 * val0 (4 bit value to be used for 0s in pixs)
1741 * val1 (4 bit value to be used for 1s in pixs)
1742 * Return: pixd (4 bpp)
1743 *
1744 * Notes:
1745 * (1) If pixd is null, a new pix is made.
1746 * (2) If pixd is not null, it must be of equal width and height
1747 * as pixs. It is always returned.
1748 * (3) A simple unpacking might use val0 = 0 and val1 = 15, or v.v.
1749 * (4) If you want a colormapped pixd, use pixConvert1To4Cmap().
1750 */
1751 PIX *
pixConvert1To4(PIX * pixd,PIX * pixs,l_int32 val0,l_int32 val1)1752 pixConvert1To4(PIX *pixd,
1753 PIX *pixs,
1754 l_int32 val0,
1755 l_int32 val1)
1756 {
1757 l_int32 w, h, i, j, byteval, nbytes, wpls, wpld;
1758 l_uint8 val[2];
1759 l_uint32 index;
1760 l_uint32 *tab, *datas, *datad, *lines, *lined;
1761
1762 PROCNAME("pixConvert1To4");
1763
1764 if (!pixs)
1765 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1766 if (pixGetDepth(pixs) != 1)
1767 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
1768
1769 pixGetDimensions(pixs, &w, &h, NULL);
1770 if (pixd) {
1771 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
1772 return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
1773 if (pixGetDepth(pixd) != 4)
1774 return (PIX *)ERROR_PTR("pixd not 4 bpp", procName, pixd);
1775 }
1776 else {
1777 if ((pixd = pixCreate(w, h, 4)) == NULL)
1778 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1779 }
1780 pixCopyResolution(pixd, pixs);
1781
1782 /* Use a table to convert 8 src bits to 32 bit dest word */
1783 if ((tab = (l_uint32 *)CALLOC(256, sizeof(l_uint32))) == NULL)
1784 return (PIX *)ERROR_PTR("tab not made", procName, NULL);
1785 val[0] = val0;
1786 val[1] = val1;
1787 for (index = 0; index < 256; index++) {
1788 tab[index] = (val[(index >> 7) & 1] << 28) |
1789 (val[(index >> 6) & 1] << 24) |
1790 (val[(index >> 5) & 1] << 20) |
1791 (val[(index >> 4) & 1] << 16) |
1792 (val[(index >> 3) & 1] << 12) |
1793 (val[(index >> 2) & 1] << 8) |
1794 (val[(index >> 1) & 1] << 4) | val[index & 1];
1795 }
1796
1797 datas = pixGetData(pixs);
1798 wpls = pixGetWpl(pixs);
1799 datad = pixGetData(pixd);
1800 wpld = pixGetWpl(pixd);
1801 nbytes = (w + 7) / 8;
1802 for (i = 0; i < h; i++) {
1803 lines = datas + i * wpls;
1804 lined = datad + i * wpld;
1805 for (j = 0; j < nbytes; j++) {
1806 byteval = GET_DATA_BYTE(lines, j);
1807 lined[j] = tab[byteval];
1808 }
1809 }
1810
1811 FREE(tab);
1812 return pixd;
1813 }
1814
1815
1816 /*---------------------------------------------------------------------------*
1817 * Conversion from 1, 2 and 4 bpp to 8 bpp *
1818 *---------------------------------------------------------------------------*/
1819 /*!
1820 * pixConvert1To8()
1821 *
1822 * Input: pixd (<optional> 8 bpp, can be null)
1823 * pixs (1 bpp)
1824 * val0 (8 bit value to be used for 0s in pixs)
1825 * val1 (8 bit value to be used for 1s in pixs)
1826 * Return: pixd (8 bpp)
1827 *
1828 * Notes:
1829 * (1) If pixd is null, a new pix is made.
1830 * (2) If pixd is not null, it must be of equal width and height
1831 * as pixs. It is always returned.
1832 * (3) A simple unpacking might use val0 = 0 and val1 = 255, or v.v.
1833 * (4) In a typical application where one wants to use a colormap
1834 * with the dest, you can use val0 = 0, val1 = 1 to make a
1835 * non-cmapped 8 bpp pix, and then make a colormap and set 0
1836 * and 1 to the desired colors. Here is an example:
1837 * pixd = pixConvert1To8(NULL, pixs, 0, 1);
1838 * cmap = pixCreate(8);
1839 * pixcmapAddColor(cmap, 255, 255, 255);
1840 * pixcmapAddColor(cmap, 0, 0, 0);
1841 * pixSetColormap(pixd, cmap);
1842 */
1843 PIX *
pixConvert1To8(PIX * pixd,PIX * pixs,l_uint8 val0,l_uint8 val1)1844 pixConvert1To8(PIX *pixd,
1845 PIX *pixs,
1846 l_uint8 val0,
1847 l_uint8 val1)
1848 {
1849 l_int32 w, h, i, j, qbit, nqbits, wpls, wpld;
1850 l_uint8 val[2];
1851 l_uint32 index;
1852 l_uint32 *tab, *datas, *datad, *lines, *lined;
1853
1854 PROCNAME("pixConvert1To8");
1855
1856 if (!pixs)
1857 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1858 if (pixGetDepth(pixs) != 1)
1859 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
1860
1861 pixGetDimensions(pixs, &w, &h, NULL);
1862 if (pixd) {
1863 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
1864 return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
1865 if (pixGetDepth(pixd) != 8)
1866 return (PIX *)ERROR_PTR("pixd not 8 bpp", procName, pixd);
1867 }
1868 else {
1869 if ((pixd = pixCreate(w, h, 8)) == NULL)
1870 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1871 }
1872 pixCopyResolution(pixd, pixs);
1873
1874 /* Use a table to convert 4 src bits at a time */
1875 if ((tab = (l_uint32 *)CALLOC(16, sizeof(l_uint32))) == NULL)
1876 return (PIX *)ERROR_PTR("tab not made", procName, NULL);
1877 val[0] = val0;
1878 val[1] = val1;
1879 for (index = 0; index < 16; index++) {
1880 tab[index] = (val[(index >> 3) & 1] << 24) |
1881 (val[(index >> 2) & 1] << 16) |
1882 (val[(index >> 1) & 1] << 8) | val[index & 1];
1883 }
1884
1885 datas = pixGetData(pixs);
1886 wpls = pixGetWpl(pixs);
1887 datad = pixGetData(pixd);
1888 wpld = pixGetWpl(pixd);
1889 nqbits = (w + 3) / 4;
1890 for (i = 0; i < h; i++) {
1891 lines = datas + i * wpls;
1892 lined = datad + i * wpld;
1893 for (j = 0; j < nqbits; j++) {
1894 qbit = GET_DATA_QBIT(lines, j);
1895 lined[j] = tab[qbit];
1896 }
1897 }
1898
1899 FREE(tab);
1900 return pixd;
1901 }
1902
1903
1904 /*!
1905 * pixConvert2To8()
1906 *
1907 * Input: pixs (2 bpp)
1908 * val0 (8 bit value to be used for 00 in pixs)
1909 * val1 (8 bit value to be used for 01 in pixs)
1910 * val2 (8 bit value to be used for 10 in pixs)
1911 * val3 (8 bit value to be used for 11 in pixs)
1912 * cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise)
1913 * Return: pixd (8 bpp), or null on error
1914 *
1915 * Notes:
1916 * - A simple unpacking might use val0 = 0,
1917 * val1 = 85 (0x55), val2 = 170 (0xaa), val3 = 255.
1918 * - If cmapflag is TRUE:
1919 * - The 8 bpp image is made with a colormap.
1920 * - If pixs has a colormap, the input values are ignored and
1921 * the 8 bpp image is made using the colormap
1922 * - If pixs does not have a colormap, the input values are
1923 * used to build the colormap.
1924 * - If cmapflag is FALSE:
1925 * - The 8 bpp image is made without a colormap.
1926 * - If pixs has a colormap, the input values are ignored,
1927 * the colormap is removed, and the values stored in the 8 bpp
1928 * image are from the colormap.
1929 * - If pixs does not have a colormap, the input values are
1930 * used to populate the 8 bpp image.
1931 */
1932 PIX *
pixConvert2To8(PIX * pixs,l_uint8 val0,l_uint8 val1,l_uint8 val2,l_uint8 val3,l_int32 cmapflag)1933 pixConvert2To8(PIX *pixs,
1934 l_uint8 val0,
1935 l_uint8 val1,
1936 l_uint8 val2,
1937 l_uint8 val3,
1938 l_int32 cmapflag)
1939 {
1940 l_int32 w, h, i, j, nbytes, wpls, wpld, dibit, ncolor;
1941 l_int32 rval, gval, bval, byte;
1942 l_uint8 val[4];
1943 l_uint32 index;
1944 l_uint32 *tab, *datas, *datad, *lines, *lined;
1945 PIX *pixd;
1946 PIXCMAP *cmaps, *cmapd;
1947
1948 PROCNAME("pixConvert2To8");
1949
1950 if (!pixs)
1951 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1952 if (pixGetDepth(pixs) != 2)
1953 return (PIX *)ERROR_PTR("pixs not 2 bpp", procName, NULL);
1954
1955 cmaps = pixGetColormap(pixs);
1956 if (cmaps && cmapflag == FALSE)
1957 return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
1958
1959 pixGetDimensions(pixs, &w, &h, NULL);
1960 if ((pixd = pixCreate(w, h, 8)) == NULL)
1961 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1962 pixCopyResolution(pixd, pixs);
1963 datas = pixGetData(pixs);
1964 wpls = pixGetWpl(pixs);
1965 datad = pixGetData(pixd);
1966 wpld = pixGetWpl(pixd);
1967
1968 if (cmapflag == TRUE) { /* pixd will have a colormap */
1969 cmapd = pixcmapCreate(8); /* 8 bpp standard cmap */
1970 if (cmaps) { /* use the existing colormap from pixs */
1971 ncolor = pixcmapGetCount(cmaps);
1972 for (i = 0; i < ncolor; i++) {
1973 pixcmapGetColor(cmaps, i, &rval, &gval, &bval);
1974 pixcmapAddColor(cmapd, rval, gval, bval);
1975 }
1976 }
1977 else { /* make a colormap from the input values */
1978 pixcmapAddColor(cmapd, val0, val0, val0);
1979 pixcmapAddColor(cmapd, val1, val1, val1);
1980 pixcmapAddColor(cmapd, val2, val2, val2);
1981 pixcmapAddColor(cmapd, val3, val3, val3);
1982 }
1983 pixSetColormap(pixd, cmapd);
1984 for (i = 0; i < h; i++) {
1985 lines = datas + i * wpls;
1986 lined = datad + i * wpld;
1987 for (j = 0; j < w; j++) {
1988 dibit = GET_DATA_DIBIT(lines, j);
1989 SET_DATA_BYTE(lined, j, dibit);
1990 }
1991 }
1992 return pixd;
1993 }
1994
1995 /* Last case: no colormap in either pixs or pixd.
1996 * Use input values and build a table to convert 1 src byte
1997 * (4 src pixels) at a time */
1998 if ((tab = (l_uint32 *)CALLOC(256, sizeof(l_uint32))) == NULL)
1999 return (PIX *)ERROR_PTR("tab not made", procName, NULL);
2000 val[0] = val0;
2001 val[1] = val1;
2002 val[2] = val2;
2003 val[3] = val3;
2004 for (index = 0; index < 256; index++) {
2005 tab[index] = (val[(index >> 6) & 3] << 24) |
2006 (val[(index >> 4) & 3] << 16) |
2007 (val[(index >> 2) & 3] << 8) | val[index & 3];
2008 }
2009
2010 nbytes = (w + 3) / 4;
2011 for (i = 0; i < h; i++) {
2012 lines = datas + i * wpls;
2013 lined = datad + i * wpld;
2014 for (j = 0; j < nbytes; j++) {
2015 byte = GET_DATA_BYTE(lines, j);
2016 lined[j] = tab[byte];
2017 }
2018 }
2019
2020 FREE(tab);
2021 return pixd;
2022 }
2023
2024
2025 /*!
2026 * pixConvert4To8()
2027 *
2028 * Input: pixs (4 bpp)
2029 * cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise)
2030 * Return: pixd (8 bpp), or null on error
2031 *
2032 * Notes:
2033 * - If cmapflag is TRUE:
2034 * - pixd is made with a colormap.
2035 * - If pixs has a colormap, it is copied and the colormap
2036 * index values are placed in pixd.
2037 * - If pixs does not have a colormap, a colormap with linear
2038 * trc is built and the pixel values in pixs are placed in
2039 * pixd as colormap index values.
2040 * - If cmapflag is FALSE:
2041 * - pixd is made without a colormap.
2042 * - If pixs has a colormap, it is removed and the values stored
2043 * in pixd are from the colormap (converted to gray).
2044 * - If pixs does not have a colormap, the pixel values in pixs
2045 * are used, with shift replication, to populate pixd.
2046 */
2047 PIX *
pixConvert4To8(PIX * pixs,l_int32 cmapflag)2048 pixConvert4To8(PIX *pixs,
2049 l_int32 cmapflag)
2050 {
2051 l_int32 w, h, i, j, wpls, wpld, ncolor;
2052 l_int32 rval, gval, bval, byte, qbit;
2053 l_uint32 *datas, *datad, *lines, *lined;
2054 PIX *pixd;
2055 PIXCMAP *cmaps, *cmapd;
2056
2057 PROCNAME("pixConvert4To8");
2058
2059 if (!pixs)
2060 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2061 if (pixGetDepth(pixs) != 4)
2062 return (PIX *)ERROR_PTR("pixs not 4 bpp", procName, NULL);
2063
2064 cmaps = pixGetColormap(pixs);
2065 if (cmaps && cmapflag == FALSE)
2066 return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
2067
2068 pixGetDimensions(pixs, &w, &h, NULL);
2069 if ((pixd = pixCreate(w, h, 8)) == NULL)
2070 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2071 pixCopyResolution(pixd, pixs);
2072 datas = pixGetData(pixs);
2073 wpls = pixGetWpl(pixs);
2074 datad = pixGetData(pixd);
2075 wpld = pixGetWpl(pixd);
2076
2077 if (cmapflag == TRUE) { /* pixd will have a colormap */
2078 cmapd = pixcmapCreate(8);
2079 if (cmaps) { /* use the existing colormap from pixs */
2080 ncolor = pixcmapGetCount(cmaps);
2081 for (i = 0; i < ncolor; i++) {
2082 pixcmapGetColor(cmaps, i, &rval, &gval, &bval);
2083 pixcmapAddColor(cmapd, rval, gval, bval);
2084 }
2085 }
2086 else { /* make a colormap with a linear trc */
2087 for (i = 0; i < 16; i++)
2088 pixcmapAddColor(cmapd, 17 * i, 17 * i, 17 * i);
2089 }
2090 pixSetColormap(pixd, cmapd);
2091 for (i = 0; i < h; i++) {
2092 lines = datas + i * wpls;
2093 lined = datad + i * wpld;
2094 for (j = 0; j < w; j++) {
2095 qbit = GET_DATA_QBIT(lines, j);
2096 SET_DATA_BYTE(lined, j, qbit);
2097 }
2098 }
2099 return pixd;
2100 }
2101
2102 /* Last case: no colormap in either pixs or pixd.
2103 * Replicate the qbit value into 8 bits. */
2104 for (i = 0; i < h; i++) {
2105 lines = datas + i * wpls;
2106 lined = datad + i * wpld;
2107 for (j = 0; j < w; j++) {
2108 qbit = GET_DATA_QBIT(lines, j);
2109 byte = (qbit << 4) | qbit;
2110 SET_DATA_BYTE(lined, j, byte);
2111 }
2112 }
2113 return pixd;
2114 }
2115
2116
2117
2118 /*---------------------------------------------------------------------------*
2119 * Unpacking conversion from 8 bpp to 16 bpp *
2120 *---------------------------------------------------------------------------*/
2121 /*!
2122 * pixConvert8To16()
2123 *
2124 * Input: pixs (8 bpp; colormap removed to gray)
2125 * leftshift (number of bits: 0 is no shift;
2126 * 8 replicates in MSB and LSB of dest)
2127 * Return: pixd (16 bpp), or null on error
2128 *
2129 * Notes:
2130 * (1) For left shift of 8, the 8 bit value is replicated in both
2131 * the MSB and the LSB of the pixels in pixd. That way, we get
2132 * proportional mapping, with a correct map from 8 bpp white
2133 * (0xff) to 16 bpp white (0xffff).
2134 */
2135 PIX *
pixConvert8To16(PIX * pixs,l_int32 leftshift)2136 pixConvert8To16(PIX *pixs,
2137 l_int32 leftshift)
2138 {
2139 l_int32 i, j, w, h, d, wplt, wpld, val;
2140 l_uint32 *datat, *datad, *linet, *lined;
2141 PIX *pixt, *pixd;
2142
2143 PROCNAME("pixConvert8To16");
2144
2145 if (!pixs)
2146 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2147 pixGetDimensions(pixs, &w, &h, &d);
2148 if (d != 8)
2149 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
2150 if (leftshift < 0 || leftshift > 8)
2151 return (PIX *)ERROR_PTR("leftshift not in [0 ... 8]", procName, NULL);
2152
2153 if (pixGetColormap(pixs) != NULL)
2154 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
2155 else
2156 pixt = pixClone(pixs);
2157
2158 pixd = pixCreate(w, h, 16);
2159 datat = pixGetData(pixt);
2160 datad = pixGetData(pixd);
2161 wplt = pixGetWpl(pixt);
2162 wpld = pixGetWpl(pixd);
2163 for (i = 0; i < h; i++) {
2164 linet = datat + i * wplt;
2165 lined = datad + i * wpld;
2166 for (j = 0; j < w; j++) {
2167 val = GET_DATA_BYTE(linet, j);
2168 if (leftshift == 8)
2169 val = val | (val << leftshift);
2170 else
2171 val <<= leftshift;
2172 SET_DATA_TWO_BYTES(lined, j, val);
2173 }
2174 }
2175
2176 pixDestroy(&pixt);
2177 return pixd;
2178 }
2179
2180
2181
2182 /*---------------------------------------------------------------------------*
2183 * Top-level conversion to 1 bpp *
2184 *---------------------------------------------------------------------------*/
2185 /*!
2186 * pixConvertTo1()
2187 *
2188 * Input: pixs (1, 2, 4, 8, 16 or 32 bpp)
2189 * threshold (for final binarization, relative to 8 bpp)
2190 * Return: pixd (1 bpp), or null on error
2191 *
2192 * Notes:
2193 * (1) This is a top-level function, with simple default values
2194 * used in pixConvertTo8() if unpacking is necessary.
2195 * (2) Any existing colormap is removed.
2196 * (3) If the input image has 1 bpp and no colormap, the operation is
2197 * lossless and a copy is returned.
2198 */
2199 PIX *
pixConvertTo1(PIX * pixs,l_int32 threshold)2200 pixConvertTo1(PIX *pixs,
2201 l_int32 threshold)
2202 {
2203 l_int32 d, color0, color1, rval, gval, bval;
2204 PIX *pixg, *pixd;
2205 PIXCMAP *cmap;
2206
2207 PROCNAME("pixConvertTo1");
2208
2209 if (!pixs)
2210 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2211 d = pixGetDepth(pixs);
2212 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
2213 return (PIX *)ERROR_PTR("depth not {1,2,4,8,16,32}", procName, NULL);
2214
2215 cmap = pixGetColormap(pixs);
2216 if (d == 1) {
2217 if (!cmap)
2218 return pixCopy(NULL, pixs);
2219 else { /* strip the colormap off, and invert if reasonable
2220 for standard binary photometry. */
2221 pixcmapGetColor(cmap, 0, &rval, &gval, &bval);
2222 color0 = rval + gval + bval;
2223 pixcmapGetColor(cmap, 1, &rval, &gval, &bval);
2224 color1 = rval + gval + bval;
2225 pixd = pixCopy(NULL, pixs);
2226 pixDestroyColormap(pixd);
2227 if (color1 > color0)
2228 pixInvert(pixd, pixd);
2229 return pixd;
2230 }
2231 }
2232
2233 /* For all other depths, use 8 bpp as an intermediary */
2234 pixg = pixConvertTo8(pixs, FALSE);
2235 pixd = pixThresholdToBinary(pixg, threshold);
2236 pixDestroy(&pixg);
2237 return pixd;
2238 }
2239
2240
2241 /*!
2242 * pixConvertTo1BySampling()
2243 *
2244 * Input: pixs (1, 2, 4, 8, 16 or 32 bpp)
2245 * factor (submsampling factor; integer >= 1)
2246 * threshold (for final binarization, relative to 8 bpp)
2247 * Return: pixd (1 bpp), or null on error
2248 *
2249 * Notes:
2250 * (1) This is a fast, quick/dirty, top-level converter.
2251 * (2) See pixConvertTo1() for default values.
2252 */
2253 PIX *
pixConvertTo1BySampling(PIX * pixs,l_int32 factor,l_int32 threshold)2254 pixConvertTo1BySampling(PIX *pixs,
2255 l_int32 factor,
2256 l_int32 threshold)
2257 {
2258 l_float32 scalefactor;
2259 PIX *pixt, *pixd;
2260
2261 PROCNAME("pixConvertTo1BySampling");
2262
2263 if (!pixs)
2264 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2265 if (factor < 1)
2266 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
2267
2268 scalefactor = 1. / (l_float32)factor;
2269 pixt = pixScaleBySampling(pixs, scalefactor, scalefactor);
2270 pixd = pixConvertTo1(pixt, threshold);
2271
2272 pixDestroy(&pixt);
2273 return pixd;
2274 }
2275
2276
2277 /*---------------------------------------------------------------------------*
2278 * Top-level conversion to 8 bpp *
2279 *---------------------------------------------------------------------------*/
2280 /*!
2281 * pixConvertTo8()
2282 *
2283 * Input: pixs (1, 2, 4, 8, 16 or 32 bpp)
2284 * cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise)
2285 * Return: pixd (8 bpp), or null on error
2286 *
2287 * Notes:
2288 * (1) This is a top-level function, with simple default values
2289 * for unpacking.
2290 * (2) The result, pixd, is made with a colormap if specified.
2291 * (3) If d == 8, and cmapflag matches the existence of a cmap
2292 * in pixs, the operation is lossless and it returns a copy.
2293 * (4) The default values used are:
2294 * - 1 bpp: val0 = 255, val1 = 0
2295 * - 2 bpp: 4 bpp: even increments over dynamic range
2296 * - 8 bpp: lossless if cmap matches cmapflag
2297 * - 16 bpp: use most significant byte
2298 * (5) If 32 bpp RGB, this is converted to gray. If you want
2299 * to do color quantization, you must specify the type
2300 * explicitly, using the color quantization code.
2301 */
2302 PIX *
pixConvertTo8(PIX * pixs,l_int32 cmapflag)2303 pixConvertTo8(PIX *pixs,
2304 l_int32 cmapflag)
2305 {
2306 l_int32 d;
2307 PIX *pixd;
2308 PIXCMAP *cmap;
2309
2310 PROCNAME("pixConvertTo8");
2311
2312 if (!pixs)
2313 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2314 d = pixGetDepth(pixs);
2315 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
2316 return (PIX *)ERROR_PTR("depth not {1,2,4,8,16,32}", procName, NULL);
2317
2318 if (d == 1) {
2319 if (!cmapflag)
2320 return pixConvert1To8(NULL, pixs, 255, 0);
2321 else {
2322 pixd = pixConvert1To8(NULL, pixs, 0, 1);
2323 cmap = pixcmapCreate(8);
2324 pixcmapAddColor(cmap, 255, 255, 255);
2325 pixcmapAddColor(cmap, 0, 0, 0);
2326 pixSetColormap(pixd, cmap);
2327 return pixd;
2328 }
2329 }
2330 else if (d == 2)
2331 return pixConvert2To8(pixs, 0, 85, 170, 255, cmapflag);
2332 else if (d == 4)
2333 return pixConvert4To8(pixs, cmapflag);
2334 else if (d == 8) {
2335 cmap = pixGetColormap(pixs);
2336 if ((cmap && cmapflag) || (!cmap && !cmapflag))
2337 return pixCopy(NULL, pixs);
2338 else if (cmap) /* !cmapflag */
2339 return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
2340 else { /* !cmap && cmapflag; add colormap to pixd */
2341 pixd = pixCopy(NULL, pixs);
2342 pixAddGrayColormap8(pixd);
2343 return pixd;
2344 }
2345 }
2346 else if (d == 16) {
2347 pixd = pixConvert16To8(pixs, 1);
2348 if (cmapflag)
2349 pixAddGrayColormap8(pixd);
2350 return pixd;
2351 }
2352 else { /* d == 32 */
2353 pixd = pixConvertRGBToLuminance(pixs);
2354 if (cmapflag)
2355 pixAddGrayColormap8(pixd);
2356 return pixd;
2357 }
2358 }
2359
2360
2361 /*!
2362 * pixConvertTo8BySampling()
2363 *
2364 * Input: pixs (1, 2, 4, 8, 16 or 32 bpp)
2365 * factor (submsampling factor; integer >= 1)
2366 * cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise)
2367 * Return: pixd (8 bpp), or null on error
2368 *
2369 * Notes:
2370 * (1) This is a fast, quick/dirty, top-level converter.
2371 * (2) See pixConvertTo8() for default values.
2372 */
2373 PIX *
pixConvertTo8BySampling(PIX * pixs,l_int32 factor,l_int32 cmapflag)2374 pixConvertTo8BySampling(PIX *pixs,
2375 l_int32 factor,
2376 l_int32 cmapflag)
2377 {
2378 l_float32 scalefactor;
2379 PIX *pixt, *pixd;
2380
2381 PROCNAME("pixConvertTo8BySampling");
2382
2383 if (!pixs)
2384 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2385 if (factor < 1)
2386 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
2387
2388 scalefactor = 1. / (l_float32)factor;
2389 pixt = pixScaleBySampling(pixs, scalefactor, scalefactor);
2390 pixd = pixConvertTo8(pixt, cmapflag);
2391
2392 pixDestroy(&pixt);
2393 return pixd;
2394 }
2395
2396
2397 /*---------------------------------------------------------------------------*
2398 * Top-level conversion to 16 bpp *
2399 *---------------------------------------------------------------------------*/
2400 /*!
2401 * pixConvertTo16()
2402 *
2403 * Input: pixs (1, 8 bpp)
2404 * Return: pixd (16 bpp), or null on error
2405 *
2406 * Usage: Top-level function, with simple default values for unpacking.
2407 * 1 bpp: val0 = 0xffff, val1 = 0
2408 * 8 bpp: replicates the 8 bit value in both the MSB and LSB
2409 * of the 16 bit pixel.
2410 */
2411 PIX *
pixConvertTo16(PIX * pixs)2412 pixConvertTo16(PIX *pixs)
2413 {
2414 l_int32 d;
2415
2416 PROCNAME("pixConvertTo16");
2417
2418 if (!pixs)
2419 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2420
2421 d = pixGetDepth(pixs);
2422 if (d == 1)
2423 return pixConvert1To16(NULL, pixs, 0xffff, 0);
2424 else if (d == 8)
2425 return pixConvert8To16(pixs, 8);
2426 else
2427 return (PIX *)ERROR_PTR("src depth not 1 or 8 bpp", procName, NULL);
2428 }
2429
2430
2431
2432 /*---------------------------------------------------------------------------*
2433 * Top-level conversion to 32 bpp *
2434 *---------------------------------------------------------------------------*/
2435 /*!
2436 * pixConvertTo32()
2437 *
2438 * Input: pixs (1, 2, 4, 8, 16 or 32 bpp)
2439 * Return: pixd (32 bpp), or null on error
2440 *
2441 * Usage: Top-level function, with simple default values for unpacking.
2442 * 1 bpp: val0 = 255, val1 = 0
2443 * and then replication into R, G and B components
2444 * 2 bpp: if colormapped, use the colormap values; otherwise,
2445 * use val0 = 0, val1 = 0x55, val2 = 0xaa, val3 = 255
2446 * and replicate gray into R, G and B components
2447 * 4 bpp: if colormapped, use the colormap values; otherwise,
2448 * replicate 2 nybs into a byte, and then into R,G,B components
2449 * 8 bpp: if colormapped, use the colormap values; otherwise,
2450 * replicate gray values into R, G and B components
2451 * 16 bpp: replicate MSB into R, G and B components
2452 * 32 bpp: makes a copy
2453 *
2454 * Notes:
2455 * (1) Implicit assumption about RGB component ordering.
2456 */
2457 PIX *
pixConvertTo32(PIX * pixs)2458 pixConvertTo32(PIX *pixs)
2459 {
2460 l_int32 d;
2461 PIX *pixt, *pixd;
2462
2463 PROCNAME("pixConvertTo32");
2464
2465 if (!pixs)
2466 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2467
2468 d = pixGetDepth(pixs);
2469 if (d == 1)
2470 return pixConvert1To32(NULL, pixs, 0xffffffff, 0);
2471 else if (d == 2) {
2472 pixt = pixConvert2To8(pixs, 0, 85, 170, 255, TRUE);
2473 pixd = pixConvert8To32(pixt);
2474 pixDestroy(&pixt);
2475 return pixd;
2476 }
2477 else if (d == 4) {
2478 pixt = pixConvert4To8(pixs, TRUE);
2479 pixd = pixConvert8To32(pixt);
2480 pixDestroy(&pixt);
2481 return pixd;
2482 }
2483 else if (d == 8)
2484 return pixConvert8To32(pixs);
2485 else if (d == 16) {
2486 pixt = pixConvert16To8(pixs, 1);
2487 pixd = pixConvert8To32(pixt);
2488 pixDestroy(&pixt);
2489 return pixd;
2490 }
2491 else if (d == 32)
2492 return pixCopy(NULL, pixs);
2493 else
2494 return (PIX *)ERROR_PTR("depth not 1, 2, 4, 8, 16, 32 bpp",
2495 procName, NULL);
2496 }
2497
2498
2499 /*!
2500 * pixConvertTo32BySampling()
2501 *
2502 * Input: pixs (1, 2, 4, 8, 16 or 32 bpp)
2503 * factor (submsampling factor; integer >= 1)
2504 * Return: pixd (32 bpp), or null on error
2505 *
2506 * Notes:
2507 * (1) This is a fast, quick/dirty, top-level converter.
2508 * (2) See pixConvertTo32() for default values.
2509 */
2510 PIX *
pixConvertTo32BySampling(PIX * pixs,l_int32 factor)2511 pixConvertTo32BySampling(PIX *pixs,
2512 l_int32 factor)
2513 {
2514 l_float32 scalefactor;
2515 PIX *pixt, *pixd;
2516
2517 PROCNAME("pixConvertTo32BySampling");
2518
2519 if (!pixs)
2520 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2521 if (factor < 1)
2522 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
2523
2524 scalefactor = 1. / (l_float32)factor;
2525 pixt = pixScaleBySampling(pixs, scalefactor, scalefactor);
2526 pixd = pixConvertTo32(pixt);
2527
2528 pixDestroy(&pixt);
2529 return pixd;
2530 }
2531
2532
2533 /*!
2534 * pixConvert8To32()
2535 *
2536 * Input: pix (8 bpp)
2537 * Return: 32 bpp rgb pix, or null on error
2538 *
2539 * Notes:
2540 * (1) If there is no colormap, replicates the gray value
2541 * into the 3 MSB of the dest pixel.
2542 * (2) Implicit assumption about RGB component ordering.
2543 */
2544 PIX *
pixConvert8To32(PIX * pixs)2545 pixConvert8To32(PIX *pixs)
2546 {
2547 l_int32 i, j, w, h, wpls, wpld, val;
2548 l_uint32 *datas, *datad, *lines, *lined;
2549 l_uint32 *tab;
2550 PIX *pixd;
2551
2552 PROCNAME("pixConvert8To32");
2553
2554 if (!pixs)
2555 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2556 if (pixGetDepth(pixs) != 8)
2557 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
2558
2559 if (pixGetColormap(pixs))
2560 return pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
2561
2562 /* Replication table */
2563 if ((tab = (l_uint32 *)CALLOC(256, sizeof(l_uint32))) == NULL)
2564 return (PIX *)ERROR_PTR("tab not made", procName, NULL);
2565 for (i = 0; i < 256; i++)
2566 tab[i] = (i << 24) | (i << 16) | (i << 8);
2567
2568 pixGetDimensions(pixs, &w, &h, NULL);
2569 datas = pixGetData(pixs);
2570 wpls = pixGetWpl(pixs);
2571 if ((pixd = pixCreate(w, h, 32)) == NULL)
2572 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2573 pixCopyResolution(pixd, pixs);
2574 datad = pixGetData(pixd);
2575 wpld = pixGetWpl(pixd);
2576
2577 for (i = 0; i < h; i++) {
2578 lines = datas + i * wpls;
2579 lined = datad + i * wpld;
2580 for (j = 0; j < w; j++) {
2581 val = GET_DATA_BYTE(lines, j);
2582 lined[j] = tab[val];
2583 }
2584 }
2585
2586 FREE(tab);
2587 return pixd;
2588 }
2589
2590
2591 /*---------------------------------------------------------------------------*
2592 * Top-level conversion to 8 or 32 bpp, without colormap *
2593 *---------------------------------------------------------------------------*/
2594 /*!
2595 * pixConvertTo8Or32()
2596 *
2597 * Input: pixs (1, 2, 4, 8, 16, with or without colormap; or 32 bpp rgb)
2598 * copyflag (use 0 to return clone if pixs does not need to
2599 * be changed; 1 to return a copy in those situations)
2600 * warnflag (1 to issue warning if colormap is removed; else 0)
2601 * Return: pixd (8 bpp grayscale or 32 bpp rgb), or null on error
2602 *
2603 * Notes:
2604 * (1) If there is a colormap, the colormap is removed to 8 or 32 bpp,
2605 * depending on whether the colors in the colormap are all gray.
2606 * (2) If the input is either rgb or 8 bpp without a colormap,
2607 * this returns either a clone or a copy, depending on @copyflag.
2608 * (3) Otherwise, the pix is converted to 8 bpp grayscale.
2609 * In all cases, pixd does not have a colormap.
2610 */
2611 PIX *
pixConvertTo8Or32(PIX * pixs,l_int32 copyflag,l_int32 warnflag)2612 pixConvertTo8Or32(PIX *pixs,
2613 l_int32 copyflag,
2614 l_int32 warnflag)
2615 {
2616 l_int32 d;
2617 PIX *pixd;
2618
2619 PROCNAME("pixConvertTo8Or32");
2620
2621 if (!pixs)
2622 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2623
2624 d = pixGetDepth(pixs);
2625 if (pixGetColormap(pixs)) {
2626 if (warnflag) L_WARNING("pix has colormap; removing", procName);
2627 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
2628 }
2629 else if (d == 8 || d == 32) {
2630 if (copyflag == 0)
2631 pixd = pixClone(pixs);
2632 else
2633 pixd = pixCopy(NULL, pixs);
2634 }
2635 else
2636 pixd = pixConvertTo8(pixs, 0);
2637
2638 /* Sanity check on result */
2639 d = pixGetDepth(pixd);
2640 if (d != 8 && d != 32) {
2641 pixDestroy(&pixd);
2642 return (PIX *)ERROR_PTR("depth not 8 or 32 bpp", procName, NULL);
2643 }
2644
2645 return pixd;
2646 }
2647
2648
2649 /*---------------------------------------------------------------------------*
2650 * Lossless depth conversion (unpacking) *
2651 *---------------------------------------------------------------------------*/
2652 /*!
2653 * pixConvertLossless()
2654 *
2655 * Input: pixs (1, 2, 4, 8 bpp, not cmapped)
2656 * d (destination depth: 2, 4 or 8)
2657 * Return: pixd (2, 4 or 8 bpp), or null on error
2658 *
2659 * Notes:
2660 * (1) This is a lossless unpacking (depth-increasing)
2661 * conversion. If ds is the depth of pixs, then
2662 * - if d < ds, returns NULL
2663 * - if d == ds, returns a copy
2664 * - if d > ds, does the unpacking conversion
2665 * (2) If pixs has a colormap, this is an error.
2666 */
2667 PIX *
pixConvertLossless(PIX * pixs,l_int32 d)2668 pixConvertLossless(PIX *pixs,
2669 l_int32 d)
2670 {
2671 l_int32 w, h, ds, wpls, wpld, i, j, val;
2672 l_uint32 *datas, *datad, *lines, *lined;
2673 PIX *pixd;
2674
2675 PROCNAME("pixConvertLossless");
2676
2677 if (!pixs)
2678 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2679 if (pixGetColormap(pixs))
2680 return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
2681 if (d != 2 && d != 4 && d != 8)
2682 return (PIX *)ERROR_PTR("invalid dest depth", procName, NULL);
2683
2684 pixGetDimensions(pixs, &w, &h, &ds);
2685 if (d < ds)
2686 return (PIX *)ERROR_PTR("depth > d", procName, NULL);
2687 else if (d == ds)
2688 return pixCopy(NULL, pixs);
2689
2690 if ((pixd = pixCreate(w, h, d)) == NULL)
2691 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2692 pixCopyResolution(pixd, pixs);
2693
2694 /* Unpack the bits */
2695 datas = pixGetData(pixs);
2696 wpls = pixGetWpl(pixs);
2697 datad = pixGetData(pixd);
2698 wpld = pixGetWpl(pixd);
2699 for (i = 0; i < h; i++) {
2700 lines = datas + i * wpls;
2701 lined = datad + i * wpld;
2702 switch (ds)
2703 {
2704 case 1:
2705 for (j = 0; j < w; j++) {
2706 val = GET_DATA_BIT(lines, j);
2707 if (d == 8)
2708 SET_DATA_BYTE(lined, j, val);
2709 else if (d == 4)
2710 SET_DATA_QBIT(lined, j, val);
2711 else /* d == 2 */
2712 SET_DATA_DIBIT(lined, j, val);
2713 }
2714 break;
2715 case 2:
2716 for (j = 0; j < w; j++) {
2717 val = GET_DATA_DIBIT(lines, j);
2718 if (d == 8)
2719 SET_DATA_BYTE(lined, j, val);
2720 else /* d == 4 */
2721 SET_DATA_QBIT(lined, j, val);
2722 }
2723 case 4:
2724 for (j = 0; j < w; j++) {
2725 val = GET_DATA_DIBIT(lines, j);
2726 SET_DATA_BYTE(lined, j, val);
2727 }
2728 break;
2729 }
2730 }
2731
2732 return pixd;
2733 }
2734
2735
2736 /*---------------------------------------------------------------------------*
2737 * Conversion for printing in PostScript *
2738 *---------------------------------------------------------------------------*/
2739 /*!
2740 * pixConvertForPSWrap()
2741 *
2742 * Input: pixs (1, 2, 4, 8, 16, 32 bpp)
2743 * Return: pixd (1, 8, or 32 bpp), or null on error
2744 *
2745 * Notes:
2746 * (1) For wrapping in PostScript, we convert pixs to
2747 * 1 bpp, 8 bpp (gray) and 32 bpp (RGB color).
2748 * (2) Colormaps are removed. For pixs with colormaps, the
2749 * images are converted to either 8 bpp gray or 32 bpp
2750 * RGB, depending on whether the colormap has color content.
2751 * (3) Images without colormaps, that are not 1 bpp or 32 bpp,
2752 * are converted to 8 bpp gray.
2753 */
2754 PIX *
pixConvertForPSWrap(PIX * pixs)2755 pixConvertForPSWrap(PIX *pixs)
2756 {
2757 l_int32 d;
2758 PIX *pixd;
2759 PIXCMAP *cmap;
2760
2761 PROCNAME("pixConvertForPSWrap");
2762
2763 if (!pixs)
2764 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2765
2766 cmap = pixGetColormap(pixs);
2767 d = pixGetDepth(pixs);
2768 switch (d)
2769 {
2770 case 1:
2771 case 32:
2772 pixd = pixClone(pixs);
2773 break;
2774 case 2:
2775 if (cmap)
2776 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
2777 else
2778 pixd = pixConvert2To8(pixs, 0, 0x55, 0xaa, 0xff, FALSE);
2779 break;
2780 case 4:
2781 if (cmap)
2782 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
2783 else
2784 pixd = pixConvert4To8(pixs, FALSE);
2785 break;
2786 case 8:
2787 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
2788 break;
2789 case 16:
2790 pixd = pixConvert16To8(pixs, 1);
2791 break;
2792 default:
2793 fprintf(stderr, "depth not in {1, 2, 4, 8, 16, 32}");
2794 return NULL;
2795 }
2796
2797 return pixd;
2798 }
2799
2800
2801 /*---------------------------------------------------------------------------*
2802 * Colorspace conversion between RGB and HSB *
2803 *---------------------------------------------------------------------------*/
2804 /*!
2805 * pixConvertRGBToHSV()
2806 *
2807 * Input: pixd (can be NULL; if not NULL, must == pixs)
2808 * pixs
2809 * Return: pixd always
2810 *
2811 * Notes:
2812 * (1) For pixs = pixd, this is in-place; otherwise pixd must be NULL.
2813 * (2) The definition of our HSV space is given in convertRGBToHSV().
2814 * (3) The h, s and v values are stored in the same places as
2815 * the r, g and b values, respectively. Here, they are explicitly
2816 * placed in the 3 MS bytes in the pixel.
2817 * (4) Normalizing to 1 and considering the r,g,b components,
2818 * a simple way to understand the HSV space is:
2819 * - v = max(r,g,b)
2820 * - s = (max - min) / max
2821 * - h ~ (mid - min) / (max - min) [apart from signs and constants]
2822 * (5) Normalizing to 1, some properties of the HSV space are:
2823 * - For gray values (r = g = b) along the continuum between
2824 * black and white:
2825 * s = 0 (becoming undefined as you approach black)
2826 * h is undefined everywhere
2827 * - Where one component is saturated and the others are zero:
2828 * v = 1
2829 * s = 1
2830 * h = 0 (r = max), 1/3 (g = max), 2/3 (b = max)
2831 * - Where two components are saturated and the other is zero:
2832 * v = 1
2833 * s = 1
2834 * h = 1/2 (if r = 0), 5/6 (if g = 0), 1/6 (if b = 0)
2835 */
2836 PIX *
pixConvertRGBToHSV(PIX * pixd,PIX * pixs)2837 pixConvertRGBToHSV(PIX *pixd,
2838 PIX *pixs)
2839 {
2840 l_int32 w, h, d, wpl, i, j, rval, gval, bval, hval, sval, vval;
2841 l_uint32 pixel;
2842 l_uint32 *line, *data;
2843 PIXCMAP *cmap;
2844
2845 PROCNAME("pixConvertRGBToHSV");
2846
2847 if (!pixs)
2848 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
2849 if (pixd && pixd != pixs)
2850 return (PIX *)ERROR_PTR("pixd defined and not inplace", procName, pixd);
2851
2852 d = pixGetDepth(pixs);
2853 cmap = pixGetColormap(pixs);
2854 if (!cmap && d != 32)
2855 return (PIX *)ERROR_PTR("not cmapped or rgb", procName, pixd);
2856
2857 if (!pixd)
2858 pixd = pixCopy(NULL, pixs);
2859
2860 cmap = pixGetColormap(pixd);
2861 if (cmap) { /* just convert the colormap */
2862 pixcmapConvertRGBToHSV(cmap);
2863 return pixd;
2864 }
2865
2866 /* Convert RGB image */
2867 pixGetDimensions(pixd, &w, &h, NULL);
2868 wpl = pixGetWpl(pixd);
2869 data = pixGetData(pixd);
2870 for (i = 0; i < h; i++) {
2871 line = data + i * wpl;
2872 for (j = 0; j < w; j++) {
2873 pixel = line[j];
2874 extractRGBValues(pixel, &rval, &gval, &bval);
2875 convertRGBToHSV(rval, gval, bval, &hval, &sval, &vval);
2876 line[j] = (hval << 24) | (sval << 16) | (vval << 8);
2877 }
2878 }
2879
2880 return pixd;
2881 }
2882
2883
2884 /*!
2885 * pixConvertHSVToRGB()
2886 *
2887 * Input: pixd (can be NULL; if not NULL, must == pixs)
2888 * pixs
2889 * Return: pixd always
2890 *
2891 * Notes:
2892 * (1) For pixs = pixd, this is in-place; otherwise pixd must be NULL.
2893 * (2) The user takes responsibility for making sure that pixs is
2894 * in our HSV space. The definition of our HSV space is given
2895 * in convertRGBToHSV().
2896 * (3) The h, s and v values are stored in the same places as
2897 * the r, g and b values, respectively. Here, they are explicitly
2898 * placed in the 3 MS bytes in the pixel.
2899 */
2900 PIX *
pixConvertHSVToRGB(PIX * pixd,PIX * pixs)2901 pixConvertHSVToRGB(PIX *pixd,
2902 PIX *pixs)
2903 {
2904 l_int32 w, h, d, wpl, i, j, rval, gval, bval, hval, sval, vval;
2905 l_uint32 pixel;
2906 l_uint32 *line, *data;
2907 PIXCMAP *cmap;
2908
2909 PROCNAME("pixConvertHSVToRGB");
2910
2911 if (!pixs)
2912 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
2913 if (pixd && pixd != pixs)
2914 return (PIX *)ERROR_PTR("pixd defined and not inplace", procName, pixd);
2915
2916 d = pixGetDepth(pixs);
2917 cmap = pixGetColormap(pixs);
2918 if (!cmap && d != 32)
2919 return (PIX *)ERROR_PTR("not cmapped or hsv", procName, pixd);
2920
2921 if (!pixd)
2922 pixd = pixCopy(NULL, pixs);
2923
2924 cmap = pixGetColormap(pixd);
2925 if (cmap) { /* just convert the colormap */
2926 pixcmapConvertHSVToRGB(cmap);
2927 return pixd;
2928 }
2929
2930 /* Convert HSV image */
2931 pixGetDimensions(pixd, &w, &h, NULL);
2932 wpl = pixGetWpl(pixd);
2933 data = pixGetData(pixd);
2934 for (i = 0; i < h; i++) {
2935 line = data + i * wpl;
2936 for (j = 0; j < w; j++) {
2937 pixel = line[j];
2938 hval = pixel >> 24;
2939 sval = (pixel >> 16) & 0xff;
2940 vval = (pixel >> 8) & 0xff;
2941 convertHSVToRGB(hval, sval, vval, &rval, &gval, &bval);
2942 composeRGBPixel(rval, gval, bval, line + j);
2943 }
2944 }
2945
2946 return pixd;
2947 }
2948
2949
2950 /*!
2951 * convertRGBToHSV()
2952 *
2953 * Input: rval, gval, bval (RGB input)
2954 * &hval, &sval, &vval (<return> HSV values)
2955 * Return: 0 if OK, 1 on error
2956 *
2957 * Notes:
2958 * (1) The range of returned values is:
2959 * h [0 ... 239]
2960 * s [0 ... 255]
2961 * v [0 ... 255]
2962 * (2) If r = g = b, the pixel is gray (s = 0), and we define h = 0.
2963 * (3) h wraps around, so that h = 0 and h = 240 are equivalent
2964 * in hue space.
2965 * (4) h has the following correspondence to color:
2966 * h = 0 magenta
2967 * h = 40 red
2968 * h = 80 yellow
2969 * h = 120 green
2970 * h = 160 cyan
2971 * h = 200 blue
2972 */
2973 l_int32
convertRGBToHSV(l_int32 rval,l_int32 gval,l_int32 bval,l_int32 * phval,l_int32 * psval,l_int32 * pvval)2974 convertRGBToHSV(l_int32 rval,
2975 l_int32 gval,
2976 l_int32 bval,
2977 l_int32 *phval,
2978 l_int32 *psval,
2979 l_int32 *pvval)
2980 {
2981 l_int32 minrg, maxrg, min, max, delta;
2982 l_float32 h;
2983
2984 PROCNAME("convertRGBToHSV");
2985
2986 if (!phval || !psval || !pvval)
2987 return ERROR_INT("&hval, &sval, &vval not all defined", procName, 1);
2988
2989 minrg = L_MIN(rval, gval);
2990 min = L_MIN(minrg, bval);
2991 maxrg = L_MAX(rval, gval);
2992 max = L_MAX(maxrg, bval);
2993 delta = max - min;
2994
2995 *pvval = max;
2996 if (delta == 0) { /* gray; no chroma */
2997 *phval = 0;
2998 *psval = 0;
2999 }
3000 else {
3001 *psval = (l_int32)(255. * (l_float32)delta / (l_float32)max + 0.5);
3002 if (rval == max) /* between magenta and yellow */
3003 h = (l_float32)(gval - bval) / (l_float32)delta;
3004 else if (gval == max) /* between yellow and cyan */
3005 h = 2. + (l_float32)(bval - rval) / (l_float32)delta;
3006 else /* between cyan and magenta */
3007 h = 4. + (l_float32)(rval - gval) / (l_float32)delta;
3008 h *= 40.0;
3009 if (h < 0.0)
3010 h += 240.0;
3011 if (h >= 239.5)
3012 h = 0.0;
3013 *phval = (l_int32)(h + 0.5);
3014 }
3015
3016 return 0;
3017 }
3018
3019
3020 /*!
3021 * convertHSVToRGB()
3022 *
3023 * Input: hval, sval, vval
3024 * &rval, &gval, &bval (<return> RGB values)
3025 * Return: 0 if OK, 1 on error
3026 *
3027 * Notes:
3028 * (1) See convertRGBToHSV() for valid input range of HSV values
3029 * and their interpretation in color space.
3030 */
3031 l_int32
convertHSVToRGB(l_int32 hval,l_int32 sval,l_int32 vval,l_int32 * prval,l_int32 * pgval,l_int32 * pbval)3032 convertHSVToRGB(l_int32 hval,
3033 l_int32 sval,
3034 l_int32 vval,
3035 l_int32 *prval,
3036 l_int32 *pgval,
3037 l_int32 *pbval)
3038 {
3039 l_int32 i, x, y, z;
3040 l_float32 h, f, s;
3041
3042 PROCNAME("convertHSVToRGB");
3043
3044 if (!prval || !pgval || !pbval)
3045 return ERROR_INT("&rval, &gval, &bval not all defined", procName, 1);
3046
3047 if (sval == 0) { /* gray */
3048 *prval = vval;
3049 *pgval = vval;
3050 *pbval = vval;
3051 }
3052 else {
3053 if (hval < 0 || hval > 240)
3054 return ERROR_INT("invalid hval", procName, 1);
3055 if (hval == 240)
3056 hval = 0;
3057 h = (l_float32)hval / 40.;
3058 i = (l_int32)h;
3059 f = h - i;
3060 s = (l_float32)sval / 255.;
3061 x = (l_int32)(vval * (1. - s) + 0.5);
3062 y = (l_int32)(vval * (1. - s * f) + 0.5);
3063 z = (l_int32)(vval * (1. - s * (1. - f)) + 0.5);
3064 switch (i)
3065 {
3066 case 0:
3067 *prval = vval;
3068 *pgval = z;
3069 *pbval = x;
3070 break;
3071 case 1:
3072 *prval = y;
3073 *pgval = vval;
3074 *pbval = x;
3075 break;
3076 case 2:
3077 *prval = x;
3078 *pgval = vval;
3079 *pbval = z;
3080 break;
3081 case 3:
3082 *prval = x;
3083 *pgval = y;
3084 *pbval = vval;
3085 break;
3086 case 4:
3087 *prval = z;
3088 *pgval = x;
3089 *pbval = vval;
3090 break;
3091 case 5:
3092 *prval = vval;
3093 *pgval = x;
3094 *pbval = y;
3095 break;
3096 default: /* none possible */
3097 return 1;
3098 }
3099 }
3100
3101 return 0;
3102 }
3103
3104
3105 /*!
3106 * pixConvertRGBToHue()
3107 *
3108 * Input: pixs (32 bpp RGB or 8 bpp with colormap)
3109 * Return: pixd (8 bpp hue of HSV), or null on error
3110 *
3111 * Notes:
3112 * (1) The conversion to HSV hue is in-lined here.
3113 * (2) If there is a colormap, it is removed.
3114 * (3) If you just want the hue component, this does it
3115 * at about 10 Mpixels/sec/GHz, which is about
3116 * 2x faster than using pixConvertRGBToHSV()
3117 */
3118 PIX *
pixConvertRGBToHue(PIX * pixs)3119 pixConvertRGBToHue(PIX *pixs)
3120 {
3121 l_int32 w, h, d, wplt, wpld;
3122 l_int32 i, j, rval, gval, bval, hval, minrg, min, maxrg, max, delta;
3123 l_float32 fh;
3124 l_uint32 pixel;
3125 l_uint32 *linet, *lined, *datat, *datad;
3126 PIX *pixt, *pixd;
3127
3128 PROCNAME("pixConvertRGBToHue");
3129
3130 if (!pixs)
3131 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3132
3133 pixGetDimensions(pixs, &w, &h, &d);
3134 if (d != 32 && !pixGetColormap(pixs))
3135 return (PIX *)ERROR_PTR("not cmapped or rgb", procName, NULL);
3136 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
3137
3138 /* Convert RGB image */
3139 pixd = pixCreate(w, h, 8);
3140 pixCopyResolution(pixd, pixs);
3141 wplt = pixGetWpl(pixt);
3142 datat = pixGetData(pixt);
3143 wpld = pixGetWpl(pixd);
3144 datad = pixGetData(pixd);
3145 for (i = 0; i < h; i++) {
3146 linet = datat + i * wplt;
3147 lined = datad + i * wpld;
3148 for (j = 0; j < w; j++) {
3149 pixel = linet[j];
3150 extractRGBValues(pixel, &rval, &gval, &bval);
3151 minrg = L_MIN(rval, gval);
3152 min = L_MIN(minrg, bval);
3153 maxrg = L_MAX(rval, gval);
3154 max = L_MAX(maxrg, bval);
3155 delta = max - min;
3156 if (delta == 0) /* gray; no chroma */
3157 hval = 0;
3158 else {
3159 if (rval == max) /* between magenta and yellow */
3160 fh = (l_float32)(gval - bval) / (l_float32)delta;
3161 else if (gval == max) /* between yellow and cyan */
3162 fh = 2. + (l_float32)(bval - rval) / (l_float32)delta;
3163 else /* between cyan and magenta */
3164 fh = 4. + (l_float32)(rval - gval) / (l_float32)delta;
3165 fh *= 40.0;
3166 if (fh < 0.0)
3167 fh += 240.0;
3168 hval = (l_int32)(fh + 0.5);
3169 }
3170 SET_DATA_BYTE(lined, j, hval);
3171 }
3172 }
3173 pixDestroy(&pixt);
3174
3175 return pixd;
3176 }
3177
3178
3179
3180 /*!
3181 * pixConvertRGBToSaturation()
3182 *
3183 * Input: pixs (32 bpp RGB or 8 bpp with colormap)
3184 * Return: pixd (8 bpp sat of HSV), or null on error
3185 *
3186 * Notes:
3187 * (1) The conversion to HSV sat is in-lined here.
3188 * (2) If there is a colormap, it is removed.
3189 * (3) If you just want the saturation component, this does it
3190 * at about 12 Mpixels/sec/GHz.
3191 */
3192 PIX *
pixConvertRGBToSaturation(PIX * pixs)3193 pixConvertRGBToSaturation(PIX *pixs)
3194 {
3195 l_int32 w, h, d, wplt, wpld;
3196 l_int32 i, j, rval, gval, bval, sval, minrg, min, maxrg, max, delta;
3197 l_uint32 pixel;
3198 l_uint32 *linet, *lined, *datat, *datad;
3199 PIX *pixt, *pixd;
3200
3201 PROCNAME("pixConvertRGBToSaturation");
3202
3203 if (!pixs)
3204 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3205
3206 pixGetDimensions(pixs, &w, &h, &d);
3207 if (d != 32 && !pixGetColormap(pixs))
3208 return (PIX *)ERROR_PTR("not cmapped or rgb", procName, NULL);
3209 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
3210
3211 /* Convert RGB image */
3212 pixd = pixCreate(w, h, 8);
3213 pixCopyResolution(pixd, pixs);
3214 wplt = pixGetWpl(pixt);
3215 datat = pixGetData(pixt);
3216 wpld = pixGetWpl(pixd);
3217 datad = pixGetData(pixd);
3218 for (i = 0; i < h; i++) {
3219 linet = datat + i * wplt;
3220 lined = datad + i * wpld;
3221 for (j = 0; j < w; j++) {
3222 pixel = linet[j];
3223 extractRGBValues(pixel, &rval, &gval, &bval);
3224 minrg = L_MIN(rval, gval);
3225 min = L_MIN(minrg, bval);
3226 maxrg = L_MAX(rval, gval);
3227 max = L_MAX(maxrg, bval);
3228 delta = max - min;
3229 if (delta == 0) /* gray; no chroma */
3230 sval = 0;
3231 else
3232 sval = (l_int32)(255. *
3233 (l_float32)delta / (l_float32)max + 0.5);
3234 SET_DATA_BYTE(lined, j, sval);
3235 }
3236 }
3237
3238 pixDestroy(&pixt);
3239 return pixd;
3240 }
3241
3242
3243 /*!
3244 * pixConvertRGBToValue()
3245 *
3246 * Input: pixs (32 bpp RGB or 8 bpp with colormap)
3247 * Return: pixd (8 bpp max component intensity of HSV), or null on error
3248 *
3249 * Notes:
3250 * (1) The conversion to HSV sat is in-lined here.
3251 * (2) If there is a colormap, it is removed.
3252 * (3) If you just want the value component, this does it
3253 * at about 35 Mpixels/sec/GHz.
3254 */
3255 PIX *
pixConvertRGBToValue(PIX * pixs)3256 pixConvertRGBToValue(PIX *pixs)
3257 {
3258 l_int32 w, h, d, wplt, wpld;
3259 l_int32 i, j, rval, gval, bval, maxrg, max;
3260 l_uint32 pixel;
3261 l_uint32 *linet, *lined, *datat, *datad;
3262 PIX *pixt, *pixd;
3263
3264 PROCNAME("pixConvertRGBToValue");
3265
3266 if (!pixs)
3267 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
3268
3269 pixGetDimensions(pixs, &w, &h, &d);
3270 if (d != 32 && !pixGetColormap(pixs))
3271 return (PIX *)ERROR_PTR("not cmapped or rgb", procName, NULL);
3272 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
3273
3274 /* Convert RGB image */
3275 pixd = pixCreate(w, h, 8);
3276 pixCopyResolution(pixd, pixs);
3277 wplt = pixGetWpl(pixt);
3278 datat = pixGetData(pixt);
3279 wpld = pixGetWpl(pixd);
3280 datad = pixGetData(pixd);
3281 for (i = 0; i < h; i++) {
3282 linet = datat + i * wplt;
3283 lined = datad + i * wpld;
3284 for (j = 0; j < w; j++) {
3285 pixel = linet[j];
3286 extractRGBValues(pixel, &rval, &gval, &bval);
3287 maxrg = L_MAX(rval, gval);
3288 max = L_MAX(maxrg, bval);
3289 SET_DATA_BYTE(lined, j, max);
3290 }
3291 }
3292
3293 pixDestroy(&pixt);
3294 return pixd;
3295 }
3296
3297
3298
3299
3300
3301