Leptonica 1.68
C Image Processing Library
|
00001 /*====================================================================* 00002 - Copyright (C) 2001 Leptonica. All rights reserved. 00003 - This software is distributed in the hope that it will be 00004 - useful, but with NO WARRANTY OF ANY KIND. 00005 - No author or distributor accepts responsibility to anyone for the 00006 - consequences of using this software, or for whether it serves any 00007 - particular purpose or works at all, unless he or she says so in 00008 - writing. Everyone is granted permission to copy, modify and 00009 - redistribute this source code, for commercial or non-commercial 00010 - purposes, with the following restrictions: (1) the origin of this 00011 - source code must not be misrepresented; (2) modified versions must 00012 - be plainly marked as such; and (3) this notice may not be removed 00013 - or altered from any source or modified source distribution. 00014 *====================================================================*/ 00015 00016 /* 00017 * pixconv.c 00018 * 00019 * These functions convert between images of different types 00020 * without scaling. 00021 * 00022 * Conversion from 8 bpp grayscale to 1, 2, 4 and 8 bpp 00023 * PIX *pixThreshold8() 00024 * 00025 * Conversion from colormap to full color or grayscale 00026 * PIX *pixRemoveColormap() 00027 * 00028 * Add colormap losslessly (8 to 8) 00029 * l_int32 pixAddGrayColormap8() 00030 * PIX *pixAddMinimalGrayColormap8() 00031 * 00032 * Conversion from RGB color to grayscale 00033 * PIX *pixConvertRGBToLuminance() 00034 * PIX *pixConvertRGBToGray() 00035 * PIX *pixConvertRGBToGrayFast() 00036 * PIX *pixConvertRGBToGrayMinMax() 00037 * 00038 * Conversion from grayscale to colormap 00039 * PIX *pixConvertGrayToColormap() -- 2, 4, 8 bpp 00040 * PIX *pixConvertGrayToColormap8() -- 8 bpp only 00041 * 00042 * Colorizing conversion from grayscale to color 00043 * PIX *pixColorizeGray() -- 8 bpp or cmapped 00044 * 00045 * Conversion from RGB color to colormap 00046 * PIX *pixConvertRGBToColormap() 00047 * 00048 * Quantization for relatively small number of colors in source 00049 * l_int32 pixQuantizeIfFewColors() 00050 * 00051 * Conversion from 16 bpp to 8 bpp 00052 * PIX *pixConvert16To8() 00053 * 00054 * Conversion from grayscale to false color 00055 * PIX *pixConvertGrayToFalseColor() 00056 * 00057 * Unpacking conversion from 1 bpp to 2, 4, 8, 16 and 32 bpp 00058 * PIX *pixUnpackBinary() 00059 * PIX *pixConvert1To16() 00060 * PIX *pixConvert1To32() 00061 * 00062 * Unpacking conversion from 1 bpp to 2 bpp 00063 * PIX *pixConvert1To2Cmap() 00064 * PIX *pixConvert1To2() 00065 * 00066 * Unpacking conversion from 1 bpp to 4 bpp 00067 * PIX *pixConvert1To4Cmap() 00068 * PIX *pixConvert1To4() 00069 * 00070 * Unpacking conversion from 1, 2 and 4 bpp to 8 bpp 00071 * PIX *pixConvert1To8() 00072 * PIX *pixConvert2To8() 00073 * PIX *pixConvert4To8() 00074 * 00075 * Unpacking conversion from 8 bpp to 16 bpp 00076 * PIX *pixConvert8To16() 00077 * 00078 * Top-level conversion to 1 bpp 00079 * PIX *pixConvertTo1() 00080 * PIX *pixConvertTo1BySampling() 00081 * 00082 * Top-level conversion to 8 bpp 00083 * PIX *pixConvertTo8() 00084 * PIX *pixConvertTo8BySampling() 00085 * 00086 * Top-level conversion to 16 bpp 00087 * PIX *pixConvertTo16() 00088 * 00089 * Top-level conversion to 32 bpp (RGB) 00090 * PIX *pixConvertTo32() *** 00091 * PIX *pixConvertTo32BySampling() *** 00092 * PIX *pixConvert8To32() *** 00093 * 00094 * Top-level conversion to 8 or 32 bpp, without colormap 00095 * PIX *pixConvertTo8Or32 00096 * 00097 * Conversion between 24 bpp and 32 bpp rgb 00098 * PIX *pixConvert24To32() 00099 * PIX *pixConvert32To24() 00100 * 00101 * Lossless depth conversion (unpacking) 00102 * PIX *pixConvertLossless() 00103 * 00104 * Conversion for printing in PostScript 00105 * PIX *pixConvertForPSWrap() 00106 * 00107 * Scaling conversion to subpixel RGB 00108 * PIX *pixConvertToSubpixelRGB() 00109 * PIX *pixConvertGrayToSubpixelRGB() 00110 * PIX *pixConvertColorToSubpixelRGB() 00111 * 00112 * *** indicates implicit assumption about RGB component ordering 00113 */ 00114 00115 #include <string.h> 00116 #include <math.h> 00117 #include "allheaders.h" 00118 00119 #ifndef NO_CONSOLE_IO 00120 #define DEBUG_CONVERT_TO_COLORMAP 0 00121 #define DEBUG_UNROLLING 0 00122 #endif /* ~NO_CONSOLE_IO */ 00123 00124 00125 /*-------------------------------------------------------------* 00126 * Conversion from 8 bpp grayscale to 1, 2 4 and 8 bpp * 00127 *-------------------------------------------------------------*/ 00128 /*! 00129 * pixThreshold8() 00130 * 00131 * Input: pix (8 bpp grayscale) 00132 * d (destination depth: 1, 2, 4 or 8) 00133 * nlevels (number of levels to be used for colormap) 00134 * cmapflag (1 if makes colormap; 0 otherwise) 00135 * Return: pixd (thresholded with standard dest thresholds), 00136 * or null on error 00137 * 00138 * Notes: 00139 * (1) This uses, by default, equally spaced "target" values 00140 * that depend on the number of levels, with thresholds 00141 * halfway between. For N levels, with separation (N-1)/255, 00142 * there are N-1 fixed thresholds. 00143 * (2) For 1 bpp destination, the number of levels can only be 2 00144 * and if a cmap is made, black is (0,0,0) and white 00145 * is (255,255,255), which is opposite to the convention 00146 * without a colormap. 00147 * (3) For 1, 2 and 4 bpp, the nlevels arg is used if a colormap 00148 * is made; otherwise, we take the most significant bits 00149 * from the src that will fit in the dest. 00150 * (4) For 8 bpp, the input pixs is quantized to nlevels. The 00151 * dest quantized with that mapping, either through a colormap 00152 * table or directly with 8 bit values. 00153 * (5) Typically you should not use make a colormap for 1 bpp dest. 00154 * (6) This is not dithering. Each pixel is treated independently. 00155 */ 00156 PIX * 00157 pixThreshold8(PIX *pixs, 00158 l_int32 d, 00159 l_int32 nlevels, 00160 l_int32 cmapflag) 00161 { 00162 PIX *pixd; 00163 PIXCMAP *cmap; 00164 00165 PROCNAME("pixThreshold8"); 00166 00167 if (!pixs) 00168 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00169 if (pixGetDepth(pixs) != 8) 00170 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 00171 if (cmapflag && nlevels < 2) 00172 return (PIX *)ERROR_PTR("nlevels must be at least 2", procName, NULL); 00173 00174 switch (d) { 00175 case 1: 00176 pixd = pixThresholdToBinary(pixs, 128); 00177 if (cmapflag) { 00178 cmap = pixcmapCreateLinear(1, 2); 00179 pixSetColormap(pixd, cmap); 00180 } 00181 break; 00182 case 2: 00183 pixd = pixThresholdTo2bpp(pixs, nlevels, cmapflag); 00184 break; 00185 case 4: 00186 pixd = pixThresholdTo4bpp(pixs, nlevels, cmapflag); 00187 break; 00188 case 8: 00189 pixd = pixThresholdOn8bpp(pixs, nlevels, cmapflag); 00190 break; 00191 default: 00192 return (PIX *)ERROR_PTR("d must be in {1,2,4,8}", procName, NULL); 00193 } 00194 00195 if (!pixd) 00196 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00197 return pixd; 00198 } 00199 00200 00201 /*-------------------------------------------------------------* 00202 * Conversion from colormapped pix * 00203 *-------------------------------------------------------------*/ 00204 /*! 00205 * pixRemoveColormap() 00206 * 00207 * Input: pixs (see restrictions below) 00208 * type (REMOVE_CMAP_TO_BINARY, 00209 * REMOVE_CMAP_TO_GRAYSCALE, 00210 * REMOVE_CMAP_TO_FULL_COLOR, 00211 * REMOVE_CMAP_BASED_ON_SRC) 00212 * Return: new pix, or null on error 00213 * 00214 * Notes: 00215 * (1) If there is no colormap, a clone is returned. 00216 * (2) Otherwise, the input pixs is restricted to 1, 2, 4 or 8 bpp. 00217 * (3) Use REMOVE_CMAP_TO_BINARY only on 1 bpp pix. 00218 * (4) For grayscale conversion from RGB, use a weighted average 00219 * of RGB values, and always return an 8 bpp pix, regardless 00220 * of whether the input pixs depth is 2, 4 or 8 bpp. 00221 */ 00222 PIX * 00223 pixRemoveColormap(PIX *pixs, 00224 l_int32 type) 00225 { 00226 l_int32 sval, rval, gval, bval; 00227 l_int32 i, j, k, w, h, d, wpls, wpld, ncolors, count; 00228 l_int32 colorfound; 00229 l_int32 *rmap, *gmap, *bmap, *graymap; 00230 l_uint32 *datas, *lines, *datad, *lined, *lut; 00231 l_uint32 sword, dword; 00232 PIXCMAP *cmap; 00233 PIX *pixd; 00234 00235 PROCNAME("pixRemoveColormap"); 00236 00237 if (!pixs) 00238 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00239 if ((cmap = pixGetColormap(pixs)) == NULL) 00240 return pixClone(pixs); 00241 00242 if (type != REMOVE_CMAP_TO_BINARY && 00243 type != REMOVE_CMAP_TO_GRAYSCALE && 00244 type != REMOVE_CMAP_TO_FULL_COLOR && 00245 type != REMOVE_CMAP_BASED_ON_SRC) { 00246 L_WARNING("Invalid type; converting based on src", procName); 00247 type = REMOVE_CMAP_BASED_ON_SRC; 00248 } 00249 00250 pixGetDimensions(pixs, &w, &h, &d); 00251 if (d != 1 && d != 2 && d != 4 && d != 8) 00252 return (PIX *)ERROR_PTR("pixs must be {1,2,4,8} bpp", procName, NULL); 00253 00254 if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap)) 00255 return (PIX *)ERROR_PTR("colormap arrays not made", procName, NULL); 00256 00257 if (d != 1 && type == REMOVE_CMAP_TO_BINARY) { 00258 L_WARNING("not 1 bpp; can't remove cmap to binary", procName); 00259 type = REMOVE_CMAP_BASED_ON_SRC; 00260 } 00261 00262 if (type == REMOVE_CMAP_BASED_ON_SRC) { 00263 /* select output type depending on colormap */ 00264 pixcmapHasColor(cmap, &colorfound); 00265 if (!colorfound) { 00266 if (d == 1) 00267 type = REMOVE_CMAP_TO_BINARY; 00268 else 00269 type = REMOVE_CMAP_TO_GRAYSCALE; 00270 } 00271 else 00272 type = REMOVE_CMAP_TO_FULL_COLOR; 00273 } 00274 00275 ncolors = pixcmapGetCount(cmap); 00276 datas = pixGetData(pixs); 00277 wpls = pixGetWpl(pixs); 00278 if (type == REMOVE_CMAP_TO_BINARY) { 00279 if ((pixd = pixCopy(NULL, pixs)) == NULL) 00280 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00281 pixcmapGetColor(cmap, 0, &rval, &gval, &bval); 00282 if (rval == 0) /* photometrically inverted from standard */ 00283 pixInvert(pixd, pixd); 00284 pixDestroyColormap(pixd); 00285 } 00286 else if (type == REMOVE_CMAP_TO_GRAYSCALE) { 00287 if ((pixd = pixCreate(w, h, 8)) == NULL) 00288 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00289 pixCopyResolution(pixd, pixs); 00290 datad = pixGetData(pixd); 00291 wpld = pixGetWpl(pixd); 00292 if ((graymap = (l_int32 *)CALLOC(ncolors, sizeof(l_int32))) == NULL) 00293 return (PIX *)ERROR_PTR("calloc fail for graymap", procName, NULL); 00294 for (i = 0; i < pixcmapGetCount(cmap); i++) { 00295 graymap[i] = (rmap[i] + 2 * gmap[i] + bmap[i]) / 4; 00296 } 00297 for (i = 0; i < h; i++) { 00298 lines = datas + i * wpls; 00299 lined = datad + i * wpld; 00300 switch (d) /* depth test above; no default permitted */ 00301 { 00302 case 8: 00303 /* Unrolled 4x */ 00304 for (j = 0, count = 0; j + 3 < w; j += 4, count++) { 00305 sword = lines[count]; 00306 dword = (graymap[(sword >> 24) & 0xff] << 24) | 00307 (graymap[(sword >> 16) & 0xff] << 16) | 00308 (graymap[(sword >> 8) & 0xff] << 8) | 00309 graymap[sword & 0xff]; 00310 lined[count] = dword; 00311 } 00312 /* Cleanup partial word */ 00313 for (; j < w; j++) { 00314 sval = GET_DATA_BYTE(lines, j); 00315 gval = graymap[sval]; 00316 SET_DATA_BYTE(lined, j, gval); 00317 } 00318 #if DEBUG_UNROLLING 00319 #define CHECK_VALUE(a, b, c) if (GET_DATA_BYTE(a, b) != c) { \ 00320 fprintf(stderr, "Error: mismatch at %d, %d vs %d\n", \ 00321 j, GET_DATA_BYTE(a, b), c); } 00322 for (j = 0; j < w; j++) { 00323 sval = GET_DATA_BYTE(lines, j); 00324 gval = graymap[sval]; 00325 CHECK_VALUE(lined, j, gval); 00326 } 00327 #endif 00328 break; 00329 case 4: 00330 /* Unrolled 8x */ 00331 for (j = 0, count = 0; j + 7 < w; j += 8, count++) { 00332 sword = lines[count]; 00333 dword = (graymap[(sword >> 28) & 0xf] << 24) | 00334 (graymap[(sword >> 24) & 0xf] << 16) | 00335 (graymap[(sword >> 20) & 0xf] << 8) | 00336 graymap[(sword >> 16) & 0xf]; 00337 lined[2 * count] = dword; 00338 dword = (graymap[(sword >> 12) & 0xf] << 24) | 00339 (graymap[(sword >> 8) & 0xf] << 16) | 00340 (graymap[(sword >> 4) & 0xf] << 8) | 00341 graymap[sword & 0xf]; 00342 lined[2 * count + 1] = dword; 00343 } 00344 /* Cleanup partial word */ 00345 for (; j < w; j++) { 00346 sval = GET_DATA_QBIT(lines, j); 00347 gval = graymap[sval]; 00348 SET_DATA_BYTE(lined, j, gval); 00349 } 00350 #if DEBUG_UNROLLING 00351 for (j = 0; j < w; j++) { 00352 sval = GET_DATA_QBIT(lines, j); 00353 gval = graymap[sval]; 00354 CHECK_VALUE(lined, j, gval); 00355 } 00356 #endif 00357 break; 00358 case 2: 00359 /* Unrolled 16x */ 00360 for (j = 0, count = 0; j + 15 < w; j += 16, count++) { 00361 sword = lines[count]; 00362 dword = (graymap[(sword >> 30) & 0x3] << 24) | 00363 (graymap[(sword >> 28) & 0x3] << 16) | 00364 (graymap[(sword >> 26) & 0x3] << 8) | 00365 graymap[(sword >> 24) & 0x3]; 00366 lined[4 * count] = dword; 00367 dword = (graymap[(sword >> 22) & 0x3] << 24) | 00368 (graymap[(sword >> 20) & 0x3] << 16) | 00369 (graymap[(sword >> 18) & 0x3] << 8) | 00370 graymap[(sword >> 16) & 0x3]; 00371 lined[4 * count + 1] = dword; 00372 dword = (graymap[(sword >> 14) & 0x3] << 24) | 00373 (graymap[(sword >> 12) & 0x3] << 16) | 00374 (graymap[(sword >> 10) & 0x3] << 8) | 00375 graymap[(sword >> 8) & 0x3]; 00376 lined[4 * count + 2] = dword; 00377 dword = (graymap[(sword >> 6) & 0x3] << 24) | 00378 (graymap[(sword >> 4) & 0x3] << 16) | 00379 (graymap[(sword >> 2) & 0x3] << 8) | 00380 graymap[sword & 0x3]; 00381 lined[4 * count + 3] = dword; 00382 } 00383 /* Cleanup partial word */ 00384 for (; j < w; j++) { 00385 sval = GET_DATA_DIBIT(lines, j); 00386 gval = graymap[sval]; 00387 SET_DATA_BYTE(lined, j, gval); 00388 } 00389 #if DEBUG_UNROLLING 00390 for (j = 0; j < w; j++) { 00391 sval = GET_DATA_DIBIT(lines, j); 00392 gval = graymap[sval]; 00393 CHECK_VALUE(lined, j, gval); 00394 } 00395 #endif 00396 break; 00397 case 1: 00398 /* Unrolled 8x */ 00399 for (j = 0, count = 0; j + 31 < w; j += 32, count++) { 00400 sword = lines[count]; 00401 for (k = 0; k < 4; k++) { 00402 /* The top byte is always the relevant one */ 00403 dword = (graymap[(sword >> 31) & 0x1] << 24) | 00404 (graymap[(sword >> 30) & 0x1] << 16) | 00405 (graymap[(sword >> 29) & 0x1] << 8) | 00406 graymap[(sword >> 28) & 0x1]; 00407 lined[8 * count + 2 * k] = dword; 00408 dword = (graymap[(sword >> 27) & 0x1] << 24) | 00409 (graymap[(sword >> 26) & 0x1] << 16) | 00410 (graymap[(sword >> 25) & 0x1] << 8) | 00411 graymap[(sword >> 24) & 0x1]; 00412 lined[8 * count + 2 * k + 1] = dword; 00413 sword <<= 8; /* Move up the next byte */ 00414 } 00415 } 00416 /* Cleanup partial word */ 00417 for (; j < w; j++) { 00418 sval = GET_DATA_BIT(lines, j); 00419 gval = graymap[sval]; 00420 SET_DATA_BYTE(lined, j, gval); 00421 } 00422 #if DEBUG_UNROLLING 00423 for (j = 0; j < w; j++) { 00424 sval = GET_DATA_BIT(lines, j); 00425 gval = graymap[sval]; 00426 CHECK_VALUE(lined, j, gval); 00427 } 00428 #undef CHECK_VALUE 00429 #endif 00430 break; 00431 default: 00432 return NULL; 00433 } 00434 } 00435 if (graymap) 00436 FREE(graymap); 00437 } 00438 else { /* type == REMOVE_CMAP_TO_FULL_COLOR */ 00439 if ((pixd = pixCreate(w, h, 32)) == NULL) 00440 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00441 pixCopyResolution(pixd, pixs); 00442 datad = pixGetData(pixd); 00443 wpld = pixGetWpl(pixd); 00444 if ((lut = (l_uint32 *)CALLOC(ncolors, sizeof(l_uint32))) == NULL) 00445 return (PIX *)ERROR_PTR("calloc fail for lut", procName, NULL); 00446 for (i = 0; i < ncolors; i++) 00447 composeRGBPixel(rmap[i], gmap[i], bmap[i], lut + i); 00448 00449 for (i = 0; i < h; i++) { 00450 lines = datas + i * wpls; 00451 lined = datad + i * wpld; 00452 for (j = 0; j < w; j++) { 00453 if (d == 8) 00454 sval = GET_DATA_BYTE(lines, j); 00455 else if (d == 4) 00456 sval = GET_DATA_QBIT(lines, j); 00457 else if (d == 2) 00458 sval = GET_DATA_DIBIT(lines, j); 00459 else if (d == 1) 00460 sval = GET_DATA_BIT(lines, j); 00461 else 00462 return NULL; 00463 if (sval >= ncolors) 00464 L_WARNING("pixel value out of bounds", procName); 00465 else 00466 lined[j] = lut[sval]; 00467 } 00468 } 00469 FREE(lut); 00470 } 00471 00472 FREE(rmap); 00473 FREE(gmap); 00474 FREE(bmap); 00475 return pixd; 00476 } 00477 00478 00479 /*-------------------------------------------------------------* 00480 * Add colormap losslessly (8 to 8) * 00481 *-------------------------------------------------------------*/ 00482 /*! 00483 * pixAddGrayColormap8() 00484 * 00485 * Input: pixs (8 bpp) 00486 * Return: 0 if OK, 1 on error 00487 * 00488 * Notes: 00489 * (1) If pixs has a colormap, this is a no-op. 00490 */ 00491 l_int32 00492 pixAddGrayColormap8(PIX *pixs) 00493 { 00494 PIXCMAP *cmap; 00495 00496 PROCNAME("pixAddGrayColormap8"); 00497 00498 if (!pixs || pixGetDepth(pixs) != 8) 00499 return ERROR_INT("pixs not defined or not 8 bpp", procName, 1); 00500 if (pixGetColormap(pixs)) 00501 return 0; 00502 00503 cmap = pixcmapCreateLinear(8, 256); 00504 pixSetColormap(pixs, cmap); 00505 return 0; 00506 } 00507 00508 00509 /*! 00510 * pixAddMinimalGrayColormap8() 00511 * 00512 * Input: pixs (8 bpp) 00513 * Return: 0 if OK, 1 on error 00514 * 00515 * Notes: 00516 * (1) This generates a colormapped version of the input image 00517 * that has the same number of colormap entries as the 00518 * input image has unique gray levels. 00519 */ 00520 PIX * 00521 pixAddMinimalGrayColormap8(PIX *pixs) 00522 { 00523 l_int32 ncolors, w, h, i, j, wplt, wpld, index, val; 00524 l_int32 *inta, *revmap; 00525 l_uint32 *datat, *datad, *linet, *lined; 00526 PIX *pixt, *pixd; 00527 PIXCMAP *cmap; 00528 00529 PROCNAME("pixAddMinimalGrayColormap8"); 00530 00531 if (!pixs || pixGetDepth(pixs) != 8) 00532 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL); 00533 00534 /* Eliminate the easy cases */ 00535 pixNumColors(pixs, 1, &ncolors); 00536 cmap = pixGetColormap(pixs); 00537 if (cmap) { 00538 if (pixcmapGetCount(cmap) == ncolors) /* irreducible */ 00539 return pixCopy(NULL, pixs); 00540 else 00541 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 00542 } 00543 else { 00544 if (ncolors == 256) { 00545 pixt = pixCopy(NULL, pixs); 00546 pixAddGrayColormap8(pixt); 00547 return pixt; 00548 } 00549 pixt = pixClone(pixs); 00550 } 00551 00552 /* Find the gray levels and make a reverse map */ 00553 pixGetDimensions(pixt, &w, &h, NULL); 00554 datat = pixGetData(pixt); 00555 wplt = pixGetWpl(pixt); 00556 inta = (l_int32 *)CALLOC(256, sizeof(l_int32)); 00557 for (i = 0; i < h; i++) { 00558 linet = datat + i * wplt; 00559 for (j = 0; j < w; j++) { 00560 val = GET_DATA_BYTE(linet, j); 00561 inta[val] = 1; 00562 } 00563 } 00564 cmap = pixcmapCreate(8); 00565 revmap = (l_int32 *)CALLOC(256, sizeof(l_int32)); 00566 for (i = 0, index = 0; i < 256; i++) { 00567 if (inta[i]) { 00568 pixcmapAddColor(cmap, i, i, i); 00569 revmap[i] = index++; 00570 } 00571 } 00572 00573 /* Set all pixels in pixd to the colormap index */ 00574 pixd = pixCreateTemplate(pixt); 00575 pixSetColormap(pixd, cmap); 00576 pixCopyResolution(pixd, pixs); 00577 datad = pixGetData(pixd); 00578 wpld = pixGetWpl(pixd); 00579 for (i = 0; i < h; i++) { 00580 linet = datat + i * wplt; 00581 lined = datad + i * wpld; 00582 for (j = 0; j < w; j++) { 00583 val = GET_DATA_BYTE(linet, j); 00584 SET_DATA_BYTE(lined, j, revmap[val]); 00585 } 00586 } 00587 00588 pixDestroy(&pixt); 00589 FREE(inta); 00590 FREE(revmap); 00591 return pixd; 00592 } 00593 00594 00595 /*-------------------------------------------------------------* 00596 * Conversion from RGB color to grayscale * 00597 *-------------------------------------------------------------*/ 00598 /*! 00599 * pixConvertRGBToLuminance() 00600 * 00601 * Input: pix (32 bpp RGB) 00602 * Return: 8 bpp pix, or null on error 00603 * 00604 * Notes: 00605 * (1) Use a standard luminance conversion. 00606 */ 00607 PIX * 00608 pixConvertRGBToLuminance(PIX *pixs) 00609 { 00610 return pixConvertRGBToGray(pixs, 0.0, 0.0, 0.0); 00611 } 00612 00613 00614 /*! 00615 * pixConvertRGBToGray() 00616 * 00617 * Input: pix (32 bpp RGB) 00618 * rwt, gwt, bwt (non-negative; these should add to 1.0, 00619 * or use 0.0 for default) 00620 * Return: 8 bpp pix, or null on error 00621 * 00622 * Notes: 00623 * (1) Use a weighted average of the RGB values. 00624 */ 00625 PIX * 00626 pixConvertRGBToGray(PIX *pixs, 00627 l_float32 rwt, 00628 l_float32 gwt, 00629 l_float32 bwt) 00630 { 00631 l_int32 i, j, w, h, wpls, wpld, val; 00632 l_uint32 word; 00633 l_uint32 *datas, *lines, *datad, *lined; 00634 l_float32 sum; 00635 PIX *pixd; 00636 00637 PROCNAME("pixConvertRGBToGray"); 00638 00639 if (!pixs) 00640 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00641 if (pixGetDepth(pixs) != 32) 00642 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL); 00643 if (rwt < 0.0 || gwt < 0.0 || bwt < 0.0) 00644 return (PIX *)ERROR_PTR("weights not all >= 0.0", procName, NULL); 00645 00646 /* Make sure the sum of weights is 1.0; otherwise, you can get 00647 * overflow in the gray value. */ 00648 if (rwt == 0.0 && gwt == 0.0 && bwt == 0.0) { 00649 rwt = L_RED_WEIGHT; 00650 gwt = L_GREEN_WEIGHT; 00651 bwt = L_BLUE_WEIGHT; 00652 } 00653 sum = rwt + gwt + bwt; 00654 if (L_ABS(sum - 1.0) > 0.0001) { /* maintain ratios with sum == 1.0 */ 00655 L_WARNING("weights don't sum to 1; maintaining ratios", procName); 00656 rwt = rwt / sum; 00657 gwt = gwt / sum; 00658 bwt = bwt / sum; 00659 } 00660 00661 pixGetDimensions(pixs, &w, &h, NULL); 00662 datas = pixGetData(pixs); 00663 wpls = pixGetWpl(pixs); 00664 if ((pixd = pixCreate(w, h, 8)) == NULL) 00665 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00666 pixCopyResolution(pixd, pixs); 00667 datad = pixGetData(pixd); 00668 wpld = pixGetWpl(pixd); 00669 00670 for (i = 0, lines = datas, lined = datad; i < h; i++) { 00671 for (j = 0; j < w; j++) { 00672 word = *(lines + j); 00673 val = (l_int32)(rwt * ((word >> L_RED_SHIFT) & 0xff) + 00674 gwt * ((word >> L_GREEN_SHIFT) & 0xff) + 00675 bwt * ((word >> L_BLUE_SHIFT) & 0xff) + 0.5); 00676 SET_DATA_BYTE(lined, j, val); 00677 } 00678 lines += wpls; 00679 lined += wpld; 00680 } 00681 00682 return pixd; 00683 } 00684 00685 00686 /*! 00687 * pixConvertRGBToGrayFast() 00688 * 00689 * Input: pix (32 bpp RGB) 00690 * Return: 8 bpp pix, or null on error 00691 * 00692 * Notes: 00693 * (1) This function should be used if speed of conversion 00694 * is paramount, and the green channel can be used as 00695 * a fair representative of the RGB intensity. It is 00696 * several times faster than pixConvertRGBToGray(). 00697 * (2) To combine RGB to gray conversion with subsampling, 00698 * use pixScaleRGBToGrayFast() instead. 00699 */ 00700 PIX * 00701 pixConvertRGBToGrayFast(PIX *pixs) 00702 { 00703 l_int32 i, j, w, h, wpls, wpld, val; 00704 l_uint32 *datas, *lines, *datad, *lined; 00705 PIX *pixd; 00706 00707 PROCNAME("pixConvertRGBToGrayFast"); 00708 00709 if (!pixs) 00710 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00711 if (pixGetDepth(pixs) != 32) 00712 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL); 00713 00714 pixGetDimensions(pixs, &w, &h, NULL); 00715 datas = pixGetData(pixs); 00716 wpls = pixGetWpl(pixs); 00717 if ((pixd = pixCreate(w, h, 8)) == NULL) 00718 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00719 pixCopyResolution(pixd, pixs); 00720 datad = pixGetData(pixd); 00721 wpld = pixGetWpl(pixd); 00722 00723 for (i = 0; i < h; i++) { 00724 lines = datas + i * wpls; 00725 lined = datad + i * wpld; 00726 for (j = 0; j < w; j++, lines++) { 00727 val = ((*lines) >> L_GREEN_SHIFT) & 0xff; 00728 SET_DATA_BYTE(lined, j, val); 00729 } 00730 } 00731 00732 return pixd; 00733 } 00734 00735 00736 /*! 00737 * pixConvertRGBToGrayMinMax() 00738 * 00739 * Input: pix (32 bpp RGB) 00740 * type (L_CHOOSE_MIN or L_CHOOSE_MAX) 00741 * Return: 8 bpp pix, or null on error 00742 * 00743 * Notes: 00744 * (1) @type chooses among the 3 color components for each pixel 00745 * (2) This is useful when looking for the maximum deviation 00746 * of a component from either 0 or 255. For finding the 00747 * deviation of a single component, it is more sensitive 00748 * than using a weighted average. 00749 */ 00750 PIX * 00751 pixConvertRGBToGrayMinMax(PIX *pixs, 00752 l_int32 type) 00753 { 00754 l_int32 i, j, w, h, wpls, wpld, rval, gval, bval, val; 00755 l_uint32 *datas, *lines, *datad, *lined; 00756 PIX *pixd; 00757 00758 PROCNAME("pixConvertRGBToGrayMinMax"); 00759 00760 if (!pixs) 00761 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00762 if (pixGetDepth(pixs) != 32) 00763 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL); 00764 if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX) 00765 return (PIX *)ERROR_PTR("invalid type", procName, NULL); 00766 00767 pixGetDimensions(pixs, &w, &h, NULL); 00768 datas = pixGetData(pixs); 00769 wpls = pixGetWpl(pixs); 00770 if ((pixd = pixCreate(w, h, 8)) == NULL) 00771 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 00772 pixCopyResolution(pixd, pixs); 00773 datad = pixGetData(pixd); 00774 wpld = pixGetWpl(pixd); 00775 00776 for (i = 0; i < h; i++) { 00777 lines = datas + i * wpls; 00778 lined = datad + i * wpld; 00779 for (j = 0; j < w; j++) { 00780 extractRGBValues(lines[j], &rval, &gval, &bval); 00781 if (type == L_CHOOSE_MIN) { 00782 val = L_MIN(rval, gval); 00783 val = L_MIN(val, bval); 00784 } 00785 else { /* type == L_CHOOSE_MAX */ 00786 val = L_MAX(rval, gval); 00787 val = L_MAX(val, bval); 00788 } 00789 SET_DATA_BYTE(lined, j, val); 00790 } 00791 } 00792 00793 return pixd; 00794 } 00795 00796 00797 00798 /*---------------------------------------------------------------------------* 00799 * Conversion from grayscale to colormap * 00800 *---------------------------------------------------------------------------*/ 00801 /*! 00802 * pixConvertGrayToColormap() 00803 * 00804 * Input: pixs (2, 4 or 8 bpp grayscale) 00805 * Return: pixd (2, 4 or 8 bpp with colormap), or null on error 00806 * 00807 * Notes: 00808 * (1) This is a simple interface for adding a colormap to a 00809 * 2, 4 or 8 bpp grayscale image without causing any 00810 * quantization. There is some similarity to operations 00811 * in grayquant.c, such as pixThresholdOn8bpp(), where 00812 * the emphasis is on quantization with an arbitrary number 00813 * of levels, and a colormap is an option. 00814 * (2) Returns a copy if pixs already has a colormap. 00815 * (3) For 8 bpp src, this is a lossless transformation. 00816 * (4) For 2 and 4 bpp src, this generates a colormap that 00817 * assumes full coverage of the gray space, with equally spaced 00818 * levels: 4 levels for d = 2 and 16 levels for d = 4. 00819 * (5) In all cases, the depth of the dest is the same as the src. 00820 */ 00821 PIX * 00822 pixConvertGrayToColormap(PIX *pixs) 00823 { 00824 l_int32 d; 00825 PIX *pixd; 00826 PIXCMAP *cmap; 00827 00828 PROCNAME("pixConvertGrayToColormap"); 00829 00830 if (!pixs) 00831 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00832 d = pixGetDepth(pixs); 00833 if (d != 2 && d != 4 && d != 8) 00834 return (PIX *)ERROR_PTR("pixs not 2, 4 or 8 bpp", procName, NULL); 00835 00836 if (pixGetColormap(pixs)) { 00837 L_WARNING("pixs already has a colormap", procName); 00838 return pixCopy(NULL, pixs); 00839 } 00840 00841 if (d == 8) /* lossless conversion */ 00842 return pixConvertGrayToColormap8(pixs, 2); 00843 00844 /* Build a cmap with equally spaced target values over the 00845 * full 8 bpp range. */ 00846 pixd = pixCopy(NULL, pixs); 00847 cmap = pixcmapCreateLinear(d, 1 << d); 00848 pixSetColormap(pixd, cmap); 00849 return pixd; 00850 } 00851 00852 00853 /*! 00854 * pixConvertGrayToColormap8() 00855 * 00856 * Input: pixs (8 bpp grayscale) 00857 * mindepth (of pixd; valid values are 2, 4 and 8) 00858 * Return: pixd (2, 4 or 8 bpp with colormap), or null on error 00859 * 00860 * Notes: 00861 * (1) Returns a copy if pixs already has a colormap. 00862 * (2) This is a lossless transformation; there is no quantization. 00863 * We compute the number of different gray values in pixs, 00864 * and construct a colormap that has exactly these values. 00865 * (3) 'mindepth' is the minimum depth of pixd. If mindepth == 8, 00866 * pixd will always be 8 bpp. Let the number of different 00867 * gray values in pixs be ngray. If mindepth == 4, we attempt 00868 * to save pixd as a 4 bpp image, but if ngray > 16, 00869 * pixd must be 8 bpp. Likewise, if mindepth == 2, 00870 * the depth of pixd will be 2 if ngray <= 4 and 4 if ngray > 4 00871 * but <= 16. 00872 */ 00873 PIX * 00874 pixConvertGrayToColormap8(PIX *pixs, 00875 l_int32 mindepth) 00876 { 00877 l_int32 ncolors, w, h, depth, i, j, wpls, wpld; 00878 l_int32 index, num, val, newval; 00879 l_int32 array[256]; 00880 l_uint32 *lines, *lined, *datas, *datad; 00881 NUMA *na; 00882 PIX *pixd; 00883 PIXCMAP *cmap; 00884 00885 PROCNAME("pixConvertGrayToColormap8"); 00886 00887 if (!pixs) 00888 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00889 if (pixGetDepth(pixs) != 8) 00890 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 00891 if (mindepth != 2 && mindepth != 4 && mindepth != 8) { 00892 L_WARNING("invalid value of mindepth; setting to 8", procName); 00893 mindepth = 8; 00894 } 00895 00896 if (pixGetColormap(pixs)) { 00897 L_WARNING("pixs already has a colormap", procName); 00898 return pixCopy(NULL, pixs); 00899 } 00900 00901 na = pixGetGrayHistogram(pixs, 1); 00902 numaGetCountRelativeToZero(na, L_GREATER_THAN_ZERO, &ncolors); 00903 if (mindepth == 8 || ncolors > 16) 00904 depth = 8; 00905 else if (mindepth == 4 || ncolors > 4) 00906 depth = 4; 00907 else 00908 depth = 2; 00909 00910 pixGetDimensions(pixs, &w, &h, NULL); 00911 pixd = pixCreate(w, h, depth); 00912 cmap = pixcmapCreate(depth); 00913 pixSetColormap(pixd, cmap); 00914 pixCopyResolution(pixd, pixs); 00915 00916 index = 0; 00917 for (i = 0; i < 256; i++) { 00918 numaGetIValue(na, i, &num); 00919 if (num > 0) { 00920 pixcmapAddColor(cmap, i, i, i); 00921 array[i] = index; 00922 index++; 00923 } 00924 } 00925 00926 datas = pixGetData(pixs); 00927 wpls = pixGetWpl(pixs); 00928 datad = pixGetData(pixd); 00929 wpld = pixGetWpl(pixd); 00930 for (i = 0; i < h; i++) { 00931 lines = datas + i * wpls; 00932 lined = datad + i * wpld; 00933 for (j = 0; j < w; j++) { 00934 val = GET_DATA_BYTE(lines, j); 00935 newval = array[val]; 00936 if (depth == 2) 00937 SET_DATA_DIBIT(lined, j, newval); 00938 else if (depth == 4) 00939 SET_DATA_QBIT(lined, j, newval); 00940 else /* depth == 8 */ 00941 SET_DATA_BYTE(lined, j, newval); 00942 } 00943 } 00944 00945 numaDestroy(&na); 00946 return pixd; 00947 } 00948 00949 00950 /*---------------------------------------------------------------------------* 00951 * Colorizing conversion from grayscale to color * 00952 *---------------------------------------------------------------------------*/ 00953 /*! 00954 * pixColorizeGray() 00955 * 00956 * Input: pixs (8 bpp gray; 2, 4 or 8 bpp colormapped) 00957 * color (32 bit rgba pixel) 00958 * cmapflag (1 for result to have colormap; 0 for RGB) 00959 * Return: pixd (8 bpp colormapped or 32 bpp rgb), or null on error 00960 * 00961 * Notes: 00962 * (1) This applies the specific color to the grayscale image. 00963 * (2) If pixs already has a colormap, it is removed to gray 00964 * before colorizing. 00965 */ 00966 PIX * 00967 pixColorizeGray(PIX *pixs, 00968 l_uint32 color, 00969 l_int32 cmapflag) 00970 { 00971 l_int32 i, j, w, h, wplt, wpld, val8; 00972 l_uint32 *datad, *datat, *lined, *linet, *tab; 00973 PIX *pixt, *pixd; 00974 PIXCMAP *cmap; 00975 00976 PROCNAME("pixColorizeGray"); 00977 00978 if (!pixs) 00979 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 00980 if (pixGetDepth(pixs) != 8 && !pixGetColormap(pixs)) 00981 return (PIX *)ERROR_PTR("pixs not 8 bpp or cmapped", procName, NULL); 00982 00983 if (pixGetColormap(pixs)) 00984 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 00985 else 00986 pixt = pixClone(pixs); 00987 00988 cmap = pixcmapGrayToColor(color); 00989 if (cmapflag) { 00990 pixd = pixCopy(NULL, pixt); 00991 pixSetColormap(pixd, cmap); 00992 pixDestroy(&pixt); 00993 return pixd; 00994 } 00995 00996 /* Make an RGB pix */ 00997 pixcmapToRGBTable(cmap, &tab, NULL); 00998 pixGetDimensions(pixt, &w, &h, NULL); 00999 pixd = pixCreate(w, h, 32); 01000 pixCopyResolution(pixd, pixs); 01001 datad = pixGetData(pixd); 01002 wpld = pixGetWpl(pixd); 01003 datat = pixGetData(pixt); 01004 wplt = pixGetWpl(pixt); 01005 for (i = 0; i < h; i++) { 01006 lined = datad + i * wpld; 01007 linet = datat + i * wplt; 01008 for (j = 0; j < w; j++) { 01009 val8 = GET_DATA_BYTE(linet, j); 01010 lined[j] = tab[val8]; 01011 } 01012 } 01013 01014 pixDestroy(&pixt); 01015 pixcmapDestroy(&cmap); 01016 FREE(tab); 01017 return pixd; 01018 } 01019 01020 01021 /*---------------------------------------------------------------------------* 01022 * Conversion from RGB color to colormap * 01023 *---------------------------------------------------------------------------*/ 01024 /*! 01025 * pixConvertRGBToColormap() 01026 * 01027 * Input: pixs (32 bpp rgb) 01028 * ditherflag (1 to dither, 0 otherwise) 01029 * Return: pixd (2, 4 or 8 bpp with colormap), or null on error 01030 * 01031 * Notes: 01032 * (1) This function has two relatively simple modes of color 01033 * quantization: 01034 * (a) If the image is made orthographically and has not more 01035 * than 256 'colors' at the level 4 octcube leaves, 01036 * it is quantized nearly exactly. The ditherflag 01037 * is ignored. 01038 * (b) Most natural images have more than 256 different colors; 01039 * in that case we use adaptive octree quantization, 01040 * with dithering if requested. 01041 * (2) If there are not more than 256 occupied level 4 octcubes, 01042 * the color in the colormap that represents all pixels in 01043 * one of those octcubes is given by the first pixel that 01044 * falls into that octcube. 01045 * (3) If there are more than 256 colors, we use adaptive octree 01046 * color quantization. 01047 * (4) Dithering gives better visual results on images where 01048 * there is a color wash (a slow variation of color), but it 01049 * is about twice as slow and results in significantly larger 01050 * files when losslessly compressed (e.g., into png). 01051 */ 01052 PIX * 01053 pixConvertRGBToColormap(PIX *pixs, 01054 l_int32 ditherflag) 01055 { 01056 l_int32 ncolors; 01057 NUMA *na; 01058 PIX *pixd; 01059 01060 PROCNAME("pixConvertRGBToColormap"); 01061 01062 if (!pixs) 01063 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01064 if (pixGetDepth(pixs) != 32) 01065 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL); 01066 01067 /* Get the histogram and count the number of occupied level 4 01068 * leaf octcubes. We don't yet know if this is the number of 01069 * actual colors, but if it's not, all pixels falling into 01070 * the same leaf octcube will be assigned to the color of the 01071 * first pixel that lands there. */ 01072 na = pixOctcubeHistogram(pixs, 4, &ncolors); 01073 01074 /* If there are too many occupied leaf octcubes to be 01075 * represented directly in a colormap, fall back to octree 01076 * quantization, optionally with dithering. */ 01077 if (ncolors > 256) { 01078 numaDestroy(&na); 01079 if (ditherflag) 01080 L_INFO("More than 256 colors; using octree quant with dithering", 01081 procName); 01082 else 01083 L_INFO("More than 256 colors; using octree quant; no dithering", 01084 procName); 01085 return pixOctreeColorQuant(pixs, 240, ditherflag); 01086 } 01087 01088 /* There are not more than 256 occupied leaf octcubes. 01089 * Quantize to those octcubes. */ 01090 pixd = pixFewColorsOctcubeQuant2(pixs, 4, na, ncolors, NULL); 01091 numaDestroy(&na); 01092 return pixd; 01093 } 01094 01095 01096 /*---------------------------------------------------------------------------* 01097 * Quantization for relatively small number of colors in source * 01098 *---------------------------------------------------------------------------*/ 01099 /*! 01100 * pixQuantizeIfFewColors() 01101 * 01102 * Input: pixs (8 bpp gray or 32 bpp rgb) 01103 * maxcolors (max number of colors allowed to be returned 01104 * from pixColorsForQuantization(); use 0 for default) 01105 * mingraycolors (min number of gray levels that a grayscale 01106 * image is quantized to; use 0 for default) 01107 * octlevel (for octcube quantization: 3 or 4) 01108 * &pixd (2, 4 or 8 bpp quantized; null if too many colors) 01109 * Return: 0 if OK, 1 on error or if pixs can't be quantized into 01110 * a small number of colors. 01111 * 01112 * Notes: 01113 * (1) This is a wrapper that tests if the pix can be quantized 01114 * with good quality using a small number of colors. If so, 01115 * it does the quantization, defining a colormap and using 01116 * pixels whose value is an index into the colormap. 01117 * (2) If the image has color, it is quantized with 8 bpp pixels. 01118 * If the image is essentially grayscale, the pixels are 01119 * either 4 or 8 bpp, depending on the size of the required 01120 * colormap. 01121 * (3) @octlevel = 3 works well for most images. However, for best 01122 * quality, at a cost of more colors in the colormap, use 01123 * @octlevel = 4. 01124 * (4) If the image already has a colormap, it returns a clone. 01125 */ 01126 l_int32 01127 pixQuantizeIfFewColors(PIX *pixs, 01128 l_int32 maxcolors, 01129 l_int32 mingraycolors, 01130 l_int32 octlevel, 01131 PIX **ppixd) 01132 { 01133 l_int32 d, ncolors, iscolor, graycolors; 01134 PIX *pixg, *pixd; 01135 01136 PROCNAME("pixQuantizeIfFewColors"); 01137 01138 if (!ppixd) 01139 return ERROR_INT("&pixd not defined", procName, 1); 01140 *ppixd = NULL; 01141 if (!pixs) 01142 return ERROR_INT("pixs not defined", procName, 1); 01143 d = pixGetDepth(pixs); 01144 if (d != 8 && d != 32) 01145 return ERROR_INT("pixs not defined", procName, 1); 01146 if (pixGetColormap(pixs) != NULL) { 01147 *ppixd = pixClone(pixs); 01148 return 0; 01149 } 01150 if (maxcolors <= 0) 01151 maxcolors = 15; /* default */ 01152 if (maxcolors > 50) 01153 L_WARNING("maxcolors > 50; very large!", procName); 01154 if (mingraycolors <= 0) 01155 mingraycolors = 10; /* default */ 01156 if (mingraycolors > 30) 01157 L_WARNING("mingraycolors > 30; very large!", procName); 01158 if (octlevel != 3 && octlevel != 4) { 01159 L_WARNING("invalid octlevel; setting to 3", procName); 01160 octlevel = 3; 01161 } 01162 01163 /* Test the number of colors. For color, the octcube leaves 01164 * are at level 4. */ 01165 pixColorsForQuantization(pixs, 0, &ncolors, &iscolor, 0); 01166 if (ncolors > maxcolors) 01167 return ERROR_INT("too many colors", procName, 1); 01168 01169 /* Quantize! 01170 * (1) For color: 01171 * If octlevel == 4, try to quantize to an octree where 01172 * the octcube leaves are at level 4. If that fails, 01173 * back off to level 3. 01174 * If octlevel == 3, quantize to level 3 directly. 01175 * For level 3, the quality is usually good enough and there 01176 * is negligible chance of getting more than 256 colors. 01177 * (2) For grayscale, multiply ncolors by 1.5 for extra quality, 01178 * but use at least mingraycolors and not more than 256. */ 01179 if (iscolor) { 01180 pixd = pixFewColorsOctcubeQuant1(pixs, octlevel); 01181 if (!pixd) { /* backoff */ 01182 pixd = pixFewColorsOctcubeQuant1(pixs, octlevel - 1); 01183 if (octlevel == 3) /* shouldn't happen */ 01184 L_WARNING("quantized at level 2; low quality", procName); 01185 } 01186 } 01187 else { /* image is really grayscale */ 01188 if (d == 32) 01189 pixg = pixConvertRGBToLuminance(pixs); 01190 else 01191 pixg = pixClone(pixs); 01192 graycolors = L_MAX(mingraycolors, (l_int32)(1.5 * ncolors)); 01193 graycolors = L_MIN(graycolors, 256); 01194 if (graycolors < 16) 01195 pixd = pixThresholdTo4bpp(pixg, graycolors, 1); 01196 else 01197 pixd = pixThresholdOn8bpp(pixg, graycolors, 1); 01198 pixDestroy(&pixg); 01199 } 01200 *ppixd = pixd; 01201 01202 if (!pixd) 01203 return ERROR_INT("pixd not made", procName, 1); 01204 else 01205 return 0; 01206 } 01207 01208 01209 01210 /*---------------------------------------------------------------------------* 01211 * Conversion from 16 bpp to 8 bpp * 01212 *---------------------------------------------------------------------------*/ 01213 /*! 01214 * pixConvert16To8() 01215 * 01216 * Input: pixs (16 bpp) 01217 * whichbyte (1 for MSB, 0 for LSB) 01218 * Return: pixd (8 bpp), or null on error 01219 * 01220 * Notes: 01221 * (1) For each dest pixel, use either the MSB or LSB of each src pixel. 01222 */ 01223 PIX * 01224 pixConvert16To8(PIX *pixs, 01225 l_int32 whichbyte) 01226 { 01227 l_uint16 dsword; 01228 l_int32 w, h, wpls, wpld, i, j; 01229 l_uint32 sword; 01230 l_uint32 *datas, *datad, *lines, *lined; 01231 PIX *pixd; 01232 01233 PROCNAME("pixConvert16To8"); 01234 01235 if (!pixs) 01236 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01237 if (pixGetDepth(pixs) != 16) 01238 return (PIX *)ERROR_PTR("pixs not 16 bpp", procName, NULL); 01239 01240 pixGetDimensions(pixs, &w, &h, NULL); 01241 if ((pixd = pixCreate(w, h, 8)) == NULL) 01242 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01243 pixCopyResolution(pixd, pixs); 01244 wpls = pixGetWpl(pixs); 01245 datas = pixGetData(pixs); 01246 wpld = pixGetWpl(pixd); 01247 datad = pixGetData(pixd); 01248 01249 /* Convert 2 pixels at a time */ 01250 for (i = 0; i < h; i++) { 01251 lines = datas + i * wpls; 01252 lined = datad + i * wpld; 01253 if (whichbyte == 0) { /* LSB */ 01254 for (j = 0; j < wpls; j++) { 01255 sword = *(lines + j); 01256 dsword = ((sword >> 8) & 0xff00) | (sword & 0xff); 01257 SET_DATA_TWO_BYTES(lined, j, dsword); 01258 } 01259 } 01260 else { /* MSB */ 01261 for (j = 0; j < wpls; j++) { 01262 sword = *(lines + j); 01263 dsword = ((sword >> 16) & 0xff00) | ((sword >> 8) & 0xff); 01264 SET_DATA_TWO_BYTES(lined, j, dsword); 01265 } 01266 } 01267 } 01268 01269 return pixd; 01270 } 01271 01272 01273 01274 /*---------------------------------------------------------------------------* 01275 * Conversion from grayscale to false color 01276 *---------------------------------------------------------------------------*/ 01277 /*! 01278 * pixConvertGrayToFalseColor() 01279 * 01280 * Input: pixs (8 or 16 bpp grayscale) 01281 * gamma factor (0.0 or 1.0 for default; > 1.0 for brighter; 01282 * 2.0 is quite nice) 01283 * Return: pixd (8 bpp with colormap), or null on error 01284 * 01285 * Notes: 01286 * (1) For 8 bpp input, this simply adds a colormap to the input image. 01287 * (2) For 16 bpp input, it first converts to 8 bpp and then 01288 * adds the colormap. 01289 * (3) The colormap is modeled after the Matlab "jet" configuration. 01290 */ 01291 PIX * 01292 pixConvertGrayToFalseColor(PIX *pixs, 01293 l_float32 gamma) 01294 { 01295 l_int32 d, i, rval, bval, gval; 01296 l_int32 *curve; 01297 l_float32 invgamma, x; 01298 PIX *pixd; 01299 PIXCMAP *cmap; 01300 01301 PROCNAME("pixConvertGrayToFalseColor"); 01302 01303 if (!pixs) 01304 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01305 d = pixGetDepth(pixs); 01306 if (d != 8 && d != 16) 01307 return (PIX *)ERROR_PTR("pixs not 8 or 16 bpp", procName, NULL); 01308 01309 if (d == 16) 01310 pixd = pixConvert16To8(pixs, 1); 01311 else { /* d == 8 */ 01312 if (pixGetColormap(pixs)) 01313 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 01314 else 01315 pixd = pixCopy(NULL, pixs); 01316 } 01317 if (!pixd) 01318 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01319 if ((cmap = pixcmapCreate(8)) == NULL) 01320 return (PIX *)ERROR_PTR("cmap not made", procName, NULL); 01321 pixSetColormap(pixd, cmap); 01322 pixCopyResolution(pixd, pixs); 01323 01324 /* Generate curve for transition part of color map */ 01325 if ((curve = (l_int32 *)CALLOC(64, sizeof(l_int32)))== NULL) 01326 return (PIX *)ERROR_PTR("curve not made", procName, NULL); 01327 if (gamma == 0.0) gamma = 1.0; 01328 invgamma = 1. / gamma; 01329 for (i = 0; i < 64; i++) { 01330 x = (l_float32)i / 64.; 01331 curve[i] = (l_int32)(255. * powf(x, invgamma) + 0.5); 01332 } 01333 01334 for (i = 0; i < 256; i++) { 01335 if (i < 32) { 01336 rval = 0; 01337 gval = 0; 01338 bval = curve[i + 32]; 01339 } 01340 else if (i < 96) { /* 32 - 95 */ 01341 rval = 0; 01342 gval = curve[i - 32]; 01343 bval = 255; 01344 } 01345 else if (i < 160) { /* 96 - 159 */ 01346 rval = curve[i - 96]; 01347 gval = 255; 01348 bval = curve[159 - i]; 01349 } 01350 else if (i < 224) { /* 160 - 223 */ 01351 rval = 255; 01352 gval = curve[223 - i]; 01353 bval = 0; 01354 } 01355 else { /* 224 - 255 */ 01356 rval = curve[287 - i]; 01357 gval = 0; 01358 bval = 0; 01359 } 01360 pixcmapAddColor(cmap, rval, gval, bval); 01361 } 01362 01363 FREE(curve); 01364 return pixd; 01365 } 01366 01367 01368 /*---------------------------------------------------------------------------* 01369 * Unpacking conversion from 1 bpp to 2, 4, 8, 16 and 32 bpp * 01370 *---------------------------------------------------------------------------*/ 01371 /*! 01372 * pixUnpackBinary() 01373 * 01374 * Input: pixs (1 bpp) 01375 * depth (of destination: 2, 4, 8, 16 or 32 bpp) 01376 * invert (0: binary 0 --> grayscale 0 01377 * binary 1 --> grayscale 0xff... 01378 * 1: binary 0 --> grayscale 0xff... 01379 * binary 1 --> grayscale 0) 01380 * Return: pixd (2, 4, 8, 16 or 32 bpp), or null on error 01381 * 01382 * Notes: 01383 * (1) This function calls special cases of pixConvert1To*(), 01384 * for 2, 4, 8, 16 and 32 bpp destinations. 01385 */ 01386 PIX * 01387 pixUnpackBinary(PIX *pixs, 01388 l_int32 depth, 01389 l_int32 invert) 01390 { 01391 PIX *pixd; 01392 01393 PROCNAME("pixUnpackBinary"); 01394 01395 if (!pixs) 01396 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01397 if (pixGetDepth(pixs) != 1) 01398 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL); 01399 if (depth != 2 && depth != 4 && depth != 8 && depth != 16 && depth != 32) 01400 return (PIX *)ERROR_PTR("depth not 2, 4, 8, 16 or 32 bpp", 01401 procName, NULL); 01402 01403 if (depth == 2) { 01404 if (invert == 0) 01405 pixd = pixConvert1To2(NULL, pixs, 0, 3); 01406 else /* invert bits */ 01407 pixd = pixConvert1To2(NULL, pixs, 3, 0); 01408 } 01409 else if (depth == 4) { 01410 if (invert == 0) 01411 pixd = pixConvert1To4(NULL, pixs, 0, 15); 01412 else /* invert bits */ 01413 pixd = pixConvert1To4(NULL, pixs, 15, 0); 01414 } 01415 else if (depth == 8) { 01416 if (invert == 0) 01417 pixd = pixConvert1To8(NULL, pixs, 0, 255); 01418 else /* invert bits */ 01419 pixd = pixConvert1To8(NULL, pixs, 255, 0); 01420 } 01421 else if (depth == 16) { 01422 if (invert == 0) 01423 pixd = pixConvert1To16(NULL, pixs, 0, 0xffff); 01424 else /* invert bits */ 01425 pixd = pixConvert1To16(NULL, pixs, 0xffff, 0); 01426 } 01427 else { 01428 if (invert == 0) 01429 pixd = pixConvert1To32(NULL, pixs, 0, 0xffffffff); 01430 else /* invert bits */ 01431 pixd = pixConvert1To32(NULL, pixs, 0xffffffff, 0); 01432 } 01433 01434 return pixd; 01435 } 01436 01437 01438 /*! 01439 * pixConvert1To16() 01440 * 01441 * Input: pixd (<optional> 16 bpp, can be null) 01442 * pixs (1 bpp) 01443 * val0 (16 bit value to be used for 0s in pixs) 01444 * val1 (16 bit value to be used for 1s in pixs) 01445 * Return: pixd (16 bpp) 01446 * 01447 * Notes: 01448 * (1) If pixd is null, a new pix is made. 01449 * (2) If pixd is not null, it must be of equal width and height 01450 * as pixs. It is always returned. 01451 */ 01452 PIX * 01453 pixConvert1To16(PIX *pixd, 01454 PIX *pixs, 01455 l_uint16 val0, 01456 l_uint16 val1) 01457 { 01458 l_int32 w, h, i, j, dibit, ndibits, wpls, wpld; 01459 l_uint16 val[2]; 01460 l_uint32 index; 01461 l_uint32 *tab, *datas, *datad, *lines, *lined; 01462 01463 PROCNAME("pixConvert1To16"); 01464 01465 if (!pixs) 01466 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01467 if (pixGetDepth(pixs) != 1) 01468 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL); 01469 01470 w = pixGetWidth(pixs); 01471 h = pixGetHeight(pixs); 01472 if (pixd) { 01473 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd)) 01474 return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd); 01475 if (pixGetDepth(pixd) != 16) 01476 return (PIX *)ERROR_PTR("pixd not 16 bpp", procName, pixd); 01477 } 01478 else { 01479 if ((pixd = pixCreate(w, h, 16)) == NULL) 01480 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01481 } 01482 pixCopyResolution(pixd, pixs); 01483 01484 /* Use a table to convert 2 src bits at a time */ 01485 if ((tab = (l_uint32 *)CALLOC(4, sizeof(l_uint32))) == NULL) 01486 return (PIX *)ERROR_PTR("tab not made", procName, NULL); 01487 val[0] = val0; 01488 val[1] = val1; 01489 for (index = 0; index < 4; index++) { 01490 tab[index] = (val[(index >> 1) & 1] << 16) | val[index & 1]; 01491 } 01492 01493 datas = pixGetData(pixs); 01494 wpls = pixGetWpl(pixs); 01495 datad = pixGetData(pixd); 01496 wpld = pixGetWpl(pixd); 01497 ndibits = (w + 1) / 2; 01498 for (i = 0; i < h; i++) { 01499 lines = datas + i * wpls; 01500 lined = datad + i * wpld; 01501 for (j = 0; j < ndibits; j++) { 01502 dibit = GET_DATA_DIBIT(lines, j); 01503 lined[j] = tab[dibit]; 01504 } 01505 } 01506 01507 FREE(tab); 01508 return pixd; 01509 } 01510 01511 01512 /*! 01513 * pixConvert1To32() 01514 * 01515 * Input: pixd (<optional> 32 bpp, can be null) 01516 * pixs (1 bpp) 01517 * val0 (32 bit value to be used for 0s in pixs) 01518 * val1 (32 bit value to be used for 1s in pixs) 01519 * Return: pixd (32 bpp) 01520 * 01521 * Notes: 01522 * (1) If pixd is null, a new pix is made. 01523 * (2) If pixd is not null, it must be of equal width and height 01524 * as pixs. It is always returned. 01525 */ 01526 PIX * 01527 pixConvert1To32(PIX *pixd, 01528 PIX *pixs, 01529 l_uint32 val0, 01530 l_uint32 val1) 01531 { 01532 l_int32 w, h, i, j, wpls, wpld, bit; 01533 l_uint32 val[2]; 01534 l_uint32 *datas, *datad, *lines, *lined; 01535 01536 PROCNAME("pixConvert1To32"); 01537 01538 if (!pixs) 01539 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01540 if (pixGetDepth(pixs) != 1) 01541 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL); 01542 01543 pixGetDimensions(pixs, &w, &h, NULL); 01544 if (pixd) { 01545 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd)) 01546 return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd); 01547 if (pixGetDepth(pixd) != 32) 01548 return (PIX *)ERROR_PTR("pixd not 32 bpp", procName, pixd); 01549 } 01550 else { 01551 if ((pixd = pixCreate(w, h, 32)) == NULL) 01552 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01553 } 01554 pixCopyResolution(pixd, pixs); 01555 01556 val[0] = val0; 01557 val[1] = val1; 01558 datas = pixGetData(pixs); 01559 wpls = pixGetWpl(pixs); 01560 datad = pixGetData(pixd); 01561 wpld = pixGetWpl(pixd); 01562 for (i = 0; i < h; i++) { 01563 lines = datas + i * wpls; 01564 lined = datad + i * wpld; 01565 for (j = 0; j <w; j++) { 01566 bit = GET_DATA_BIT(lines, j); 01567 lined[j] = val[bit]; 01568 } 01569 } 01570 01571 return pixd; 01572 } 01573 01574 01575 /*---------------------------------------------------------------------------* 01576 * Conversion from 1 bpp to 2 bpp * 01577 *---------------------------------------------------------------------------*/ 01578 /*! 01579 * pixConvert1To2Cmap() 01580 * 01581 * Input: pixs (1 bpp) 01582 * Return: pixd (2 bpp, cmapped) 01583 * 01584 * Notes: 01585 * (1) Input 0 is mapped to (255, 255, 255); 1 is mapped to (0, 0, 0) 01586 */ 01587 PIX * 01588 pixConvert1To2Cmap(PIX *pixs) 01589 { 01590 PIX *pixd; 01591 PIXCMAP *cmap; 01592 01593 PROCNAME("pixConvert1To2Cmap"); 01594 01595 if (!pixs) 01596 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01597 if (pixGetDepth(pixs) != 1) 01598 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL); 01599 01600 if ((pixd = pixConvert1To2(NULL, pixs, 0, 1)) == NULL) 01601 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01602 cmap = pixcmapCreate(2); 01603 pixcmapAddColor(cmap, 255, 255, 255); 01604 pixcmapAddColor(cmap, 0, 0, 0); 01605 pixSetColormap(pixd, cmap); 01606 01607 return pixd; 01608 } 01609 01610 01611 /*! 01612 * pixConvert1To2() 01613 * 01614 * Input: pixd (<optional> 2 bpp, can be null) 01615 * pixs (1 bpp) 01616 * val0 (2 bit value to be used for 0s in pixs) 01617 * val1 (2 bit value to be used for 1s in pixs) 01618 * Return: pixd (2 bpp) 01619 * 01620 * Notes: 01621 * (1) If pixd is null, a new pix is made. 01622 * (2) If pixd is not null, it must be of equal width and height 01623 * as pixs. It is always returned. 01624 * (3) A simple unpacking might use val0 = 0 and val1 = 3. 01625 * (4) If you want a colormapped pixd, use pixConvert1To2Cmap(). 01626 */ 01627 PIX * 01628 pixConvert1To2(PIX *pixd, 01629 PIX *pixs, 01630 l_int32 val0, 01631 l_int32 val1) 01632 { 01633 l_int32 w, h, i, j, byteval, nbytes, wpls, wpld; 01634 l_uint8 val[2]; 01635 l_uint32 index; 01636 l_uint16 *tab; 01637 l_uint32 *datas, *datad, *lines, *lined; 01638 01639 PROCNAME("pixConvert1To2"); 01640 01641 if (!pixs) 01642 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd); 01643 if (pixGetDepth(pixs) != 1) 01644 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd); 01645 01646 pixGetDimensions(pixs, &w, &h, NULL); 01647 if (pixd) { 01648 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd)) 01649 return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd); 01650 if (pixGetDepth(pixd) != 2) 01651 return (PIX *)ERROR_PTR("pixd not 2 bpp", procName, pixd); 01652 } 01653 else { 01654 if ((pixd = pixCreate(w, h, 2)) == NULL) 01655 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01656 } 01657 pixCopyResolution(pixd, pixs); 01658 01659 /* Use a table to convert 8 src bits to 16 dest bits */ 01660 if ((tab = (l_uint16 *)CALLOC(256, sizeof(l_uint16))) == NULL) 01661 return (PIX *)ERROR_PTR("tab not made", procName, NULL); 01662 val[0] = val0; 01663 val[1] = val1; 01664 for (index = 0; index < 256; index++) { 01665 tab[index] = (val[(index >> 7) & 1] << 14) | 01666 (val[(index >> 6) & 1] << 12) | 01667 (val[(index >> 5) & 1] << 10) | 01668 (val[(index >> 4) & 1] << 8) | 01669 (val[(index >> 3) & 1] << 6) | 01670 (val[(index >> 2) & 1] << 4) | 01671 (val[(index >> 1) & 1] << 2) | val[index & 1]; 01672 } 01673 01674 datas = pixGetData(pixs); 01675 wpls = pixGetWpl(pixs); 01676 datad = pixGetData(pixd); 01677 wpld = pixGetWpl(pixd); 01678 nbytes = (w + 7) / 8; 01679 for (i = 0; i < h; i++) { 01680 lines = datas + i * wpls; 01681 lined = datad + i * wpld; 01682 for (j = 0; j < nbytes; j++) { 01683 byteval = GET_DATA_BYTE(lines, j); 01684 SET_DATA_TWO_BYTES(lined, j, tab[byteval]); 01685 } 01686 } 01687 01688 FREE(tab); 01689 return pixd; 01690 } 01691 01692 01693 /*---------------------------------------------------------------------------* 01694 * Conversion from 1 bpp to 4 bpp * 01695 *---------------------------------------------------------------------------*/ 01696 /*! 01697 * pixConvert1To4Cmap() 01698 * 01699 * Input: pixs (1 bpp) 01700 * Return: pixd (4 bpp, cmapped) 01701 * 01702 * Notes: 01703 * (1) Input 0 is mapped to (255, 255, 255); 1 is mapped to (0, 0, 0) 01704 */ 01705 PIX * 01706 pixConvert1To4Cmap(PIX *pixs) 01707 { 01708 PIX *pixd; 01709 PIXCMAP *cmap; 01710 01711 PROCNAME("pixConvert1To4Cmap"); 01712 01713 if (!pixs) 01714 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01715 if (pixGetDepth(pixs) != 1) 01716 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL); 01717 01718 if ((pixd = pixConvert1To4(NULL, pixs, 0, 1)) == NULL) 01719 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01720 cmap = pixcmapCreate(4); 01721 pixcmapAddColor(cmap, 255, 255, 255); 01722 pixcmapAddColor(cmap, 0, 0, 0); 01723 pixSetColormap(pixd, cmap); 01724 01725 return pixd; 01726 } 01727 01728 01729 /*! 01730 * pixConvert1To4() 01731 * 01732 * Input: pixd (<optional> 4 bpp, can be null) 01733 * pixs (1 bpp) 01734 * val0 (4 bit value to be used for 0s in pixs) 01735 * val1 (4 bit value to be used for 1s in pixs) 01736 * Return: pixd (4 bpp) 01737 * 01738 * Notes: 01739 * (1) If pixd is null, a new pix is made. 01740 * (2) If pixd is not null, it must be of equal width and height 01741 * as pixs. It is always returned. 01742 * (3) A simple unpacking might use val0 = 0 and val1 = 15, or v.v. 01743 * (4) If you want a colormapped pixd, use pixConvert1To4Cmap(). 01744 */ 01745 PIX * 01746 pixConvert1To4(PIX *pixd, 01747 PIX *pixs, 01748 l_int32 val0, 01749 l_int32 val1) 01750 { 01751 l_int32 w, h, i, j, byteval, nbytes, wpls, wpld; 01752 l_uint8 val[2]; 01753 l_uint32 index; 01754 l_uint32 *tab, *datas, *datad, *lines, *lined; 01755 01756 PROCNAME("pixConvert1To4"); 01757 01758 if (!pixs) 01759 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd); 01760 if (pixGetDepth(pixs) != 1) 01761 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd); 01762 01763 pixGetDimensions(pixs, &w, &h, NULL); 01764 if (pixd) { 01765 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd)) 01766 return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd); 01767 if (pixGetDepth(pixd) != 4) 01768 return (PIX *)ERROR_PTR("pixd not 4 bpp", procName, pixd); 01769 } 01770 else { 01771 if ((pixd = pixCreate(w, h, 4)) == NULL) 01772 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01773 } 01774 pixCopyResolution(pixd, pixs); 01775 01776 /* Use a table to convert 8 src bits to 32 bit dest word */ 01777 if ((tab = (l_uint32 *)CALLOC(256, sizeof(l_uint32))) == NULL) 01778 return (PIX *)ERROR_PTR("tab not made", procName, NULL); 01779 val[0] = val0; 01780 val[1] = val1; 01781 for (index = 0; index < 256; index++) { 01782 tab[index] = (val[(index >> 7) & 1] << 28) | 01783 (val[(index >> 6) & 1] << 24) | 01784 (val[(index >> 5) & 1] << 20) | 01785 (val[(index >> 4) & 1] << 16) | 01786 (val[(index >> 3) & 1] << 12) | 01787 (val[(index >> 2) & 1] << 8) | 01788 (val[(index >> 1) & 1] << 4) | val[index & 1]; 01789 } 01790 01791 datas = pixGetData(pixs); 01792 wpls = pixGetWpl(pixs); 01793 datad = pixGetData(pixd); 01794 wpld = pixGetWpl(pixd); 01795 nbytes = (w + 7) / 8; 01796 for (i = 0; i < h; i++) { 01797 lines = datas + i * wpls; 01798 lined = datad + i * wpld; 01799 for (j = 0; j < nbytes; j++) { 01800 byteval = GET_DATA_BYTE(lines, j); 01801 lined[j] = tab[byteval]; 01802 } 01803 } 01804 01805 FREE(tab); 01806 return pixd; 01807 } 01808 01809 01810 /*---------------------------------------------------------------------------* 01811 * Conversion from 1, 2 and 4 bpp to 8 bpp * 01812 *---------------------------------------------------------------------------*/ 01813 /*! 01814 * pixConvert1To8() 01815 * 01816 * Input: pixd (<optional> 8 bpp, can be null) 01817 * pixs (1 bpp) 01818 * val0 (8 bit value to be used for 0s in pixs) 01819 * val1 (8 bit value to be used for 1s in pixs) 01820 * Return: pixd (8 bpp) 01821 * 01822 * Notes: 01823 * (1) If pixd is null, a new pix is made. 01824 * (2) If pixd is not null, it must be of equal width and height 01825 * as pixs. It is always returned. 01826 * (3) A simple unpacking might use val0 = 0 and val1 = 255, or v.v. 01827 * (4) In a typical application where one wants to use a colormap 01828 * with the dest, you can use val0 = 0, val1 = 1 to make a 01829 * non-cmapped 8 bpp pix, and then make a colormap and set 0 01830 * and 1 to the desired colors. Here is an example: 01831 * pixd = pixConvert1To8(NULL, pixs, 0, 1); 01832 * cmap = pixCreate(8); 01833 * pixcmapAddColor(cmap, 255, 255, 255); 01834 * pixcmapAddColor(cmap, 0, 0, 0); 01835 * pixSetColormap(pixd, cmap); 01836 */ 01837 PIX * 01838 pixConvert1To8(PIX *pixd, 01839 PIX *pixs, 01840 l_uint8 val0, 01841 l_uint8 val1) 01842 { 01843 l_int32 w, h, i, j, qbit, nqbits, wpls, wpld; 01844 l_uint8 val[2]; 01845 l_uint32 index; 01846 l_uint32 *tab, *datas, *datad, *lines, *lined; 01847 01848 PROCNAME("pixConvert1To8"); 01849 01850 if (!pixs) 01851 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd); 01852 if (pixGetDepth(pixs) != 1) 01853 return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd); 01854 01855 pixGetDimensions(pixs, &w, &h, NULL); 01856 if (pixd) { 01857 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd)) 01858 return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd); 01859 if (pixGetDepth(pixd) != 8) 01860 return (PIX *)ERROR_PTR("pixd not 8 bpp", procName, pixd); 01861 } 01862 else { 01863 if ((pixd = pixCreate(w, h, 8)) == NULL) 01864 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01865 } 01866 pixCopyResolution(pixd, pixs); 01867 01868 /* Use a table to convert 4 src bits at a time */ 01869 if ((tab = (l_uint32 *)CALLOC(16, sizeof(l_uint32))) == NULL) 01870 return (PIX *)ERROR_PTR("tab not made", procName, NULL); 01871 val[0] = val0; 01872 val[1] = val1; 01873 for (index = 0; index < 16; index++) { 01874 tab[index] = (val[(index >> 3) & 1] << 24) | 01875 (val[(index >> 2) & 1] << 16) | 01876 (val[(index >> 1) & 1] << 8) | val[index & 1]; 01877 } 01878 01879 datas = pixGetData(pixs); 01880 wpls = pixGetWpl(pixs); 01881 datad = pixGetData(pixd); 01882 wpld = pixGetWpl(pixd); 01883 nqbits = (w + 3) / 4; 01884 for (i = 0; i < h; i++) { 01885 lines = datas + i * wpls; 01886 lined = datad + i * wpld; 01887 for (j = 0; j < nqbits; j++) { 01888 qbit = GET_DATA_QBIT(lines, j); 01889 lined[j] = tab[qbit]; 01890 } 01891 } 01892 01893 FREE(tab); 01894 return pixd; 01895 } 01896 01897 01898 /*! 01899 * pixConvert2To8() 01900 * 01901 * Input: pixs (2 bpp) 01902 * val0 (8 bit value to be used for 00 in pixs) 01903 * val1 (8 bit value to be used for 01 in pixs) 01904 * val2 (8 bit value to be used for 10 in pixs) 01905 * val3 (8 bit value to be used for 11 in pixs) 01906 * cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise) 01907 * Return: pixd (8 bpp), or null on error 01908 * 01909 * Notes: 01910 * - A simple unpacking might use val0 = 0, 01911 * val1 = 85 (0x55), val2 = 170 (0xaa), val3 = 255. 01912 * - If cmapflag is TRUE: 01913 * - The 8 bpp image is made with a colormap. 01914 * - If pixs has a colormap, the input values are ignored and 01915 * the 8 bpp image is made using the colormap 01916 * - If pixs does not have a colormap, the input values are 01917 * used to build the colormap. 01918 * - If cmapflag is FALSE: 01919 * - The 8 bpp image is made without a colormap. 01920 * - If pixs has a colormap, the input values are ignored, 01921 * the colormap is removed, and the values stored in the 8 bpp 01922 * image are from the colormap. 01923 * - If pixs does not have a colormap, the input values are 01924 * used to populate the 8 bpp image. 01925 */ 01926 PIX * 01927 pixConvert2To8(PIX *pixs, 01928 l_uint8 val0, 01929 l_uint8 val1, 01930 l_uint8 val2, 01931 l_uint8 val3, 01932 l_int32 cmapflag) 01933 { 01934 l_int32 w, h, i, j, nbytes, wpls, wpld, dibit, ncolor; 01935 l_int32 rval, gval, bval, byte; 01936 l_uint8 val[4]; 01937 l_uint32 index; 01938 l_uint32 *tab, *datas, *datad, *lines, *lined; 01939 PIX *pixd; 01940 PIXCMAP *cmaps, *cmapd; 01941 01942 PROCNAME("pixConvert2To8"); 01943 01944 if (!pixs) 01945 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01946 if (pixGetDepth(pixs) != 2) 01947 return (PIX *)ERROR_PTR("pixs not 2 bpp", procName, NULL); 01948 01949 cmaps = pixGetColormap(pixs); 01950 if (cmaps && cmapflag == FALSE) 01951 return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 01952 01953 pixGetDimensions(pixs, &w, &h, NULL); 01954 if ((pixd = pixCreate(w, h, 8)) == NULL) 01955 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01956 pixCopyResolution(pixd, pixs); 01957 datas = pixGetData(pixs); 01958 wpls = pixGetWpl(pixs); 01959 datad = pixGetData(pixd); 01960 wpld = pixGetWpl(pixd); 01961 01962 if (cmapflag == TRUE) { /* pixd will have a colormap */ 01963 cmapd = pixcmapCreate(8); /* 8 bpp standard cmap */ 01964 if (cmaps) { /* use the existing colormap from pixs */ 01965 ncolor = pixcmapGetCount(cmaps); 01966 for (i = 0; i < ncolor; i++) { 01967 pixcmapGetColor(cmaps, i, &rval, &gval, &bval); 01968 pixcmapAddColor(cmapd, rval, gval, bval); 01969 } 01970 } 01971 else { /* make a colormap from the input values */ 01972 pixcmapAddColor(cmapd, val0, val0, val0); 01973 pixcmapAddColor(cmapd, val1, val1, val1); 01974 pixcmapAddColor(cmapd, val2, val2, val2); 01975 pixcmapAddColor(cmapd, val3, val3, val3); 01976 } 01977 pixSetColormap(pixd, cmapd); 01978 for (i = 0; i < h; i++) { 01979 lines = datas + i * wpls; 01980 lined = datad + i * wpld; 01981 for (j = 0; j < w; j++) { 01982 dibit = GET_DATA_DIBIT(lines, j); 01983 SET_DATA_BYTE(lined, j, dibit); 01984 } 01985 } 01986 return pixd; 01987 } 01988 01989 /* Last case: no colormap in either pixs or pixd. 01990 * Use input values and build a table to convert 1 src byte 01991 * (4 src pixels) at a time */ 01992 if ((tab = (l_uint32 *)CALLOC(256, sizeof(l_uint32))) == NULL) 01993 return (PIX *)ERROR_PTR("tab not made", procName, NULL); 01994 val[0] = val0; 01995 val[1] = val1; 01996 val[2] = val2; 01997 val[3] = val3; 01998 for (index = 0; index < 256; index++) { 01999 tab[index] = (val[(index >> 6) & 3] << 24) | 02000 (val[(index >> 4) & 3] << 16) | 02001 (val[(index >> 2) & 3] << 8) | val[index & 3]; 02002 } 02003 02004 nbytes = (w + 3) / 4; 02005 for (i = 0; i < h; i++) { 02006 lines = datas + i * wpls; 02007 lined = datad + i * wpld; 02008 for (j = 0; j < nbytes; j++) { 02009 byte = GET_DATA_BYTE(lines, j); 02010 lined[j] = tab[byte]; 02011 } 02012 } 02013 02014 FREE(tab); 02015 return pixd; 02016 } 02017 02018 02019 /*! 02020 * pixConvert4To8() 02021 * 02022 * Input: pixs (4 bpp) 02023 * cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise) 02024 * Return: pixd (8 bpp), or null on error 02025 * 02026 * Notes: 02027 * - If cmapflag is TRUE: 02028 * - pixd is made with a colormap. 02029 * - If pixs has a colormap, it is copied and the colormap 02030 * index values are placed in pixd. 02031 * - If pixs does not have a colormap, a colormap with linear 02032 * trc is built and the pixel values in pixs are placed in 02033 * pixd as colormap index values. 02034 * - If cmapflag is FALSE: 02035 * - pixd is made without a colormap. 02036 * - If pixs has a colormap, it is removed and the values stored 02037 * in pixd are from the colormap (converted to gray). 02038 * - If pixs does not have a colormap, the pixel values in pixs 02039 * are used, with shift replication, to populate pixd. 02040 */ 02041 PIX * 02042 pixConvert4To8(PIX *pixs, 02043 l_int32 cmapflag) 02044 { 02045 l_int32 w, h, i, j, wpls, wpld, ncolor; 02046 l_int32 rval, gval, bval, byte, qbit; 02047 l_uint32 *datas, *datad, *lines, *lined; 02048 PIX *pixd; 02049 PIXCMAP *cmaps, *cmapd; 02050 02051 PROCNAME("pixConvert4To8"); 02052 02053 if (!pixs) 02054 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02055 if (pixGetDepth(pixs) != 4) 02056 return (PIX *)ERROR_PTR("pixs not 4 bpp", procName, NULL); 02057 02058 cmaps = pixGetColormap(pixs); 02059 if (cmaps && cmapflag == FALSE) 02060 return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 02061 02062 pixGetDimensions(pixs, &w, &h, NULL); 02063 if ((pixd = pixCreate(w, h, 8)) == NULL) 02064 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 02065 pixCopyResolution(pixd, pixs); 02066 datas = pixGetData(pixs); 02067 wpls = pixGetWpl(pixs); 02068 datad = pixGetData(pixd); 02069 wpld = pixGetWpl(pixd); 02070 02071 if (cmapflag == TRUE) { /* pixd will have a colormap */ 02072 cmapd = pixcmapCreate(8); 02073 if (cmaps) { /* use the existing colormap from pixs */ 02074 ncolor = pixcmapGetCount(cmaps); 02075 for (i = 0; i < ncolor; i++) { 02076 pixcmapGetColor(cmaps, i, &rval, &gval, &bval); 02077 pixcmapAddColor(cmapd, rval, gval, bval); 02078 } 02079 } 02080 else { /* make a colormap with a linear trc */ 02081 for (i = 0; i < 16; i++) 02082 pixcmapAddColor(cmapd, 17 * i, 17 * i, 17 * i); 02083 } 02084 pixSetColormap(pixd, cmapd); 02085 for (i = 0; i < h; i++) { 02086 lines = datas + i * wpls; 02087 lined = datad + i * wpld; 02088 for (j = 0; j < w; j++) { 02089 qbit = GET_DATA_QBIT(lines, j); 02090 SET_DATA_BYTE(lined, j, qbit); 02091 } 02092 } 02093 return pixd; 02094 } 02095 02096 /* Last case: no colormap in either pixs or pixd. 02097 * Replicate the qbit value into 8 bits. */ 02098 for (i = 0; i < h; i++) { 02099 lines = datas + i * wpls; 02100 lined = datad + i * wpld; 02101 for (j = 0; j < w; j++) { 02102 qbit = GET_DATA_QBIT(lines, j); 02103 byte = (qbit << 4) | qbit; 02104 SET_DATA_BYTE(lined, j, byte); 02105 } 02106 } 02107 return pixd; 02108 } 02109 02110 02111 02112 /*---------------------------------------------------------------------------* 02113 * Unpacking conversion from 8 bpp to 16 bpp * 02114 *---------------------------------------------------------------------------*/ 02115 /*! 02116 * pixConvert8To16() 02117 * 02118 * Input: pixs (8 bpp; colormap removed to gray) 02119 * leftshift (number of bits: 0 is no shift; 02120 * 8 replicates in MSB and LSB of dest) 02121 * Return: pixd (16 bpp), or null on error 02122 * 02123 * Notes: 02124 * (1) For left shift of 8, the 8 bit value is replicated in both 02125 * the MSB and the LSB of the pixels in pixd. That way, we get 02126 * proportional mapping, with a correct map from 8 bpp white 02127 * (0xff) to 16 bpp white (0xffff). 02128 */ 02129 PIX * 02130 pixConvert8To16(PIX *pixs, 02131 l_int32 leftshift) 02132 { 02133 l_int32 i, j, w, h, d, wplt, wpld, val; 02134 l_uint32 *datat, *datad, *linet, *lined; 02135 PIX *pixt, *pixd; 02136 02137 PROCNAME("pixConvert8To16"); 02138 02139 if (!pixs) 02140 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02141 pixGetDimensions(pixs, &w, &h, &d); 02142 if (d != 8) 02143 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 02144 if (leftshift < 0 || leftshift > 8) 02145 return (PIX *)ERROR_PTR("leftshift not in [0 ... 8]", procName, NULL); 02146 02147 if (pixGetColormap(pixs) != NULL) 02148 pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 02149 else 02150 pixt = pixClone(pixs); 02151 02152 pixd = pixCreate(w, h, 16); 02153 datat = pixGetData(pixt); 02154 datad = pixGetData(pixd); 02155 wplt = pixGetWpl(pixt); 02156 wpld = pixGetWpl(pixd); 02157 for (i = 0; i < h; i++) { 02158 linet = datat + i * wplt; 02159 lined = datad + i * wpld; 02160 for (j = 0; j < w; j++) { 02161 val = GET_DATA_BYTE(linet, j); 02162 if (leftshift == 8) 02163 val = val | (val << leftshift); 02164 else 02165 val <<= leftshift; 02166 SET_DATA_TWO_BYTES(lined, j, val); 02167 } 02168 } 02169 02170 pixDestroy(&pixt); 02171 return pixd; 02172 } 02173 02174 02175 02176 /*---------------------------------------------------------------------------* 02177 * Top-level conversion to 1 bpp * 02178 *---------------------------------------------------------------------------*/ 02179 /*! 02180 * pixConvertTo1() 02181 * 02182 * Input: pixs (1, 2, 4, 8, 16 or 32 bpp) 02183 * threshold (for final binarization, relative to 8 bpp) 02184 * Return: pixd (1 bpp), or null on error 02185 * 02186 * Notes: 02187 * (1) This is a top-level function, with simple default values 02188 * used in pixConvertTo8() if unpacking is necessary. 02189 * (2) Any existing colormap is removed. 02190 * (3) If the input image has 1 bpp and no colormap, the operation is 02191 * lossless and a copy is returned. 02192 */ 02193 PIX * 02194 pixConvertTo1(PIX *pixs, 02195 l_int32 threshold) 02196 { 02197 l_int32 d, color0, color1, rval, gval, bval; 02198 PIX *pixg, *pixd; 02199 PIXCMAP *cmap; 02200 02201 PROCNAME("pixConvertTo1"); 02202 02203 if (!pixs) 02204 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02205 d = pixGetDepth(pixs); 02206 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) 02207 return (PIX *)ERROR_PTR("depth not {1,2,4,8,16,32}", procName, NULL); 02208 02209 cmap = pixGetColormap(pixs); 02210 if (d == 1) { 02211 if (!cmap) 02212 return pixCopy(NULL, pixs); 02213 else { /* strip the colormap off, and invert if reasonable 02214 for standard binary photometry. */ 02215 pixcmapGetColor(cmap, 0, &rval, &gval, &bval); 02216 color0 = rval + gval + bval; 02217 pixcmapGetColor(cmap, 1, &rval, &gval, &bval); 02218 color1 = rval + gval + bval; 02219 pixd = pixCopy(NULL, pixs); 02220 pixDestroyColormap(pixd); 02221 if (color1 > color0) 02222 pixInvert(pixd, pixd); 02223 return pixd; 02224 } 02225 } 02226 02227 /* For all other depths, use 8 bpp as an intermediary */ 02228 pixg = pixConvertTo8(pixs, FALSE); 02229 pixd = pixThresholdToBinary(pixg, threshold); 02230 pixDestroy(&pixg); 02231 return pixd; 02232 } 02233 02234 02235 /*! 02236 * pixConvertTo1BySampling() 02237 * 02238 * Input: pixs (1, 2, 4, 8, 16 or 32 bpp) 02239 * factor (submsampling factor; integer >= 1) 02240 * threshold (for final binarization, relative to 8 bpp) 02241 * Return: pixd (1 bpp), or null on error 02242 * 02243 * Notes: 02244 * (1) This is a fast, quick/dirty, top-level converter. 02245 * (2) See pixConvertTo1() for default values. 02246 */ 02247 PIX * 02248 pixConvertTo1BySampling(PIX *pixs, 02249 l_int32 factor, 02250 l_int32 threshold) 02251 { 02252 l_float32 scalefactor; 02253 PIX *pixt, *pixd; 02254 02255 PROCNAME("pixConvertTo1BySampling"); 02256 02257 if (!pixs) 02258 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02259 if (factor < 1) 02260 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL); 02261 02262 scalefactor = 1. / (l_float32)factor; 02263 pixt = pixScaleBySampling(pixs, scalefactor, scalefactor); 02264 pixd = pixConvertTo1(pixt, threshold); 02265 02266 pixDestroy(&pixt); 02267 return pixd; 02268 } 02269 02270 02271 /*---------------------------------------------------------------------------* 02272 * Top-level conversion to 8 bpp * 02273 *---------------------------------------------------------------------------*/ 02274 /*! 02275 * pixConvertTo8() 02276 * 02277 * Input: pixs (1, 2, 4, 8, 16 or 32 bpp) 02278 * cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise) 02279 * Return: pixd (8 bpp), or null on error 02280 * 02281 * Notes: 02282 * (1) This is a top-level function, with simple default values 02283 * for unpacking. 02284 * (2) The result, pixd, is made with a colormap if specified. 02285 * (3) If d == 8, and cmapflag matches the existence of a cmap 02286 * in pixs, the operation is lossless and it returns a copy. 02287 * (4) The default values used are: 02288 * - 1 bpp: val0 = 255, val1 = 0 02289 * - 2 bpp: 4 bpp: even increments over dynamic range 02290 * - 8 bpp: lossless if cmap matches cmapflag 02291 * - 16 bpp: use most significant byte 02292 * (5) If 32 bpp RGB, this is converted to gray. If you want 02293 * to do color quantization, you must specify the type 02294 * explicitly, using the color quantization code. 02295 */ 02296 PIX * 02297 pixConvertTo8(PIX *pixs, 02298 l_int32 cmapflag) 02299 { 02300 l_int32 d; 02301 PIX *pixd; 02302 PIXCMAP *cmap; 02303 02304 PROCNAME("pixConvertTo8"); 02305 02306 if (!pixs) 02307 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02308 d = pixGetDepth(pixs); 02309 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) 02310 return (PIX *)ERROR_PTR("depth not {1,2,4,8,16,32}", procName, NULL); 02311 02312 if (d == 1) { 02313 if (!cmapflag) 02314 return pixConvert1To8(NULL, pixs, 255, 0); 02315 else { 02316 pixd = pixConvert1To8(NULL, pixs, 0, 1); 02317 cmap = pixcmapCreate(8); 02318 pixcmapAddColor(cmap, 255, 255, 255); 02319 pixcmapAddColor(cmap, 0, 0, 0); 02320 pixSetColormap(pixd, cmap); 02321 return pixd; 02322 } 02323 } 02324 else if (d == 2) 02325 return pixConvert2To8(pixs, 0, 85, 170, 255, cmapflag); 02326 else if (d == 4) 02327 return pixConvert4To8(pixs, cmapflag); 02328 else if (d == 8) { 02329 cmap = pixGetColormap(pixs); 02330 if ((cmap && cmapflag) || (!cmap && !cmapflag)) 02331 return pixCopy(NULL, pixs); 02332 else if (cmap) /* !cmapflag */ 02333 return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 02334 else { /* !cmap && cmapflag; add colormap to pixd */ 02335 pixd = pixCopy(NULL, pixs); 02336 pixAddGrayColormap8(pixd); 02337 return pixd; 02338 } 02339 } 02340 else if (d == 16) { 02341 pixd = pixConvert16To8(pixs, 1); 02342 if (cmapflag) 02343 pixAddGrayColormap8(pixd); 02344 return pixd; 02345 } 02346 else { /* d == 32 */ 02347 pixd = pixConvertRGBToLuminance(pixs); 02348 if (cmapflag) 02349 pixAddGrayColormap8(pixd); 02350 return pixd; 02351 } 02352 } 02353 02354 02355 /*! 02356 * pixConvertTo8BySampling() 02357 * 02358 * Input: pixs (1, 2, 4, 8, 16 or 32 bpp) 02359 * factor (submsampling factor; integer >= 1) 02360 * cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise) 02361 * Return: pixd (8 bpp), or null on error 02362 * 02363 * Notes: 02364 * (1) This is a fast, quick/dirty, top-level converter. 02365 * (2) See pixConvertTo8() for default values. 02366 */ 02367 PIX * 02368 pixConvertTo8BySampling(PIX *pixs, 02369 l_int32 factor, 02370 l_int32 cmapflag) 02371 { 02372 l_float32 scalefactor; 02373 PIX *pixt, *pixd; 02374 02375 PROCNAME("pixConvertTo8BySampling"); 02376 02377 if (!pixs) 02378 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02379 if (factor < 1) 02380 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL); 02381 02382 scalefactor = 1. / (l_float32)factor; 02383 pixt = pixScaleBySampling(pixs, scalefactor, scalefactor); 02384 pixd = pixConvertTo8(pixt, cmapflag); 02385 02386 pixDestroy(&pixt); 02387 return pixd; 02388 } 02389 02390 02391 /*---------------------------------------------------------------------------* 02392 * Top-level conversion to 16 bpp * 02393 *---------------------------------------------------------------------------*/ 02394 /*! 02395 * pixConvertTo16() 02396 * 02397 * Input: pixs (1, 8 bpp) 02398 * Return: pixd (16 bpp), or null on error 02399 * 02400 * Usage: Top-level function, with simple default values for unpacking. 02401 * 1 bpp: val0 = 0xffff, val1 = 0 02402 * 8 bpp: replicates the 8 bit value in both the MSB and LSB 02403 * of the 16 bit pixel. 02404 */ 02405 PIX * 02406 pixConvertTo16(PIX *pixs) 02407 { 02408 l_int32 d; 02409 02410 PROCNAME("pixConvertTo16"); 02411 02412 if (!pixs) 02413 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02414 02415 d = pixGetDepth(pixs); 02416 if (d == 1) 02417 return pixConvert1To16(NULL, pixs, 0xffff, 0); 02418 else if (d == 8) 02419 return pixConvert8To16(pixs, 8); 02420 else 02421 return (PIX *)ERROR_PTR("src depth not 1 or 8 bpp", procName, NULL); 02422 } 02423 02424 02425 02426 /*---------------------------------------------------------------------------* 02427 * Top-level conversion to 32 bpp * 02428 *---------------------------------------------------------------------------*/ 02429 /*! 02430 * pixConvertTo32() 02431 * 02432 * Input: pixs (1, 2, 4, 8, 16 or 32 bpp) 02433 * Return: pixd (32 bpp), or null on error 02434 * 02435 * Usage: Top-level function, with simple default values for unpacking. 02436 * 1 bpp: val0 = 255, val1 = 0 02437 * and then replication into R, G and B components 02438 * 2 bpp: if colormapped, use the colormap values; otherwise, 02439 * use val0 = 0, val1 = 0x55, val2 = 0xaa, val3 = 255 02440 * and replicate gray into R, G and B components 02441 * 4 bpp: if colormapped, use the colormap values; otherwise, 02442 * replicate 2 nybs into a byte, and then into R,G,B components 02443 * 8 bpp: if colormapped, use the colormap values; otherwise, 02444 * replicate gray values into R, G and B components 02445 * 16 bpp: replicate MSB into R, G and B components 02446 * 24 bpp: unpack the pixels, maintaining word alignment on each scanline 02447 * 32 bpp: makes a copy 02448 * 02449 * Notes: 02450 * (1) Implicit assumption about RGB component ordering. 02451 */ 02452 PIX * 02453 pixConvertTo32(PIX *pixs) 02454 { 02455 l_int32 d; 02456 PIX *pixt, *pixd; 02457 02458 PROCNAME("pixConvertTo32"); 02459 02460 if (!pixs) 02461 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02462 02463 d = pixGetDepth(pixs); 02464 if (d == 1) 02465 return pixConvert1To32(NULL, pixs, 0xffffffff, 0); 02466 else if (d == 2) { 02467 pixt = pixConvert2To8(pixs, 0, 85, 170, 255, TRUE); 02468 pixd = pixConvert8To32(pixt); 02469 pixDestroy(&pixt); 02470 return pixd; 02471 } 02472 else if (d == 4) { 02473 pixt = pixConvert4To8(pixs, TRUE); 02474 pixd = pixConvert8To32(pixt); 02475 pixDestroy(&pixt); 02476 return pixd; 02477 } 02478 else if (d == 8) 02479 return pixConvert8To32(pixs); 02480 else if (d == 16) { 02481 pixt = pixConvert16To8(pixs, 1); 02482 pixd = pixConvert8To32(pixt); 02483 pixDestroy(&pixt); 02484 return pixd; 02485 } 02486 else if (d == 24) 02487 return pixConvert24To32(pixs); 02488 else if (d == 32) 02489 return pixCopy(NULL, pixs); 02490 else 02491 return (PIX *)ERROR_PTR("depth not 1, 2, 4, 8, 16, 32 bpp", 02492 procName, NULL); 02493 } 02494 02495 02496 /*! 02497 * pixConvertTo32BySampling() 02498 * 02499 * Input: pixs (1, 2, 4, 8, 16 or 32 bpp) 02500 * factor (submsampling factor; integer >= 1) 02501 * Return: pixd (32 bpp), or null on error 02502 * 02503 * Notes: 02504 * (1) This is a fast, quick/dirty, top-level converter. 02505 * (2) See pixConvertTo32() for default values. 02506 */ 02507 PIX * 02508 pixConvertTo32BySampling(PIX *pixs, 02509 l_int32 factor) 02510 { 02511 l_float32 scalefactor; 02512 PIX *pixt, *pixd; 02513 02514 PROCNAME("pixConvertTo32BySampling"); 02515 02516 if (!pixs) 02517 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02518 if (factor < 1) 02519 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL); 02520 02521 scalefactor = 1. / (l_float32)factor; 02522 pixt = pixScaleBySampling(pixs, scalefactor, scalefactor); 02523 pixd = pixConvertTo32(pixt); 02524 02525 pixDestroy(&pixt); 02526 return pixd; 02527 } 02528 02529 02530 /*! 02531 * pixConvert8To32() 02532 * 02533 * Input: pix (8 bpp) 02534 * Return: 32 bpp rgb pix, or null on error 02535 * 02536 * Notes: 02537 * (1) If there is no colormap, replicates the gray value 02538 * into the 3 MSB of the dest pixel. 02539 * (2) Implicit assumption about RGB component ordering. 02540 */ 02541 PIX * 02542 pixConvert8To32(PIX *pixs) 02543 { 02544 l_int32 i, j, w, h, wpls, wpld, val; 02545 l_uint32 *datas, *datad, *lines, *lined; 02546 l_uint32 *tab; 02547 PIX *pixd; 02548 02549 PROCNAME("pixConvert8To32"); 02550 02551 if (!pixs) 02552 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02553 if (pixGetDepth(pixs) != 8) 02554 return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL); 02555 02556 if (pixGetColormap(pixs)) 02557 return pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR); 02558 02559 /* Replication table */ 02560 if ((tab = (l_uint32 *)CALLOC(256, sizeof(l_uint32))) == NULL) 02561 return (PIX *)ERROR_PTR("tab not made", procName, NULL); 02562 for (i = 0; i < 256; i++) 02563 tab[i] = (i << 24) | (i << 16) | (i << 8); 02564 02565 pixGetDimensions(pixs, &w, &h, NULL); 02566 datas = pixGetData(pixs); 02567 wpls = pixGetWpl(pixs); 02568 if ((pixd = pixCreate(w, h, 32)) == NULL) 02569 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 02570 pixCopyResolution(pixd, pixs); 02571 datad = pixGetData(pixd); 02572 wpld = pixGetWpl(pixd); 02573 02574 for (i = 0; i < h; i++) { 02575 lines = datas + i * wpls; 02576 lined = datad + i * wpld; 02577 for (j = 0; j < w; j++) { 02578 val = GET_DATA_BYTE(lines, j); 02579 lined[j] = tab[val]; 02580 } 02581 } 02582 02583 FREE(tab); 02584 return pixd; 02585 } 02586 02587 02588 /*---------------------------------------------------------------------------* 02589 * Top-level conversion to 8 or 32 bpp, without colormap * 02590 *---------------------------------------------------------------------------*/ 02591 /*! 02592 * pixConvertTo8Or32() 02593 * 02594 * Input: pixs (1, 2, 4, 8, 16, with or without colormap; or 32 bpp rgb) 02595 * copyflag (use 0 to return clone if pixs does not need to 02596 * be changed; 1 to return a copy in those situations) 02597 * warnflag (1 to issue warning if colormap is removed; else 0) 02598 * Return: pixd (8 bpp grayscale or 32 bpp rgb), or null on error 02599 * 02600 * Notes: 02601 * (1) If there is a colormap, the colormap is removed to 8 or 32 bpp, 02602 * depending on whether the colors in the colormap are all gray. 02603 * (2) If the input is either rgb or 8 bpp without a colormap, 02604 * this returns either a clone or a copy, depending on @copyflag. 02605 * (3) Otherwise, the pix is converted to 8 bpp grayscale. 02606 * In all cases, pixd does not have a colormap. 02607 */ 02608 PIX * 02609 pixConvertTo8Or32(PIX *pixs, 02610 l_int32 copyflag, 02611 l_int32 warnflag) 02612 { 02613 l_int32 d; 02614 PIX *pixd; 02615 02616 PROCNAME("pixConvertTo8Or32"); 02617 02618 if (!pixs) 02619 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02620 02621 d = pixGetDepth(pixs); 02622 if (pixGetColormap(pixs)) { 02623 if (warnflag) L_WARNING("pix has colormap; removing", procName); 02624 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); 02625 } 02626 else if (d == 8 || d == 32) { 02627 if (copyflag == 0) 02628 pixd = pixClone(pixs); 02629 else 02630 pixd = pixCopy(NULL, pixs); 02631 } 02632 else 02633 pixd = pixConvertTo8(pixs, 0); 02634 02635 /* Sanity check on result */ 02636 d = pixGetDepth(pixd); 02637 if (d != 8 && d != 32) { 02638 pixDestroy(&pixd); 02639 return (PIX *)ERROR_PTR("depth not 8 or 32 bpp", procName, NULL); 02640 } 02641 02642 return pixd; 02643 } 02644 02645 02646 /*---------------------------------------------------------------------------* 02647 * Conversion between 24 bpp and 32 bpp rgb * 02648 *---------------------------------------------------------------------------*/ 02649 /*! 02650 * pixConvert24To32() 02651 * 02652 * Input: pixs (24 bpp rgb) 02653 * Return: pixd (32 bpp rgb), or null on error 02654 * 02655 * Notes: 02656 * (1) 24 bpp rgb pix are not supported in leptonica. 02657 * The data is a byte array, with pixels in order r,g,b, and 02658 * padded to 32 bit boundaries in each line. 02659 * (2) Because they are conveniently generated by programs 02660 * such as xpdf, we need to provide the ability to write them 02661 * in png, jpeg and tiff, as well as to convert between 24 and 02662 * 32 bpp in memory. 02663 */ 02664 PIX * 02665 pixConvert24To32(PIX *pixs) 02666 { 02667 l_uint8 *lines; 02668 l_int32 w, h, d, i, j, wpls, wpld, rval, gval, bval; 02669 l_uint32 pixel; 02670 l_uint32 *datas, *datad, *lined; 02671 PIX *pixd; 02672 02673 PROCNAME("pixConvert24to32"); 02674 02675 if (!pixs) 02676 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02677 pixGetDimensions(pixs, &w, &h, &d); 02678 if (d != 24) 02679 return (PIX *)ERROR_PTR("pixs not 24 bpp", procName, NULL); 02680 02681 pixd = pixCreateNoInit(w, h, 32); 02682 datas = pixGetData(pixs); 02683 datad = pixGetData(pixd); 02684 wpls = pixGetWpl(pixs); 02685 wpld = pixGetWpl(pixd); 02686 for (i = 0; i < h; i++) { 02687 lines = (l_uint8 *)(datas + i * wpls); 02688 lined = datad + i * wpld; 02689 for (j = 0; j < w; j++) { 02690 rval = *lines++; 02691 gval = *lines++; 02692 bval = *lines++; 02693 composeRGBPixel(rval, gval, bval, &pixel); 02694 lined[j] = pixel; 02695 } 02696 } 02697 pixCopyResolution(pixd, pixs); 02698 pixCopyInputFormat(pixd, pixs); 02699 return pixd; 02700 } 02701 02702 02703 /*! 02704 * pixConvert32To24() 02705 * 02706 * Input: pixs (32 bpp rgb) 02707 * Return: pixd (24 bpp rgb), or null on error 02708 * 02709 * Notes: 02710 * (1) 24 bpp rgb pix are not supported in leptonica. 02711 * The data is a byte array, with pixels in order r,g,b, and 02712 * padded to 32 bit boundaries in each line. 02713 * (2) This function is put here for completeness, and so that we 02714 * can generate 24 bpp for testing. The test has two parts: 02715 * (a) convert the 24 bpp pix back to 32 bpp, and test 02716 * for pixel component equality 02717 * (b) write the 24 bpp pix as a png and verify that it is 02718 * identical to the file obtained by writing the 32 bpp pix. 02719 */ 02720 PIX * 02721 pixConvert32To24(PIX *pixs) 02722 { 02723 l_uint8 *rgbdata8; 02724 l_int32 w, h, d, i, j, wpls, wpld, rval, gval, bval; 02725 l_uint32 *datas, *lines, *rgbdata; 02726 PIX *pixd; 02727 02728 PROCNAME("pixConvert32to24"); 02729 02730 if (!pixs) 02731 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02732 pixGetDimensions(pixs, &w, &h, &d); 02733 if (d != 32) 02734 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL); 02735 02736 datas = pixGetData(pixs); 02737 wpls = pixGetWpl(pixs); 02738 pixd = pixCreateNoInit(w, h, 24); 02739 rgbdata = pixGetData(pixd); 02740 wpld = pixGetWpl(pixd); 02741 for (i = 0; i < h; i++) { 02742 lines = datas + i * wpls; 02743 rgbdata8 = (l_uint8 *)(rgbdata + i * wpld); 02744 for (j = 0; j < w; j++) { 02745 extractRGBValues(lines[j], &rval, &gval, &bval); 02746 *rgbdata8++ = rval; 02747 *rgbdata8++ = gval; 02748 *rgbdata8++ = bval; 02749 } 02750 } 02751 pixCopyResolution(pixd, pixs); 02752 pixCopyInputFormat(pixd, pixs); 02753 return pixd; 02754 } 02755 02756 02757 /*---------------------------------------------------------------------------* 02758 * Lossless depth conversion (unpacking) * 02759 *---------------------------------------------------------------------------*/ 02760 /*! 02761 * pixConvertLossless() 02762 * 02763 * Input: pixs (1, 2, 4, 8 bpp, not cmapped) 02764 * d (destination depth: 2, 4 or 8) 02765 * Return: pixd (2, 4 or 8 bpp), or null on error 02766 * 02767 * Notes: 02768 * (1) This is a lossless unpacking (depth-increasing) 02769 * conversion. If ds is the depth of pixs, then 02770 * - if d < ds, returns NULL 02771 * - if d == ds, returns a copy 02772 * - if d > ds, does the unpacking conversion 02773 * (2) If pixs has a colormap, this is an error. 02774 */ 02775 PIX * 02776 pixConvertLossless(PIX *pixs, 02777 l_int32 d) 02778 { 02779 l_int32 w, h, ds, wpls, wpld, i, j, val; 02780 l_uint32 *datas, *datad, *lines, *lined; 02781 PIX *pixd; 02782 02783 PROCNAME("pixConvertLossless"); 02784 02785 if (!pixs) 02786 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02787 if (pixGetColormap(pixs)) 02788 return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL); 02789 if (d != 2 && d != 4 && d != 8) 02790 return (PIX *)ERROR_PTR("invalid dest depth", procName, NULL); 02791 02792 pixGetDimensions(pixs, &w, &h, &ds); 02793 if (d < ds) 02794 return (PIX *)ERROR_PTR("depth > d", procName, NULL); 02795 else if (d == ds) 02796 return pixCopy(NULL, pixs); 02797 02798 if ((pixd = pixCreate(w, h, d)) == NULL) 02799 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 02800 pixCopyResolution(pixd, pixs); 02801 02802 /* Unpack the bits */ 02803 datas = pixGetData(pixs); 02804 wpls = pixGetWpl(pixs); 02805 datad = pixGetData(pixd); 02806 wpld = pixGetWpl(pixd); 02807 for (i = 0; i < h; i++) { 02808 lines = datas + i * wpls; 02809 lined = datad + i * wpld; 02810 switch (ds) 02811 { 02812 case 1: 02813 for (j = 0; j < w; j++) { 02814 val = GET_DATA_BIT(lines, j); 02815 if (d == 8) 02816 SET_DATA_BYTE(lined, j, val); 02817 else if (d == 4) 02818 SET_DATA_QBIT(lined, j, val); 02819 else /* d == 2 */ 02820 SET_DATA_DIBIT(lined, j, val); 02821 } 02822 break; 02823 case 2: 02824 for (j = 0; j < w; j++) { 02825 val = GET_DATA_DIBIT(lines, j); 02826 if (d == 8) 02827 SET_DATA_BYTE(lined, j, val); 02828 else /* d == 4 */ 02829 SET_DATA_QBIT(lined, j, val); 02830 } 02831 case 4: 02832 for (j = 0; j < w; j++) { 02833 val = GET_DATA_DIBIT(lines, j); 02834 SET_DATA_BYTE(lined, j, val); 02835 } 02836 break; 02837 } 02838 } 02839 02840 return pixd; 02841 } 02842 02843 02844 /*---------------------------------------------------------------------------* 02845 * Conversion for printing in PostScript * 02846 *---------------------------------------------------------------------------*/ 02847 /*! 02848 * pixConvertForPSWrap() 02849 * 02850 * Input: pixs (1, 2, 4, 8, 16, 32 bpp) 02851 * Return: pixd (1, 8, or 32 bpp), or null on error 02852 * 02853 * Notes: 02854 * (1) For wrapping in PostScript, we convert pixs to 02855 * 1 bpp, 8 bpp (gray) and 32 bpp (RGB color). 02856 * (2) Colormaps are removed. For pixs with colormaps, the 02857 * images are converted to either 8 bpp gray or 32 bpp 02858 * RGB, depending on whether the colormap has color content. 02859 * (3) Images without colormaps, that are not 1 bpp or 32 bpp, 02860 * are converted to 8 bpp gray. 02861 */ 02862 PIX * 02863 pixConvertForPSWrap(PIX *pixs) 02864 { 02865 l_int32 d; 02866 PIX *pixd; 02867 PIXCMAP *cmap; 02868 02869 PROCNAME("pixConvertForPSWrap"); 02870 02871 if (!pixs) 02872 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02873 02874 cmap = pixGetColormap(pixs); 02875 d = pixGetDepth(pixs); 02876 switch (d) 02877 { 02878 case 1: 02879 case 32: 02880 pixd = pixClone(pixs); 02881 break; 02882 case 2: 02883 if (cmap) 02884 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); 02885 else 02886 pixd = pixConvert2To8(pixs, 0, 0x55, 0xaa, 0xff, FALSE); 02887 break; 02888 case 4: 02889 if (cmap) 02890 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); 02891 else 02892 pixd = pixConvert4To8(pixs, FALSE); 02893 break; 02894 case 8: 02895 pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); 02896 break; 02897 case 16: 02898 pixd = pixConvert16To8(pixs, 1); 02899 break; 02900 default: 02901 fprintf(stderr, "depth not in {1, 2, 4, 8, 16, 32}"); 02902 return NULL; 02903 } 02904 02905 return pixd; 02906 } 02907 02908 02909 /*---------------------------------------------------------------------------* 02910 * Scaling conversion to subpixel RGB * 02911 *---------------------------------------------------------------------------*/ 02912 /*! 02913 * pixConvertToSubpixelRGB() 02914 * 02915 * Input: pixs (8 bpp grayscale, 32 bpp rgb, or colormapped) 02916 * scalex, scaley (anisotropic scaling permitted between 02917 * source and destination) 02918 * order (of subpixel rgb color components in composition of pixd: 02919 * L_SUBPIXEL_ORDER_RGB, L_SUBPIXEL_ORDER_BGR, 02920 * L_SUBPIXEL_ORDER_VRGB, L_SUBPIXEL_ORDER_VBGR) 02921 * 02922 * Return: pixd (32 bpp), or null on error 02923 * 02924 * Notes: 02925 * (1) If pixs has a colormap, it is removed based on its contents 02926 * to either 8 bpp gray or rgb. 02927 * (2) For horizontal subpixel splitting, the input image 02928 * is rescaled by @scaley vertically and by 3.0 times 02929 * @scalex horizontally. Then each horizontal triplet 02930 * of pixels is mapped back to a single rgb pixel, with the 02931 * r, g and b values being assigned based on the pixel triplet. 02932 * For gray triplets, the r, g, and b values are set equal to 02933 * the three gray values. For color triplets, the r, g and b 02934 * values are set equal to the components from the appropriate 02935 * subpixel. Vertical subpixel splitting is handled similarly. 02936 * (3) See pixConvertGrayToSubpixelRGB() and 02937 * pixConvertColorToSubpixelRGB() for further details. 02938 */ 02939 PIX * 02940 pixConvertToSubpixelRGB(PIX *pixs, 02941 l_float32 scalex, 02942 l_float32 scaley, 02943 l_int32 order) 02944 { 02945 l_int32 d; 02946 PIX *pixt, *pixd; 02947 PIXCMAP *cmap; 02948 02949 PROCNAME("pixConvertToSubpixelRGB"); 02950 02951 if (!pixs) 02952 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02953 d = pixGetDepth(pixs); 02954 cmap = pixGetColormap(pixs); 02955 if (d != 8 && d != 32 && !cmap) 02956 return (PIX *)ERROR_PTR("pix not 8 or 32 bpp and not cmapped", 02957 procName, NULL); 02958 if (scalex <= 0.0 || scaley <= 0.0) 02959 return (PIX *)ERROR_PTR("scale factors must be > 0", procName, NULL); 02960 if (order != L_SUBPIXEL_ORDER_RGB && order != L_SUBPIXEL_ORDER_BGR && 02961 order != L_SUBPIXEL_ORDER_VRGB && order != L_SUBPIXEL_ORDER_VBGR) 02962 return (PIX *)ERROR_PTR("invalid subpixel order", procName, NULL); 02963 if ((pixt = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC)) == NULL) 02964 return (PIX *)ERROR_PTR("pixt not made", procName, NULL); 02965 02966 d = pixGetDepth(pixt); 02967 pixd = NULL; 02968 if (d == 8) 02969 pixd = pixConvertGrayToSubpixelRGB(pixt, scalex, scaley, order); 02970 else if (d == 32) 02971 pixd = pixConvertColorToSubpixelRGB(pixt, scalex, scaley, order); 02972 else 02973 L_ERROR_INT("invalid depth %d", procName, d); 02974 02975 pixDestroy(&pixt); 02976 return pixd; 02977 } 02978 02979 02980 /*! 02981 * pixConvertGrayToSubpixelRGB() 02982 * 02983 * Input: pixs (8 bpp or colormapped) 02984 * scalex, scaley 02985 * order (of subpixel rgb color components in composition of pixd: 02986 * L_SUBPIXEL_ORDER_RGB, L_SUBPIXEL_ORDER_BGR, 02987 * L_SUBPIXEL_ORDER_VRGB, L_SUBPIXEL_ORDER_VBGR) 02988 * 02989 * Return: pixd (32 bpp), or null on error 02990 * 02991 * Notes: 02992 * (1) If pixs has a colormap, it is removed to 8 bpp. 02993 * (2) For horizontal subpixel splitting, the input gray image 02994 * is rescaled by @scaley vertically and by 3.0 times 02995 * @scalex horizontally. Then each horizontal triplet 02996 * of pixels is mapped back to a single rgb pixel, with the 02997 * r, g and b values being assigned from the triplet of gray values. 02998 * Similar operations are used for vertical subpixel splitting. 02999 * (3) This is a form of subpixel rendering that tends to give the 03000 * resulting text a sharper and somewhat chromatic display. 03001 * For horizontal subpixel splitting, the observable difference 03002 * between @order=L_SUBPIXEL_ORDER_RGB and 03003 * @order=L_SUBPIXEL_ORDER_BGR is reduced by optical diffusers 03004 * in the display that make the pixel color appear to emerge 03005 * from the entire pixel. 03006 */ 03007 PIX * 03008 pixConvertGrayToSubpixelRGB(PIX *pixs, 03009 l_float32 scalex, 03010 l_float32 scaley, 03011 l_int32 order) 03012 { 03013 l_int32 w, h, d, wd, hd, wplt, wpld, i, j, rval, gval, bval, direction; 03014 l_uint32 *datat, *datad, *linet, *lined; 03015 PIX *pixt1, *pixt2, *pixd; 03016 PIXCMAP *cmap; 03017 03018 PROCNAME("pixConvertGrayToSubpixelRGB"); 03019 03020 if (!pixs) 03021 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 03022 d = pixGetDepth(pixs); 03023 cmap = pixGetColormap(pixs); 03024 if (d != 8 && !cmap) 03025 return (PIX *)ERROR_PTR("pix not 8 bpp & not cmapped", procName, NULL); 03026 if (scalex <= 0.0 || scaley <= 0.0) 03027 return (PIX *)ERROR_PTR("scale factors must be > 0", procName, NULL); 03028 if (order != L_SUBPIXEL_ORDER_RGB && order != L_SUBPIXEL_ORDER_BGR && 03029 order != L_SUBPIXEL_ORDER_VRGB && order != L_SUBPIXEL_ORDER_VBGR) 03030 return (PIX *)ERROR_PTR("invalid subpixel order", procName, NULL); 03031 03032 direction = 03033 (order == L_SUBPIXEL_ORDER_RGB || order == L_SUBPIXEL_ORDER_BGR) 03034 ? L_HORIZ : L_VERT; 03035 pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); 03036 if (direction == L_HORIZ) 03037 pixt2 = pixScale(pixt1, 3.0 * scalex, scaley); 03038 else /* L_VERT */ 03039 pixt2 = pixScale(pixt1, scalex, 3.0 * scaley); 03040 03041 pixGetDimensions(pixt2, &w, &h, NULL); 03042 wd = (direction == L_HORIZ) ? w / 3 : w; 03043 hd = (direction == L_VERT) ? h / 3 : h; 03044 pixd = pixCreate(wd, hd, 32); 03045 datad = pixGetData(pixd); 03046 wpld = pixGetWpl(pixd); 03047 datat = pixGetData(pixt2); 03048 wplt = pixGetWpl(pixt2); 03049 if (direction == L_HORIZ) { 03050 for (i = 0; i < hd; i++) { 03051 linet = datat + i * wplt; 03052 lined = datad + i * wpld; 03053 for (j = 0; j < wd; j++) { 03054 rval = GET_DATA_BYTE(linet, 3 * j); 03055 gval = GET_DATA_BYTE(linet, 3 * j + 1); 03056 bval = GET_DATA_BYTE(linet, 3 * j + 2); 03057 if (order == L_SUBPIXEL_ORDER_RGB) 03058 composeRGBPixel(rval, gval, bval, &lined[j]); 03059 else /* order BGR */ 03060 composeRGBPixel(bval, gval, rval, &lined[j]); 03061 } 03062 } 03063 } 03064 else { /* L_VERT */ 03065 for (i = 0; i < hd; i++) { 03066 linet = datat + 3 * i * wplt; 03067 lined = datad + i * wpld; 03068 for (j = 0; j < wd; j++) { 03069 rval = GET_DATA_BYTE(linet, j); 03070 gval = GET_DATA_BYTE(linet + wplt, j); 03071 bval = GET_DATA_BYTE(linet + 2 * wplt, j); 03072 if (order == L_SUBPIXEL_ORDER_VRGB) 03073 composeRGBPixel(rval, gval, bval, &lined[j]); 03074 else /* order VBGR */ 03075 composeRGBPixel(bval, gval, rval, &lined[j]); 03076 } 03077 } 03078 } 03079 03080 pixDestroy(&pixt1); 03081 pixDestroy(&pixt2); 03082 return pixd; 03083 } 03084 03085 03086 /*! 03087 * pixConvertColorToSubpixelRGB() 03088 * 03089 * Input: pixs (32 bpp or colormapped) 03090 * scalex, scaley 03091 * order (of subpixel rgb color components in composition of pixd: 03092 * L_SUBPIXEL_ORDER_RGB, L_SUBPIXEL_ORDER_BGR, 03093 * L_SUBPIXEL_ORDER_VRGB, L_SUBPIXEL_ORDER_VBGR) 03094 * 03095 * Return: pixd (32 bpp), or null on error 03096 * 03097 * Notes: 03098 * (1) If pixs has a colormap, it is removed to 32 bpp rgb. 03099 * If the colormap has no color, pixConvertGrayToSubpixelRGB() 03100 * should be called instead, because it will give the same result 03101 * more efficiently. The function pixConvertToSubpixelRGB() 03102 * will do the best thing for all cases. 03103 * (2) For horizontal subpixel splitting, the input rgb image 03104 * is rescaled by @scalev vertically and by 3.0 times 03105 * @scalex horizontally. Then for each horizontal triplet 03106 * of pixels, the r component of the final pixel is selected 03107 * from the r component of the appropriate pixel in the triplet, 03108 * and likewise for g and b. Vertical subpixel splitting is 03109 * handled similarly. 03110 */ 03111 PIX * 03112 pixConvertColorToSubpixelRGB(PIX *pixs, 03113 l_float32 scalex, 03114 l_float32 scaley, 03115 l_int32 order) 03116 { 03117 l_int32 w, h, d, wd, hd, wplt, wpld, i, j, rval, gval, bval, direction; 03118 l_uint32 *datat, *datad, *linet, *lined; 03119 PIX *pixt1, *pixt2, *pixd; 03120 PIXCMAP *cmap; 03121 03122 PROCNAME("pixConvertColorToSubpixelRGB"); 03123 03124 if (!pixs) 03125 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 03126 d = pixGetDepth(pixs); 03127 cmap = pixGetColormap(pixs); 03128 if (d != 32 && !cmap) 03129 return (PIX *)ERROR_PTR("pix not 32 bpp & not cmapped", procName, NULL); 03130 if (scalex <= 0.0 || scaley <= 0.0) 03131 return (PIX *)ERROR_PTR("scale factors must be > 0", procName, NULL); 03132 if (order != L_SUBPIXEL_ORDER_RGB && order != L_SUBPIXEL_ORDER_BGR && 03133 order != L_SUBPIXEL_ORDER_VRGB && order != L_SUBPIXEL_ORDER_VBGR) 03134 return (PIX *)ERROR_PTR("invalid subpixel order", procName, NULL); 03135 03136 direction = 03137 (order == L_SUBPIXEL_ORDER_RGB || order == L_SUBPIXEL_ORDER_BGR) 03138 ? L_HORIZ : L_VERT; 03139 pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR); 03140 if (direction == L_HORIZ) 03141 pixt2 = pixScale(pixt1, 3.0 * scalex, scaley); 03142 else /* L_VERT */ 03143 pixt2 = pixScale(pixt1, scalex, 3.0 * scaley); 03144 03145 pixGetDimensions(pixt2, &w, &h, NULL); 03146 wd = (direction == L_HORIZ) ? w / 3 : w; 03147 hd = (direction == L_VERT) ? h / 3 : h; 03148 pixd = pixCreate(wd, hd, 32); 03149 datad = pixGetData(pixd); 03150 wpld = pixGetWpl(pixd); 03151 datat = pixGetData(pixt2); 03152 wplt = pixGetWpl(pixt2); 03153 if (direction == L_HORIZ) { 03154 for (i = 0; i < hd; i++) { 03155 linet = datat + i * wplt; 03156 lined = datad + i * wpld; 03157 for (j = 0; j < wd; j++) { 03158 if (order == L_SUBPIXEL_ORDER_RGB) { 03159 extractRGBValues(linet[3 * j], &rval, NULL, NULL); 03160 extractRGBValues(linet[3 * j + 1], NULL, &gval, NULL); 03161 extractRGBValues(linet[3 * j + 2], NULL, NULL, &bval); 03162 } 03163 else { /* order BGR */ 03164 extractRGBValues(linet[3 * j], NULL, NULL, &bval); 03165 extractRGBValues(linet[3 * j + 1], NULL, &gval, NULL); 03166 extractRGBValues(linet[3 * j + 2], &rval, NULL, NULL); 03167 } 03168 composeRGBPixel(rval, gval, bval, &lined[j]); 03169 } 03170 } 03171 } 03172 else { /* L_VERT */ 03173 for (i = 0; i < hd; i++) { 03174 linet = datat + 3 * i * wplt; 03175 lined = datad + i * wpld; 03176 for (j = 0; j < wd; j++) { 03177 if (order == L_SUBPIXEL_ORDER_VRGB) { 03178 extractRGBValues(linet[j], &rval, NULL, NULL); 03179 extractRGBValues((linet + wplt)[j], NULL, &gval, NULL); 03180 extractRGBValues((linet + 2 * wplt)[j], NULL, NULL, &bval); 03181 } 03182 else { /* order VBGR */ 03183 extractRGBValues(linet[j], NULL, NULL, &bval); 03184 extractRGBValues((linet + wplt)[j], NULL, &gval, NULL); 03185 extractRGBValues((linet + 2 * wplt)[j], &rval, NULL, NULL); 03186 } 03187 composeRGBPixel(rval, gval, bval, &lined[j]); 03188 } 03189 } 03190 } 03191 03192 pixDestroy(&pixt1); 03193 pixDestroy(&pixt2); 03194 return pixd; 03195 }