Leptonica 1.68
C Image Processing Library

grayquantlow.c

Go to the documentation of this file.
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 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines