home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / modules / libimg / src / dither.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  12.2 KB  |  375 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20. #include "xp.h"
  21. */
  22. #include "if.h"
  23. #include "il.h"
  24.  
  25. #include "jinclude.h"
  26. #include "jpeglib.h"
  27. #include "jpegint.h"
  28. #include "jerror.h"
  29.  
  30.  
  31. /* BEGIN code adapted from jpeg library */
  32.  
  33. typedef INT32 FSERROR;        /* 16 bits should be enough */
  34. typedef int LOCFSERROR;        /* use 'int' for calculation temps */
  35.  
  36. typedef FSERROR FAR *FSERRPTR;    /* pointer to error array (in FAR storage!) */
  37.  
  38. typedef struct my_cquantize_str {
  39.     /* Variables for Floyd-Steinberg dithering */
  40.     FSERRPTR fserrors[3];        /* accumulated errors */
  41.     boolean on_odd_row;        /* flag to remember which row we are on */
  42. } my_cquantize;
  43.  
  44. typedef my_cquantize *my_cquantize_ptr;
  45.  
  46. static JSAMPLE *the_sample_range_limit = NULL;
  47.  
  48. /* allocate and fill in the sample_range_limit table */
  49. int
  50. il_setup_quantize(void)
  51. {
  52.     JSAMPLE *table;
  53.     int i;
  54.  
  55.     if(the_sample_range_limit)
  56.         return TRUE;
  57.  
  58.     /* lost for ever */
  59.     table = (JSAMPLE *)XP_ALLOC((5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE));
  60.     if (!table) 
  61.     {
  62.         XP_TRACE(("il: range limit table lossage"));
  63.         return FALSE;
  64.     }
  65.  
  66.     table += (MAXJSAMPLE+1);    /* allow negative subscripts of simple table */
  67.     the_sample_range_limit = table;
  68.  
  69.     /* First segment of "simple" table: limit[x] = 0 for x < 0 */
  70.     MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE));
  71.  
  72.     /* Main part of "simple" table: limit[x] = x */
  73.     for (i = 0; i <= MAXJSAMPLE; i++)
  74.         table[i] = (JSAMPLE) i;
  75.  
  76.     table += CENTERJSAMPLE;    /* Point to where post-IDCT table starts */
  77.  
  78.     /* End of simple table, rest of first half of post-IDCT table */
  79.     for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++)
  80.         table[i] = MAXJSAMPLE;
  81.  
  82.     /* Second half of post-IDCT table */
  83.     MEMZERO(table + (2 * (MAXJSAMPLE+1)),
  84.             (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE));
  85.     MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE),
  86.             the_sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE));
  87.  
  88.     return TRUE;
  89. }
  90.  
  91.  
  92. /* Must remain idempotent.  Also used to make sure that the ic->quantize has the same 
  93. colorSpace info as the rest of ic. */
  94. int
  95. il_init_quantize(il_container *ic)
  96. {
  97.     size_t arraysize;
  98.     int i, j;
  99.     my_cquantize_ptr cquantize;
  100.  
  101.     if (ic->quantize)
  102.         il_free_quantize(ic);
  103.  
  104.     ic->quantize = XP_NEW_ZAP(my_cquantize);
  105.     if (!ic->quantize) 
  106.     {
  107.     loser:
  108.         ILTRACE(0,("il: MEM il_init_quantize"));
  109.         return FALSE;
  110.     }
  111.  
  112.     cquantize = (my_cquantize_ptr) ic->quantize;
  113.     arraysize = (size_t) ((ic->image->header.width + 2) * SIZEOF(FSERROR));
  114.     for (i = 0; i < 3; i++) 
  115.     {
  116.         cquantize->fserrors[i] = (FSERRPTR) XP_CALLOC(1, arraysize);
  117.         if (!cquantize->fserrors[i]) 
  118.         {
  119.             /* ran out of memory part way thru */
  120.             for (j = 0; j < i; j++) 
  121.             {
  122.                 if (cquantize->fserrors[j])
  123.                 {
  124.                     XP_FREE(cquantize->fserrors[j]);
  125.                     cquantize->fserrors[j]=0;
  126.                 }
  127.             }
  128.             if (cquantize)
  129.             {
  130.                 XP_FREE(cquantize);
  131.                 ic->quantize = 0;
  132.             }
  133.             goto loser;
  134.         }
  135.     }
  136.  
  137.     return TRUE;
  138. }
  139.  
  140. /*
  141. ** Free up quantizer information attached to ic. If this is the last
  142. ** quantizer then free up the sample range limit table.
  143. */
  144. void
  145. il_free_quantize(il_container *ic)
  146. {
  147.     my_cquantize_ptr cquantize = (my_cquantize_ptr) ic->quantize;
  148.     int i;
  149.  
  150.     if (cquantize) 
  151.     {
  152. #ifdef DEBUG
  153.         if (il_debug > 5) 
  154.             XP_TRACE(("il: 0x%x: free quantize", ic));
  155. #endif
  156.         for (i = 0; i < 3; i++) 
  157.         {
  158.             if (cquantize->fserrors[i]) 
  159.             {
  160.                 XP_FREE(cquantize->fserrors[i]);
  161.                 cquantize->fserrors[i] = 0;
  162.             }
  163.         }
  164.  
  165.         XP_FREE(cquantize);
  166.         ic->quantize = 0;
  167.     }
  168. }
  169.  
  170.  
  171. /* floyd-steinberg dithering */
  172.  
  173. #ifdef XP_MAC
  174. #ifndef powerc
  175. #pragma peephole on
  176. #endif
  177. #endif
  178.  
  179. void
  180. il_quantize_fs_dither(il_container *ic, const uint8 *mask,
  181.                       const uint8 *input_buf, int x_offset,
  182.                       uint8 XP_HUGE *output_buf, int width)
  183. {
  184.     my_cquantize_ptr cquantize;
  185.     register LOCFSERROR r_cur, g_cur, b_cur;       /* current error or pixel
  186.                                                       value */
  187.     LOCFSERROR r_belowerr, g_belowerr, b_belowerr; /* error for pixel below
  188.                                                       cur */
  189.     LOCFSERROR r_bpreverr, g_bpreverr, b_bpreverr; /* error for below/prev
  190.                                                       col */
  191.     LOCFSERROR r_bnexterr, g_bnexterr, b_bnexterr; /* error for below/next
  192.                                                       col */
  193.     LOCFSERROR delta;
  194.     FSERRPTR r_errorptr, g_errorptr, b_errorptr;   /* fserrors[] at column
  195.                                                       before current */
  196.     const JSAMPLE* input_ptr;
  197.     JSAMPLE XP_HUGE * output_ptr;
  198.     IL_ColorMap *cmap = &ic->image->header.color_space->cmap;
  199.     IL_RGB *map = cmap->map;              /* The colormap array. */
  200.     IL_RGB *map_entry;                    /* Current entry in the colormap. */
  201.     uint8 *lookup_table = cmap->table;    /* Lookup table for the colormap. */
  202.     const uint8 *maskp;
  203.     uint8 map_index;
  204.     int dir;                   /* 1 for left-to-right, -1 for right-to-left */
  205.     JDIMENSION col;
  206.     JSAMPLE *range_limit = the_sample_range_limit;
  207.     SHIFT_TEMPS
  208.  
  209.     cquantize = (my_cquantize_ptr) ic->quantize;
  210.     
  211.     output_buf += x_offset;
  212.  
  213.     /* Initialize output values to 0 so can process components separately */
  214.     if (mask) {
  215.         output_ptr = output_buf;
  216.         maskp = mask;
  217.         for (col = width; col > 0; col--)
  218.             *output_ptr++ &= ~*maskp++;
  219.     } else {
  220.         XP_BZERO((void XP_HUGE *) output_buf,
  221.                  (size_t) (width * SIZEOF(JSAMPLE)));
  222.     }
  223.  
  224.     input_ptr = input_buf;
  225.     output_ptr = output_buf;
  226.     maskp = mask;
  227.     if (cquantize->on_odd_row) {
  228.         int total_offset;
  229.  
  230.         /* work right to left in this row */
  231.         input_ptr += 3 * width - 1; /* so point to the blue sample of the
  232.                                        rightmost pixel */
  233.         output_ptr += width-1;
  234.         dir = -1;
  235.         /* => entry after last column */
  236.         total_offset = x_offset + (width + 1);
  237.         r_errorptr = cquantize->fserrors[0] + total_offset;
  238.         g_errorptr = cquantize->fserrors[1] + total_offset;
  239.         b_errorptr = cquantize->fserrors[2] + total_offset;
  240.         maskp += (width - 1);
  241.     } 
  242.     else {
  243.         /* work left to right in this row */
  244.         dir = 1;
  245.         /* => entry before first column */
  246.         r_errorptr = cquantize->fserrors[0] + x_offset;
  247.         g_errorptr = cquantize->fserrors[1] + x_offset;
  248.         b_errorptr = cquantize->fserrors[2] + x_offset;
  249.     }
  250.  
  251.     /* Preset error values: no error propagated to first pixel from left */
  252.     r_cur = g_cur = b_cur = 0;
  253.  
  254.     /* and no error propagated to row below yet */
  255.     r_belowerr = g_belowerr = b_belowerr = 0;
  256.     r_bpreverr = g_bpreverr = b_bpreverr = 0;
  257.  
  258.     for (col = width; col > 0; col--) {
  259.         /* cur holds the error propagated from the previous pixel on the
  260.          * current line.  Add the error propagated from the previous line
  261.          * to form the complete error correction term for this pixel, and
  262.          * round the error term (which is expressed * 16) to an integer.
  263.          * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
  264.          * for either sign of the error value.
  265.          * Note: errorptr points to *previous* column's array entry.
  266.          */
  267.         r_cur = RIGHT_SHIFT(r_cur + r_errorptr[dir] + 8, 4);
  268.         g_cur = RIGHT_SHIFT(g_cur + g_errorptr[dir] + 8, 4);
  269.         b_cur = RIGHT_SHIFT(b_cur + b_errorptr[dir] + 8, 4);
  270.  
  271.         /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
  272.          * The maximum error is +- MAXJSAMPLE; this sets the required size
  273.          * of the range_limit array.
  274.          */
  275.         if (dir > 0) {
  276.             r_cur += GETJSAMPLE(*input_ptr);
  277.             r_cur = GETJSAMPLE(range_limit[r_cur]);
  278.             input_ptr++;
  279.             g_cur += GETJSAMPLE(*input_ptr);
  280.             g_cur = GETJSAMPLE(range_limit[g_cur]);
  281.             input_ptr++;
  282.             b_cur += GETJSAMPLE(*input_ptr);
  283.             b_cur = GETJSAMPLE(range_limit[b_cur]);
  284.             input_ptr++;
  285.         }
  286.         else {
  287.             b_cur += GETJSAMPLE(*input_ptr);
  288.             b_cur = GETJSAMPLE(range_limit[b_cur]);
  289.             input_ptr--;
  290.             g_cur += GETJSAMPLE(*input_ptr);
  291.             g_cur = GETJSAMPLE(range_limit[g_cur]);
  292.             input_ptr--;
  293.             r_cur += GETJSAMPLE(*input_ptr);
  294.             r_cur = GETJSAMPLE(range_limit[r_cur]);
  295.             input_ptr--;
  296.         }
  297.  
  298.         /* Select output value, accumulate into output code for this pixel */
  299.         map_index = COLORMAP_INDEX(lookup_table, r_cur, g_cur, b_cur);
  300.         if (mask) {
  301.             if (*maskp)
  302.                 *output_ptr = map_index;
  303.             maskp += dir;
  304.         } else {
  305.             *output_ptr = map_index;
  306.         }
  307.  
  308.         /* Compute the actual representation error at this pixel */
  309.         map_entry = map + map_index;
  310.         r_cur -= GETJSAMPLE(map_entry->red);
  311.         g_cur -= GETJSAMPLE(map_entry->green);
  312.         b_cur -= GETJSAMPLE(map_entry->blue);
  313.  
  314.         /* Compute error fractions to be propagated to adjacent pixels.
  315.          * Add these into the running sums, and simultaneously shift the
  316.          * next-line error sums left by 1 column.
  317.          */
  318.         r_bnexterr = r_cur;
  319.         delta = r_cur * 2;
  320.         r_cur += delta;        /* form error * 3 */
  321.         r_errorptr[0] = (FSERROR) (r_bpreverr + r_cur);
  322.         r_cur += delta;        /* form error * 5 */
  323.         r_bpreverr = r_belowerr + r_cur;
  324.         r_belowerr = r_bnexterr;
  325.         r_cur += delta;        /* form error * 7 */
  326.  
  327.         g_bnexterr = g_cur;
  328.         delta = g_cur * 2;
  329.         g_cur += delta;        /* form error * 3 */
  330.         g_errorptr[0] = (FSERROR) (g_bpreverr + g_cur);
  331.         g_cur += delta;        /* form error * 5 */
  332.         g_bpreverr = g_belowerr + g_cur;
  333.         g_belowerr = g_bnexterr;
  334.         g_cur += delta;        /* form error * 7 */
  335.  
  336.         b_bnexterr = b_cur;
  337.         delta = b_cur * 2;
  338.         b_cur += delta;        /* form error * 3 */
  339.         b_errorptr[0] = (FSERROR) (b_bpreverr + b_cur);
  340.         b_cur += delta;        /* form error * 5 */
  341.         b_bpreverr = b_belowerr + b_cur;
  342.         b_belowerr = b_bnexterr;
  343.         b_cur += delta;        /* form error * 7 */
  344.  
  345.         /* At this point cur contains the 7/16 error value to be propagated
  346.          * to the next pixel on the current line, and all the errors for the
  347.          * next line have been shifted over. We are therefore ready to move on.
  348.          * Note: the input_ptr has already been advanced.
  349.          */
  350.         output_ptr += dir;    /* advance output ptr to next column */
  351.         r_errorptr += dir;    /* advance errorptr to current column */
  352.         g_errorptr += dir;    /* advance errorptr to current column */
  353.         b_errorptr += dir;    /* advance errorptr to current column */
  354.     }
  355.     
  356.     /* Post-loop cleanup: we must unload the final error value into the
  357.      * final fserrors[] entry.  Note we need not unload belowerr because
  358.      * it is for the dummy column before or after the actual array.
  359.      */
  360.     r_errorptr[0] = (FSERROR) r_bpreverr; /* unload prev err into array */
  361.     g_errorptr[0] = (FSERROR) g_bpreverr; /* unload prev err into array */
  362.     b_errorptr[0] = (FSERROR) b_bpreverr; /* unload prev err into array */
  363.  
  364.     cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE);
  365. }
  366.  
  367. #ifdef XP_MAC
  368. #ifndef powerc
  369. #pragma peephole reset
  370. #endif
  371. #endif
  372.  
  373. /* END code adapted from jpeg library */
  374.  
  375.