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 * grayquantlow.c 00018 * 00019 * Thresholding from 8 bpp to 1 bpp 00020 * 00021 * Floyd-Steinberg dithering to binary 00022 * void ditherToBinaryLow() 00023 * void ditherToBinaryLineLow() 00024 * 00025 * Simple (pixelwise) binarization 00026 * void thresholdToBinaryLow() 00027 * void thresholdToBinaryLineLow() 00028 * 00029 * A slower version of Floyd-Steinberg dithering that uses LUTs 00030 * void ditherToBinaryLUTLow() 00031 * void ditherToBinaryLineLUTLow() 00032 * l_int32 make8To1DitherTables() 00033 * 00034 * Thresholding from 8 bpp to 2 bpp 00035 * 00036 * Floyd-Steinberg-like dithering to 2 bpp 00037 * void ditherTo2bppLow() 00038 * void ditherTo2bppLineLow() 00039 * l_int32 make8To2DitherTables() 00040 * 00041 * Simple thresholding to 2 bpp 00042 * void thresholdTo2bppLow() 00043 * 00044 * Thresholding from 8 bpp to 4 bpp 00045 * 00046 * Simple thresholding to 4 bpp 00047 * void thresholdTo4bppLow() 00048 */ 00049 00050 #include <stdio.h> 00051 #include <stdlib.h> 00052 #include <string.h> 00053 #include "allheaders.h" 00054 00055 #ifndef NO_CONSOLE_IO 00056 #define DEBUG_UNROLLING 0 00057 #endif /* ~NO_CONSOLE_IO */ 00058 00059 00060 /*------------------------------------------------------------------* 00061 * Binarization by Floyd-Steinberg Dithering * 00062 *------------------------------------------------------------------*/ 00063 /* 00064 * ditherToBinaryLow() 00065 * 00066 * See comments in pixDitherToBinary() in binarize.c 00067 */ 00068 void 00069 ditherToBinaryLow(l_uint32 *datad, 00070 l_int32 w, 00071 l_int32 h, 00072 l_int32 wpld, 00073 l_uint32 *datas, 00074 l_int32 wpls, 00075 l_uint32 *bufs1, 00076 l_uint32 *bufs2, 00077 l_int32 lowerclip, 00078 l_int32 upperclip) 00079 { 00080 l_int32 i; 00081 l_uint32 *lined; 00082 00083 /* do all lines except last line */ 00084 memcpy(bufs2, datas, 4 * wpls); /* prime the buffer */ 00085 for (i = 0; i < h - 1; i++) { 00086 memcpy(bufs1, bufs2, 4 * wpls); 00087 memcpy(bufs2, datas + (i + 1) * wpls, 4 * wpls); 00088 lined = datad + i * wpld; 00089 ditherToBinaryLineLow(lined, w, bufs1, bufs2, lowerclip, upperclip, 0); 00090 } 00091 00092 /* do last line */ 00093 memcpy(bufs1, bufs2, 4 * wpls); 00094 lined = datad + (h - 1) * wpld; 00095 ditherToBinaryLineLow(lined, w, bufs1, bufs2, lowerclip, upperclip, 1); 00096 return; 00097 } 00098 00099 00100 /* 00101 * ditherToBinaryLineLow() 00102 * 00103 * Input: lined (ptr to beginning of dest line 00104 * w (width of image in pixels) 00105 * bufs1 (buffer of current source line) 00106 * bufs2 (buffer of next source line) 00107 * lowerclip (lower clip distance to black) 00108 * upperclip (upper clip distance to white) 00109 * lastlineflag (0 if not last dest line, 1 if last dest line) 00110 * Return: void 00111 * 00112 * Dispatches FS error diffusion dithering for 00113 * a single line of the image. If lastlineflag == 0, 00114 * both source buffers are used; otherwise, only bufs1 00115 * is used. We use source buffers because the error 00116 * is propagated into them, and we don't want to change 00117 * the input src image. 00118 * 00119 * We break dithering out line by line to make it 00120 * easier to combine functions like interpolative 00121 * scaling and error diffusion dithering, as such a 00122 * combination of operations obviates the need to 00123 * generate a 2x grayscale image as an intermediary. 00124 */ 00125 void 00126 ditherToBinaryLineLow(l_uint32 *lined, 00127 l_int32 w, 00128 l_uint32 *bufs1, 00129 l_uint32 *bufs2, 00130 l_int32 lowerclip, 00131 l_int32 upperclip, 00132 l_int32 lastlineflag) 00133 { 00134 l_int32 j; 00135 l_int32 oval, eval; 00136 l_uint8 fval1, fval2, rval, bval, dval; 00137 00138 if (lastlineflag == 0) { 00139 for (j = 0; j < w - 1; j++) { 00140 oval = GET_DATA_BYTE(bufs1, j); 00141 if (oval > 127) { /* binarize to OFF */ 00142 if ((eval = 255 - oval) > upperclip) { 00143 /* subtract from neighbors */ 00144 fval1 = (3 * eval) / 8; 00145 fval2 = eval / 4; 00146 rval = GET_DATA_BYTE(bufs1, j + 1); 00147 rval = L_MAX(0, rval - fval1); 00148 SET_DATA_BYTE(bufs1, j + 1, rval); 00149 bval = GET_DATA_BYTE(bufs2, j); 00150 bval = L_MAX(0, bval - fval1); 00151 SET_DATA_BYTE(bufs2, j, bval); 00152 dval = GET_DATA_BYTE(bufs2, j + 1); 00153 dval = L_MAX(0, dval - fval2); 00154 SET_DATA_BYTE(bufs2, j + 1, dval); 00155 } 00156 } 00157 else { /* oval <= 127; binarize to ON */ 00158 SET_DATA_BIT(lined, j); /* ON pixel */ 00159 if (oval > lowerclip) { 00160 /* add to neighbors */ 00161 fval1 = (3 * oval) / 8; 00162 fval2 = oval / 4; 00163 rval = GET_DATA_BYTE(bufs1, j + 1); 00164 rval = L_MIN(255, rval + fval1); 00165 SET_DATA_BYTE(bufs1, j + 1, rval); 00166 bval = GET_DATA_BYTE(bufs2, j); 00167 bval = L_MIN(255, bval + fval1); 00168 SET_DATA_BYTE(bufs2, j, bval); 00169 dval = GET_DATA_BYTE(bufs2, j + 1); 00170 dval = L_MIN(255, dval + fval2); 00171 SET_DATA_BYTE(bufs2, j + 1, dval); 00172 } 00173 } 00174 } 00175 00176 /* do last column: j = w - 1 */ 00177 oval = GET_DATA_BYTE(bufs1, j); 00178 if (oval > 127) { /* binarize to OFF */ 00179 if ((eval = 255 - oval) > upperclip) { 00180 /* subtract from neighbors */ 00181 fval1 = (3 * eval) / 8; 00182 bval = GET_DATA_BYTE(bufs2, j); 00183 bval = L_MAX(0, bval - fval1); 00184 SET_DATA_BYTE(bufs2, j, bval); 00185 } 00186 } 00187 else { /*oval <= 127; binarize to ON */ 00188 SET_DATA_BIT(lined, j); /* ON pixel */ 00189 if (oval > lowerclip) { 00190 /* add to neighbors */ 00191 fval1 = (3 * oval) / 8; 00192 bval = GET_DATA_BYTE(bufs2, j); 00193 bval = L_MIN(255, bval + fval1); 00194 SET_DATA_BYTE(bufs2, j, bval); 00195 } 00196 } 00197 } 00198 else { /* lastlineflag == 1 */ 00199 for (j = 0; j < w - 1; j++) { 00200 oval = GET_DATA_BYTE(bufs1, j); 00201 if (oval > 127) { /* binarize to OFF */ 00202 if ((eval = 255 - oval) > upperclip) { 00203 /* subtract from neighbors */ 00204 fval1 = (3 * eval) / 8; 00205 rval = GET_DATA_BYTE(bufs1, j + 1); 00206 rval = L_MAX(0, rval - fval1); 00207 SET_DATA_BYTE(bufs1, j + 1, rval); 00208 } 00209 } 00210 else { /* oval <= 127; binarize to ON */ 00211 SET_DATA_BIT(lined, j); /* ON pixel */ 00212 if (oval > lowerclip) { 00213 /* add to neighbors */ 00214 fval1 = (3 * oval) / 8; 00215 rval = GET_DATA_BYTE(bufs1, j + 1); 00216 rval = L_MIN(255, rval + fval1); 00217 SET_DATA_BYTE(bufs1, j + 1, rval); 00218 } 00219 } 00220 } 00221 00222 /* do last pixel: (i, j) = (h - 1, w - 1) */ 00223 oval = GET_DATA_BYTE(bufs1, j); 00224 if (oval < 128) 00225 SET_DATA_BIT(lined, j); /* ON pixel */ 00226 } 00227 00228 return; 00229 } 00230 00231 00232 00233 /*------------------------------------------------------------------* 00234 * Simple binarization with fixed threshold * 00235 *------------------------------------------------------------------*/ 00236 /* 00237 * thresholdToBinaryLow() 00238 * 00239 * If the source pixel is less than thresh, 00240 * the dest will be 1; otherwise, it will be 0 00241 */ 00242 void 00243 thresholdToBinaryLow(l_uint32 *datad, 00244 l_int32 w, 00245 l_int32 h, 00246 l_int32 wpld, 00247 l_uint32 *datas, 00248 l_int32 d, 00249 l_int32 wpls, 00250 l_int32 thresh) 00251 { 00252 l_int32 i; 00253 l_uint32 *lines, *lined; 00254 00255 for (i = 0; i < h; i++) { 00256 lines = datas + i * wpls; 00257 lined = datad + i * wpld; 00258 thresholdToBinaryLineLow(lined, w, lines, d, thresh); 00259 } 00260 return; 00261 } 00262 00263 00264 /* 00265 * thresholdToBinaryLineLow() 00266 * 00267 */ 00268 void 00269 thresholdToBinaryLineLow(l_uint32 *lined, 00270 l_int32 w, 00271 l_uint32 *lines, 00272 l_int32 d, 00273 l_int32 thresh) 00274 { 00275 l_int32 j, k, gval, scount, dcount; 00276 l_uint32 sword, dword; 00277 00278 PROCNAME("thresholdToBinaryLineLow"); 00279 00280 switch (d) 00281 { 00282 case 4: 00283 /* Unrolled as 4 source words, 1 dest word */ 00284 for (j = 0, scount = 0, dcount = 0; j + 31 < w; j += 32) { 00285 dword = 0; 00286 for (k = 0; k < 4; k++) { 00287 sword = lines[scount++]; 00288 dword <<= 8; 00289 gval = (sword >> 28) & 0xf; 00290 /* Trick used here and below: if gval < thresh then 00291 * gval - thresh < 0, so its high-order bit is 1, and 00292 * ((gval - thresh) >> 31) & 1 == 1; likewise, if 00293 * gval >= thresh, then ((gval - thresh) >> 31) & 1 == 0 00294 * Doing it this way avoids a random (and thus easily 00295 * mispredicted) branch on each pixel. */ 00296 dword |= ((gval - thresh) >> 24) & 128; 00297 gval = (sword >> 24) & 0xf; 00298 dword |= ((gval - thresh) >> 25) & 64; 00299 gval = (sword >> 20) & 0xf; 00300 dword |= ((gval - thresh) >> 26) & 32; 00301 gval = (sword >> 16) & 0xf; 00302 dword |= ((gval - thresh) >> 27) & 16; 00303 gval = (sword >> 12) & 0xf; 00304 dword |= ((gval - thresh) >> 28) & 8; 00305 gval = (sword >> 8) & 0xf; 00306 dword |= ((gval - thresh) >> 29) & 4; 00307 gval = (sword >> 4) & 0xf; 00308 dword |= ((gval - thresh) >> 30) & 2; 00309 gval = sword & 0xf; 00310 dword |= ((gval - thresh) >> 31) & 1; 00311 } 00312 lined[dcount++] = dword; 00313 } 00314 00315 if (j < w) { 00316 dword = 0; 00317 for (; j < w; j++) { 00318 if ((j & 7) == 0) { 00319 sword = lines[scount++]; 00320 } 00321 gval = (sword >> 28) & 0xf; 00322 sword <<= 4; 00323 dword |= (((gval - thresh) >> 31) & 1) << (31 - (j & 31)); 00324 } 00325 lined[dcount] = dword; 00326 } 00327 #if DEBUG_UNROLLING 00328 #define CHECK_BIT(a, b, c) if (GET_DATA_BIT(a, b) != c) { \ 00329 fprintf(stderr, "Error: mismatch at %d/%d(%d), %d vs %d\n", \ 00330 j, w, d, GET_DATA_BIT(a, b), c); } 00331 for (j = 0; j < w; j++) { 00332 gval = GET_DATA_QBIT(lines, j); 00333 CHECK_BIT(lined, j, gval < thresh ? 1 : 0); 00334 } 00335 #endif 00336 break; 00337 case 8: 00338 /* Unrolled as 8 source words, 1 dest word */ 00339 for (j = 0, scount = 0, dcount = 0; j + 31 < w; j += 32) { 00340 dword = 0; 00341 for (k = 0; k < 8; k++) { 00342 sword = lines[scount++]; 00343 dword <<= 4; 00344 gval = (sword >> 24) & 0xff; 00345 dword |= ((gval - thresh) >> 28) & 8; 00346 gval = (sword >> 16) & 0xff; 00347 dword |= ((gval - thresh) >> 29) & 4; 00348 gval = (sword >> 8) & 0xff; 00349 dword |= ((gval - thresh) >> 30) & 2; 00350 gval = sword & 0xff; 00351 dword |= ((gval - thresh) >> 31) & 1; 00352 } 00353 lined[dcount++] = dword; 00354 } 00355 00356 if (j < w) { 00357 dword = 0; 00358 for (; j < w; j++) { 00359 if ((j & 3) == 0) { 00360 sword = lines[scount++]; 00361 } 00362 gval = (sword >> 24) & 0xff; 00363 sword <<= 8; 00364 dword |= (((gval - thresh) >> 31) & 1) << (31 - (j & 31)); 00365 } 00366 lined[dcount] = dword; 00367 } 00368 #if DEBUG_UNROLLING 00369 for (j = 0; j < w; j++) { 00370 gval = GET_DATA_BYTE(lines, j); 00371 CHECK_BIT(lined, j, gval < thresh ? 1 : 0); 00372 } 00373 #undef CHECK_BIT 00374 #endif 00375 break; 00376 default: 00377 L_ERROR("src depth not 4 or 8 bpp", procName); 00378 break; 00379 } 00380 return; 00381 } 00382 00383 00384 /*---------------------------------------------------------------------* 00385 * Alternate implementation of dithering that uses lookup tables. * 00386 * This is analogous to the method used in dithering to 2 bpp. * 00387 *---------------------------------------------------------------------*/ 00388 /*! 00389 * ditherToBinaryLUTLow() 00390 * 00391 * Low-level function for doing Floyd-Steinberg error diffusion 00392 * dithering from 8 bpp (datas) to 1 bpp (datad). Two source 00393 * line buffers, bufs1 and bufs2, are provided, along with three 00394 * 256-entry lookup tables: tabval gives the output pixel value, 00395 * tab38 gives the extra (plus or minus) transferred to the pixels 00396 * directly to the left and below, and tab14 gives the extra 00397 * transferred to the diagonal below. The choice of 3/8 and 1/4 00398 * is traditional but arbitrary when you use a lookup table; the 00399 * only constraint is that the sum is 1. See other comments below. 00400 */ 00401 void 00402 ditherToBinaryLUTLow(l_uint32 *datad, 00403 l_int32 w, 00404 l_int32 h, 00405 l_int32 wpld, 00406 l_uint32 *datas, 00407 l_int32 wpls, 00408 l_uint32 *bufs1, 00409 l_uint32 *bufs2, 00410 l_int32 *tabval, 00411 l_int32 *tab38, 00412 l_int32 *tab14) 00413 { 00414 l_int32 i; 00415 l_uint32 *lined; 00416 00417 /* do all lines except last line */ 00418 memcpy(bufs2, datas, 4 * wpls); /* prime the buffer */ 00419 for (i = 0; i < h - 1; i++) { 00420 memcpy(bufs1, bufs2, 4 * wpls); 00421 memcpy(bufs2, datas + (i + 1) * wpls, 4 * wpls); 00422 lined = datad + i * wpld; 00423 ditherToBinaryLineLUTLow(lined, w, bufs1, bufs2, 00424 tabval, tab38, tab14, 0); 00425 } 00426 00427 /* do last line */ 00428 memcpy(bufs1, bufs2, 4 * wpls); 00429 lined = datad + (h - 1) * wpld; 00430 ditherToBinaryLineLUTLow(lined, w, bufs1, bufs2, tabval, tab38, tab14, 1); 00431 return; 00432 } 00433 00434 00435 /*! 00436 * ditherToBinaryLineLUTLow() 00437 * 00438 * Input: lined (ptr to beginning of dest line 00439 * w (width of image in pixels) 00440 * bufs1 (buffer of current source line) 00441 * bufs2 (buffer of next source line) 00442 * tabval (value to assign for current pixel) 00443 * tab38 (excess value to give to neighboring 3/8 pixels) 00444 * tab14 (excess value to give to neighboring 1/4 pixel) 00445 * lastlineflag (0 if not last dest line, 1 if last dest line) 00446 * Return: void 00447 */ 00448 void 00449 ditherToBinaryLineLUTLow(l_uint32 *lined, 00450 l_int32 w, 00451 l_uint32 *bufs1, 00452 l_uint32 *bufs2, 00453 l_int32 *tabval, 00454 l_int32 *tab38, 00455 l_int32 *tab14, 00456 l_int32 lastlineflag) 00457 { 00458 l_int32 j; 00459 l_int32 oval, tab38val, tab14val; 00460 l_uint8 rval, bval, dval; 00461 00462 if (lastlineflag == 0) { 00463 for (j = 0; j < w - 1; j++) { 00464 oval = GET_DATA_BYTE(bufs1, j); 00465 if (tabval[oval]) 00466 SET_DATA_BIT(lined, j); 00467 rval = GET_DATA_BYTE(bufs1, j + 1); 00468 bval = GET_DATA_BYTE(bufs2, j); 00469 dval = GET_DATA_BYTE(bufs2, j + 1); 00470 tab38val = tab38[oval]; 00471 if (tab38val == 0) 00472 continue; 00473 tab14val = tab14[oval]; 00474 if (tab38val < 0) { 00475 rval = L_MAX(0, rval + tab38val); 00476 bval = L_MAX(0, bval + tab38val); 00477 dval = L_MAX(0, dval + tab14val); 00478 } 00479 else { 00480 rval = L_MIN(255, rval + tab38val); 00481 bval = L_MIN(255, bval + tab38val); 00482 dval = L_MIN(255, dval + tab14val); 00483 } 00484 SET_DATA_BYTE(bufs1, j + 1, rval); 00485 SET_DATA_BYTE(bufs2, j, bval); 00486 SET_DATA_BYTE(bufs2, j + 1, dval); 00487 } 00488 00489 /* do last column: j = w - 1 */ 00490 oval = GET_DATA_BYTE(bufs1, j); 00491 if (tabval[oval]) 00492 SET_DATA_BIT(lined, j); 00493 bval = GET_DATA_BYTE(bufs2, j); 00494 tab38val = tab38[oval]; 00495 if (tab38val < 0) { 00496 bval = L_MAX(0, bval + tab38val); 00497 SET_DATA_BYTE(bufs2, j, bval); 00498 } 00499 else if (tab38val > 0 ) { 00500 bval = L_MIN(255, bval + tab38val); 00501 SET_DATA_BYTE(bufs2, j, bval); 00502 } 00503 } 00504 else { /* lastlineflag == 1 */ 00505 for (j = 0; j < w - 1; j++) { 00506 oval = GET_DATA_BYTE(bufs1, j); 00507 if (tabval[oval]) 00508 SET_DATA_BIT(lined, j); 00509 rval = GET_DATA_BYTE(bufs1, j + 1); 00510 tab38val = tab38[oval]; 00511 if (tab38val == 0) 00512 continue; 00513 if (tab38val < 0) 00514 rval = L_MAX(0, rval + tab38val); 00515 else 00516 rval = L_MIN(255, rval + tab38val); 00517 SET_DATA_BYTE(bufs1, j + 1, rval); 00518 } 00519 00520 /* do last pixel: (i, j) = (h - 1, w - 1) */ 00521 oval = GET_DATA_BYTE(bufs1, j); 00522 if (tabval[oval]) 00523 SET_DATA_BIT(lined, j); 00524 } 00525 00526 return; 00527 } 00528 00529 00530 /*! 00531 * make8To1DitherTables() 00532 * 00533 * Input: &tabval (value assigned to output pixel; 0 or 1) 00534 * &tab38 (amount propagated to pixels left and below) 00535 * &tab14 (amount propagated to pixel to left and down) 00536 * lowerclip (values near 0 where the excess is not propagated) 00537 * upperclip (values near 255 where the deficit is not propagated) 00538 * 00539 * Return: 0 if OK, 1 on error 00540 */ 00541 l_int32 00542 make8To1DitherTables(l_int32 **ptabval, 00543 l_int32 **ptab38, 00544 l_int32 **ptab14, 00545 l_int32 lowerclip, 00546 l_int32 upperclip) 00547 { 00548 l_int32 i; 00549 l_int32 *tabval, *tab38, *tab14; 00550 00551 PROCNAME("make8To1DitherTables"); 00552 00553 if (!ptabval || !ptab38 || !ptab14) 00554 return ERROR_INT("table ptrs not all defined", procName, 1); 00555 00556 /* 3 lookup tables: 1-bit value, (3/8)excess, and (1/4)excess */ 00557 if ((tabval = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL) 00558 return ERROR_INT("tabval not made", procName, 1); 00559 if ((tab38 = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL) 00560 return ERROR_INT("tab38 not made", procName, 1); 00561 if ((tab14 = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL) 00562 return ERROR_INT("tab14 not made", procName, 1); 00563 *ptabval = tabval; 00564 *ptab38 = tab38; 00565 *ptab14 = tab14; 00566 00567 for (i = 0; i < 256; i++) { 00568 if (i <= lowerclip) { 00569 tabval[i] = 1; 00570 tab38[i] = 0; 00571 tab14[i] = 0; 00572 } 00573 else if (i < 128) { 00574 tabval[i] = 1; 00575 tab38[i] = (3 * i + 4) / 8; 00576 tab14[i] = (i + 2) / 4; 00577 } 00578 else if (i < 255 - upperclip) { 00579 tabval[i] = 0; 00580 tab38[i] = (3 * (i - 255) + 4) / 8; 00581 tab14[i] = ((i - 255) + 2) / 4; 00582 } 00583 else { /* i >= 255 - upperclip */ 00584 tabval[i] = 0; 00585 tab38[i] = 0; 00586 tab14[i] = 0; 00587 } 00588 } 00589 00590 return 0; 00591 } 00592 00593 00594 /*------------------------------------------------------------------* 00595 * Dithering to 2 bpp * 00596 *------------------------------------------------------------------*/ 00597 /* 00598 * ditherTo2bppLow() 00599 * 00600 * Low-level function for doing Floyd-Steinberg error diffusion 00601 * dithering from 8 bpp (datas) to 2 bpp (datad). Two source 00602 * line buffers, bufs1 and bufs2, are provided, along with three 00603 * 256-entry lookup tables: tabval gives the output pixel value, 00604 * tab38 gives the extra (plus or minus) transferred to the pixels 00605 * directly to the left and below, and tab14 gives the extra 00606 * transferred to the diagonal below. The choice of 3/8 and 1/4 00607 * is traditional but arbitrary when you use a lookup table; the 00608 * only constraint is that the sum is 1. See other comments 00609 * below and in grayquant.c. 00610 */ 00611 void 00612 ditherTo2bppLow(l_uint32 *datad, 00613 l_int32 w, 00614 l_int32 h, 00615 l_int32 wpld, 00616 l_uint32 *datas, 00617 l_int32 wpls, 00618 l_uint32 *bufs1, 00619 l_uint32 *bufs2, 00620 l_int32 *tabval, 00621 l_int32 *tab38, 00622 l_int32 *tab14) 00623 { 00624 l_int32 i; 00625 l_uint32 *lined; 00626 00627 /* do all lines except last line */ 00628 memcpy(bufs2, datas, 4 * wpls); /* prime the buffer */ 00629 for (i = 0; i < h - 1; i++) { 00630 memcpy(bufs1, bufs2, 4 * wpls); 00631 memcpy(bufs2, datas + (i + 1) * wpls, 4 * wpls); 00632 lined = datad + i * wpld; 00633 ditherTo2bppLineLow(lined, w, bufs1, bufs2, tabval, tab38, tab14, 0); 00634 } 00635 00636 /* do last line */ 00637 memcpy(bufs1, bufs2, 4 * wpls); 00638 lined = datad + (h - 1) * wpld; 00639 ditherTo2bppLineLow(lined, w, bufs1, bufs2, tabval, tab38, tab14, 1); 00640 return; 00641 } 00642 00643 00644 /* 00645 * ditherTo2bppLineLow() 00646 * 00647 * Input: lined (ptr to beginning of dest line 00648 * w (width of image in pixels) 00649 * bufs1 (buffer of current source line) 00650 * bufs2 (buffer of next source line) 00651 * tabval (value to assign for current pixel) 00652 * tab38 (excess value to give to neighboring 3/8 pixels) 00653 * tab14 (excess value to give to neighboring 1/4 pixel) 00654 * lastlineflag (0 if not last dest line, 1 if last dest line) 00655 * Return: void 00656 * 00657 * Dispatches error diffusion dithering for 00658 * a single line of the image. If lastlineflag == 0, 00659 * both source buffers are used; otherwise, only bufs1 00660 * is used. We use source buffers because the error 00661 * is propagated into them, and we don't want to change 00662 * the input src image. 00663 * 00664 * We break dithering out line by line to make it 00665 * easier to combine functions like interpolative 00666 * scaling and error diffusion dithering, as such a 00667 * combination of operations obviates the need to 00668 * generate a 2x grayscale image as an intermediary. 00669 */ 00670 void 00671 ditherTo2bppLineLow(l_uint32 *lined, 00672 l_int32 w, 00673 l_uint32 *bufs1, 00674 l_uint32 *bufs2, 00675 l_int32 *tabval, 00676 l_int32 *tab38, 00677 l_int32 *tab14, 00678 l_int32 lastlineflag) 00679 { 00680 l_int32 j; 00681 l_int32 oval, tab38val, tab14val; 00682 l_uint8 rval, bval, dval; 00683 00684 if (lastlineflag == 0) { 00685 for (j = 0; j < w - 1; j++) { 00686 oval = GET_DATA_BYTE(bufs1, j); 00687 SET_DATA_DIBIT(lined, j, tabval[oval]); 00688 rval = GET_DATA_BYTE(bufs1, j + 1); 00689 bval = GET_DATA_BYTE(bufs2, j); 00690 dval = GET_DATA_BYTE(bufs2, j + 1); 00691 tab38val = tab38[oval]; 00692 tab14val = tab14[oval]; 00693 if (tab38val < 0) { 00694 rval = L_MAX(0, rval + tab38val); 00695 bval = L_MAX(0, bval + tab38val); 00696 dval = L_MAX(0, dval + tab14val); 00697 } 00698 else { 00699 rval = L_MIN(255, rval + tab38val); 00700 bval = L_MIN(255, bval + tab38val); 00701 dval = L_MIN(255, dval + tab14val); 00702 } 00703 SET_DATA_BYTE(bufs1, j + 1, rval); 00704 SET_DATA_BYTE(bufs2, j, bval); 00705 SET_DATA_BYTE(bufs2, j + 1, dval); 00706 } 00707 00708 /* do last column: j = w - 1 */ 00709 oval = GET_DATA_BYTE(bufs1, j); 00710 SET_DATA_DIBIT(lined, j, tabval[oval]); 00711 bval = GET_DATA_BYTE(bufs2, j); 00712 tab38val = tab38[oval]; 00713 if (tab38val < 0) 00714 bval = L_MAX(0, bval + tab38val); 00715 else 00716 bval = L_MIN(255, bval + tab38val); 00717 SET_DATA_BYTE(bufs2, j, bval); 00718 } 00719 else { /* lastlineflag == 1 */ 00720 for (j = 0; j < w - 1; j++) { 00721 oval = GET_DATA_BYTE(bufs1, j); 00722 SET_DATA_DIBIT(lined, j, tabval[oval]); 00723 rval = GET_DATA_BYTE(bufs1, j + 1); 00724 tab38val = tab38[oval]; 00725 if (tab38val < 0) 00726 rval = L_MAX(0, rval + tab38val); 00727 else 00728 rval = L_MIN(255, rval + tab38val); 00729 SET_DATA_BYTE(bufs1, j + 1, rval); 00730 } 00731 00732 /* do last pixel: (i, j) = (h - 1, w - 1) */ 00733 oval = GET_DATA_BYTE(bufs1, j); 00734 SET_DATA_DIBIT(lined, j, tabval[oval]); 00735 } 00736 00737 return; 00738 } 00739 00740 00741 /*! 00742 * make8To2DitherTables() 00743 * 00744 * Input: &tabval (value assigned to output pixel; 0, 1, 2 or 3) 00745 * &tab38 (amount propagated to pixels left and below) 00746 * &tab14 (amount propagated to pixel to left and down) 00747 * cliptoblack (values near 0 where the excess is not propagated) 00748 * cliptowhite (values near 255 where the deficit is not propagated) 00749 * 00750 * Return: 0 if OK, 1 on error 00751 */ 00752 l_int32 00753 make8To2DitherTables(l_int32 **ptabval, 00754 l_int32 **ptab38, 00755 l_int32 **ptab14, 00756 l_int32 cliptoblack, 00757 l_int32 cliptowhite) 00758 { 00759 l_int32 i; 00760 l_int32 *tabval, *tab38, *tab14; 00761 00762 PROCNAME("make8To2DitherTables"); 00763 00764 /* 3 lookup tables: 2-bit value, (3/8)excess, and (1/4)excess */ 00765 if ((tabval = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL) 00766 return ERROR_INT("tabval not made", procName, 1); 00767 if ((tab38 = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL) 00768 return ERROR_INT("tab38 not made", procName, 1); 00769 if ((tab14 = (l_int32 *)CALLOC(256, sizeof(l_int32))) == NULL) 00770 return ERROR_INT("tab14 not made", procName, 1); 00771 *ptabval = tabval; 00772 *ptab38 = tab38; 00773 *ptab14 = tab14; 00774 00775 for (i = 0; i < 256; i++) { 00776 if (i <= cliptoblack) { 00777 tabval[i] = 0; 00778 tab38[i] = 0; 00779 tab14[i] = 0; 00780 } 00781 else if (i < 43) { 00782 tabval[i] = 0; 00783 tab38[i] = (3 * i + 4) / 8; 00784 tab14[i] = (i + 2) / 4; 00785 } 00786 else if (i < 85) { 00787 tabval[i] = 1; 00788 tab38[i] = (3 * (i - 85) - 4) / 8; 00789 tab14[i] = ((i - 85) - 2) / 4; 00790 } 00791 else if (i < 128) { 00792 tabval[i] = 1; 00793 tab38[i] = (3 * (i - 85) + 4) / 8; 00794 tab14[i] = ((i - 85) + 2) / 4; 00795 } 00796 else if (i < 170) { 00797 tabval[i] = 2; 00798 tab38[i] = (3 * (i - 170) - 4) / 8; 00799 tab14[i] = ((i - 170) - 2) / 4; 00800 } 00801 else if (i < 213) { 00802 tabval[i] = 2; 00803 tab38[i] = (3 * (i - 170) + 4) / 8; 00804 tab14[i] = ((i - 170) + 2) / 4; 00805 } 00806 else if (i < 255 - cliptowhite) { 00807 tabval[i] = 3; 00808 tab38[i] = (3 * (i - 255) - 4) / 8; 00809 tab14[i] = ((i - 255) - 2) / 4; 00810 } 00811 else { /* i >= 255 - cliptowhite */ 00812 tabval[i] = 3; 00813 tab38[i] = 0; 00814 tab14[i] = 0; 00815 } 00816 } 00817 00818 #if 0 00819 for (i = 0; i < 256; i++) 00820 fprintf(stderr, "tabval[%d] = %d, tab38[%d] = %d, tab14[%d] = %d\n", 00821 i, tabval[i], i, tab38[i], i, tab14[i]); 00822 #endif 00823 00824 return 0; 00825 } 00826 00827 00828 /*------------------------------------------------------------------* 00829 * Simple thresholding to 2 bpp * 00830 *------------------------------------------------------------------*/ 00831 /* 00832 * thresholdTo2bppLow() 00833 * 00834 * Low-level function for thresholding from 8 bpp (datas) to 00835 * 2 bpp (datad), using thresholds implicitly defined through @tab, 00836 * a 256-entry lookup table that gives a 2-bit output value 00837 * for each possible input. 00838 * 00839 * For each line, unroll the loop so that for each 32 bit src word, 00840 * representing four consecutive 8-bit pixels, we compose one byte 00841 * of output consisiting of four 2-bit pixels. 00842 */ 00843 void 00844 thresholdTo2bppLow(l_uint32 *datad, 00845 l_int32 h, 00846 l_int32 wpld, 00847 l_uint32 *datas, 00848 l_int32 wpls, 00849 l_int32 *tab) 00850 { 00851 l_uint8 sval1, sval2, sval3, sval4, dval; 00852 l_int32 i, j, k; 00853 l_uint32 *lines, *lined; 00854 00855 for (i = 0; i < h; i++) { 00856 lines = datas + i * wpls; 00857 lined = datad + i * wpld; 00858 for (j = 0; j < wpls; j++) { 00859 k = 4 * j; 00860 sval1 = GET_DATA_BYTE(lines, k); 00861 sval2 = GET_DATA_BYTE(lines, k + 1); 00862 sval3 = GET_DATA_BYTE(lines, k + 2); 00863 sval4 = GET_DATA_BYTE(lines, k + 3); 00864 dval = (tab[sval1] << 6) | (tab[sval2] << 4) | 00865 (tab[sval3] << 2) | tab[sval4]; 00866 SET_DATA_BYTE(lined, j, dval); 00867 } 00868 } 00869 return; 00870 } 00871 00872 00873 /*------------------------------------------------------------------* 00874 * Simple thresholding to 4 bpp * 00875 *------------------------------------------------------------------*/ 00876 /* 00877 * thresholdTo4bppLow() 00878 * 00879 * Low-level function for thresholding from 8 bpp (datas) to 00880 * 4 bpp (datad), using thresholds implicitly defined through @tab, 00881 * a 256-entry lookup table that gives a 4-bit output value 00882 * for each possible input. 00883 * 00884 * For each line, unroll the loop so that for each 32 bit src word, 00885 * representing four consecutive 8-bit pixels, we compose two bytes 00886 * of output consisiting of four 4-bit pixels. 00887 */ 00888 void 00889 thresholdTo4bppLow(l_uint32 *datad, 00890 l_int32 h, 00891 l_int32 wpld, 00892 l_uint32 *datas, 00893 l_int32 wpls, 00894 l_int32 *tab) 00895 { 00896 l_uint8 sval1, sval2, sval3, sval4; 00897 l_uint16 dval; 00898 l_int32 i, j, k; 00899 l_uint32 *lines, *lined; 00900 00901 for (i = 0; i < h; i++) { 00902 lines = datas + i * wpls; 00903 lined = datad + i * wpld; 00904 for (j = 0; j < wpls; j++) { 00905 k = 4 * j; 00906 sval1 = GET_DATA_BYTE(lines, k); 00907 sval2 = GET_DATA_BYTE(lines, k + 1); 00908 sval3 = GET_DATA_BYTE(lines, k + 2); 00909 sval4 = GET_DATA_BYTE(lines, k + 3); 00910 dval = (tab[sval1] << 12) | (tab[sval2] << 8) | 00911 (tab[sval3] << 4) | tab[sval4]; 00912 SET_DATA_TWO_BYTES(lined, j, dval); 00913 } 00914 } 00915 return; 00916 } 00917 00918