Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

quantize.c File Reference

#include "config.h"
#include "gifsicle.h"
#include <assert.h>
#include <string.h>

Go to the source code of this file.


Data Structures

struct  adaptive_slot
struct  color_hash_item
struct  Gif_Histogram

Defines

#define min(a, b)   ((a) < (b) ? (a) : (b))
#define max(a, b)   ((a) > (b) ? (a) : (b))
#define COLOR_HASH_SIZE   20023
#define COLOR_HASH_CODE(r, g, b)   ((u_int32_t)(r * 33023 + g * 30013 + b * 27011) % COLOR_HASH_SIZE)
#define HASH_ITEM_ALLOC_AMOUNT   512
#define DITHER_SCALE   1024
#define DITHER_SCALE_M1   (DITHER_SCALE-1)
#define N_RANDOM_VALUES   512

Typedefs

typedef Gif_Histogram Gif_Histogram

Functions

void add_histogram_color (Gif_Color *, Gif_Histogram *, unsigned long)
void init_histogram (Gif_Histogram *new_hist, Gif_Histogram *old_hist)
void delete_histogram (Gif_Histogram *hist)
int popularity_sort_compare (const void *va, const void *vb)
int pixel_sort_compare (const void *va, const void *vb)
Gif_Colorhistogram (Gif_Stream *gfs, int *nhist_store)
int red_sort_compare (const void *va, const void *vb)
int green_sort_compare (const void *va, const void *vb)
int blue_sort_compare (const void *va, const void *vb)
void assert_hist_transparency (Gif_Color *hist, int nhist)
Gif_Colormapcolormap_median_cut (Gif_Color *hist, int nhist, int adapt_size)
Gif_Colormapcolormap_diversity (Gif_Color *hist, int nhist, int adapt_size, int blend)
Gif_Colormapcolormap_blend_diversity (Gif_Color *hist, int nhist, int adapt_size)
Gif_Colormapcolormap_flat_diversity (Gif_Color *hist, int nhist, int adapt_size)
color_hash_item ** new_color_hash (void)
color_hash_itemnew_color_hash_item (byte red, byte green, byte blue)
void free_all_color_hash_items (void)
int hash_color (int red, int green, int blue, color_hash_item **hash, Gif_Colormap *new_cm)
void colormap_image_posterize (Gif_Image *gfi, byte *new_data, Gif_Colormap *old_cm, Gif_Colormap *new_cm, color_hash_item **hash, u_int32_t *histogram)
void colormap_image_floyd_steinberg (Gif_Image *gfi, byte *all_new_data, Gif_Colormap *old_cm, Gif_Colormap *new_cm, color_hash_item **hash, u_int32_t *histogram)
int try_assign_transparency (Gif_Image *gfi, Gif_Colormap *old_cm, byte *new_data, Gif_Colormap *new_cm, int *new_ncol, u_int32_t *histogram)
void colormap_stream (Gif_Stream *gfs, Gif_Colormap *new_cm, colormap_image_func image_changer)

Variables

color_hash_itemhash_item_alloc_list
int hash_item_alloc_left

Define Documentation

#define COLOR_HASH_CODE r,
g,
b       ((u_int32_t)(r * 33023 + g * 30013 + b * 27011) % COLOR_HASH_SIZE)
 

Definition at line 537 of file quantize.c.

Referenced by hash_color().

#define COLOR_HASH_SIZE   20023
 

Definition at line 536 of file quantize.c.

Referenced by new_color_hash().

#define DITHER_SCALE   1024
 

Definition at line 707 of file quantize.c.

Referenced by colormap_image_floyd_steinberg().

#define DITHER_SCALE_M1   (DITHER_SCALE-1)
 

Definition at line 708 of file quantize.c.

Referenced by colormap_image_floyd_steinberg().

#define HASH_ITEM_ALLOC_AMOUNT   512
 

Definition at line 546 of file quantize.c.

Referenced by free_all_color_hash_items(), and new_color_hash_item().

#define max a,
b       ((a) > (b) ? (a) : (b))
 

Definition at line 190 of file quantize.c.

#define min a,
b       ((a) < (b) ? (a) : (b))
 

Definition at line 189 of file quantize.c.

#define N_RANDOM_VALUES   512
 

Definition at line 709 of file quantize.c.

Referenced by colormap_image_floyd_steinberg().


Typedef Documentation

typedef struct Gif_Histogram Gif_Histogram
 


Function Documentation

void add_histogram_color Gif_Color  ,
Gif_Histogram  ,
unsigned    long
[static]
 

Definition at line 47 of file quantize.c.

References Gif_Color::blue, Gif_Histogram::c, Gif_Histogram::cap, color, delete_histogram(), Gif_Color::green, Gif_Color::haspixel, i, init_histogram(), Gif_Histogram::n, Gif_Color::pixel, and Gif_Color::red.

Referenced by histogram(), and init_histogram().

00048 {
00049   Gif_Color *hc = hist->c;
00050   int hcap = hist->cap - 1;
00051   int i = (((color->red & 0xF0) << 4) | (color->green & 0xF0)
00052            | (color->blue >> 4)) & hcap;
00053   int hash2 = ((((color->red & 0x0F) << 8) | ((color->green & 0x0F) << 4)
00054                 | (color->blue & 0x0F)) & hcap) | 1;
00055   
00056   for (; hc[i].haspixel; i = (i + hash2) & hcap)
00057     if (hc[i].red == color->red && hc[i].green == color->green
00058         && hc[i].blue == color->blue) {
00059       hc[i].pixel += count;
00060       color->haspixel = 1;
00061       color->pixel = i;
00062       return;
00063     }
00064 
00065   if (hist->n > ((hist->cap * 7) >> 3)) {
00066     Gif_Histogram new_hist;
00067     init_histogram(&new_hist, hist);
00068     delete_histogram(hist);
00069     *hist = new_hist;
00070     hc = hist->c;               /* 31.Aug.1999 - bug fix from Steven Marthouse
00071                                    <comments@vrml3d.com> */
00072   }
00073 
00074   hist->n++;
00075   hc[i] = *color;
00076   hc[i].haspixel = 1;
00077   hc[i].pixel = count;
00078   color->haspixel = 1;
00079   color->pixel = i;
00080 }

void assert_hist_transparency Gif_Color   hist,
int    nhist
[static]
 

Definition at line 218 of file quantize.c.

References i.

Referenced by colormap_diversity(), and colormap_median_cut().

00219 {
00220   int i;
00221   for (i = 1; i < nhist; i++)
00222     assert(hist[i].haspixel != 255);
00223 }

int blue_sort_compare const void *    va,
const void *    vb
[static]
 

Definition at line 209 of file quantize.c.

References a, and Gif_Color::blue.

Referenced by colormap_median_cut().

00210 {
00211   const Gif_Color *a = (const Gif_Color *)va;
00212   const Gif_Color *b = (const Gif_Color *)vb;
00213   return a->blue - b->blue;
00214 }

Gif_Colormap* colormap_blend_diversity Gif_Color   hist,
int    nhist,
int    adapt_size
 

Definition at line 517 of file quantize.c.

References colormap_diversity().

00518 {
00519   return colormap_diversity(hist, nhist, adapt_size, 1);
00520 }

Gif_Colormap* colormap_diversity Gif_Color   hist,
int    nhist,
int    adapt_size,
int    blend
[static]
 

Definition at line 372 of file quantize.c.

References assert_hist_transparency(), Gif_Color::blue, Gif_Colormap::col, fatal_error(), Gif_DeleteArray, Gif_NewArray, Gif_NewFullColormap(), Gif_Color::green, Gif_Color::haspixel, i, Gif_Colormap::ncol, Gif_Color::pixel, popularity_sort_compare(), Gif_Color::red, u_int32_t, and warning().

Referenced by colormap_blend_diversity(), and colormap_flat_diversity().

00373 {
00374   u_int32_t *min_dist = Gif_NewArray(u_int32_t, nhist);
00375   int *closest = Gif_NewArray(int, nhist);
00376   Gif_Colormap *gfcm = Gif_NewFullColormap(adapt_size, 256);
00377   Gif_Color *adapt = gfcm->col;
00378   int nadapt = 0;
00379   int i, j, match = 0;
00380   
00381   /* This code was uses XV's modified diversity algorithm, and was written
00382      with reference to XV's implementation of that algorithm by John Bradley
00383      <bradley@cis.upenn.edu> and Tom Lane <Tom.Lane@g.gp.cs.cmu.edu>. */
00384   
00385   if (adapt_size < 2 || adapt_size > 256)
00386     fatal_error("adaptive palette size must be between 2 and 256");
00387   if (adapt_size > nhist) {
00388     warning("trivial adaptive palette (only %d colors in source)", nhist);
00389     adapt_size = nhist;
00390   }
00391   
00392   /* 0. remove any transparent color from consideration; reduce adaptive
00393      palette size to accommodate transparency if it looks like that'll be
00394      necessary */
00395   assert_hist_transparency(hist, nhist);
00396   /* It will be necessary to accommodate transparency if (1) there is
00397      transparency in the image; (2) the adaptive palette isn't trivial; and
00398      (3) there are a small number of colors in the image (arbitrary constant:
00399      <= 265), so it's likely that most images will use most of the slots, so
00400      it's likely there won't be unused slots. */
00401   if (adapt_size > 2 && adapt_size < nhist && hist[0].haspixel == 255
00402       && nhist <= 265)
00403     adapt_size--;
00404   if (hist[0].haspixel == 255) {
00405     hist[0] = hist[nhist - 1];
00406     nhist--;
00407   }
00408   
00409   /* blending has bad effects when there are very few colors */
00410   if (adapt_size < 4)
00411     blend = 0;
00412   
00413   /* 1. initialize min_dist and sort the colors in order of popularity. */
00414   for (i = 0; i < nhist; i++)
00415     min_dist[i] = 0x7FFFFFFF;
00416   
00417   qsort(hist, nhist, sizeof(Gif_Color), popularity_sort_compare);
00418   
00419   /* 2. choose colors one at a time */
00420   for (nadapt = 0; nadapt < adapt_size; nadapt++) {
00421     int chosen = 0;
00422     
00423     /* 2.1. choose the color to be added */
00424     if (nadapt == 0 || (nadapt >= 10 && nadapt % 2 == 0)) {
00425       /* 2.1a. choose based on popularity from unchosen colors; we've sorted
00426          them on popularity, so just choose the first in the list */
00427       for (; chosen < nhist; chosen++)
00428         if (min_dist[chosen])
00429           break;
00430       
00431     } else {
00432       /* 2.1b. choose based on diversity from unchosen colors */
00433       u_int32_t chosen_dist = 0;
00434       for (i = 0; i < nhist; i++)
00435         if (min_dist[i] > chosen_dist) {
00436           chosen = i;
00437           chosen_dist = min_dist[i];
00438         }
00439     }
00440     
00441     /* 2.2. add the color */
00442     min_dist[chosen] = 0;
00443     closest[chosen] = nadapt;
00444     
00445     /* 2.3. adjust the min_dist array */
00446     {
00447       int red = hist[chosen].red, green = hist[chosen].green,
00448         blue = hist[chosen].blue;
00449       Gif_Color *h = hist;
00450       for (i = 0; i < nhist; i++, h++)
00451         if (min_dist[i]) {
00452           u_int32_t dist = (h->red - red) * (h->red - red)
00453             + (h->green - green) * (h->green - green)
00454             + (h->blue - blue) * (h->blue - blue);
00455           if (dist < min_dist[i]) {
00456             min_dist[i] = dist;
00457             closest[i] = nadapt;
00458           }
00459         }
00460     }
00461   }
00462   
00463   /* 3. make the new palette by choosing one color from each slot. */
00464   if (!blend) {
00465     for (i = 0; i < nadapt; i++) {
00466       for (j = 0; j < nhist; j++)
00467         if (closest[j] == i && !min_dist[j])
00468           match = j;
00469       adapt[i] = hist[match];
00470       adapt[i].haspixel = 0;
00471     }
00472     
00473   } else {
00474     for (i = 0; i < nadapt; i++) {
00475       double red_total = 0, green_total = 0, blue_total = 0;
00476       u_int32_t pixel_total = 0, mismatch_pixel_total = 0;
00477       for (j = 0; j < nhist; j++)
00478         if (closest[j] == i) {
00479           u_int32_t pixel = hist[j].pixel;
00480           red_total += hist[j].red * pixel;
00481           green_total += hist[j].green * pixel;
00482           blue_total += hist[j].blue * pixel;
00483           pixel_total += pixel;
00484           if (min_dist[j])
00485             mismatch_pixel_total += pixel;
00486           else
00487             match = j;
00488         }
00489       /* Only blend if total number of mismatched pixels exceeds total number
00490          of matched pixels by a large margin. */
00491       if (3 * mismatch_pixel_total <= 2 * pixel_total)
00492         adapt[i] = hist[match];
00493       else {
00494         /* Favor, by a smallish amount, the color the plain diversity
00495            algorithm would pick. */
00496         u_int32_t pixel = hist[match].pixel * 2;
00497         red_total += hist[match].red * pixel;
00498         green_total += hist[match].green * pixel;
00499         blue_total += hist[match].blue * pixel;
00500         pixel_total += pixel;
00501         adapt[i].red = (byte)(red_total / pixel_total);
00502         adapt[i].green = (byte)(green_total / pixel_total);
00503         adapt[i].blue = (byte)(blue_total / pixel_total);
00504       }
00505       adapt[i].haspixel = 0;
00506     }
00507   }
00508   
00509   Gif_DeleteArray(min_dist);
00510   Gif_DeleteArray(closest);
00511   gfcm->ncol = nadapt;
00512   return gfcm;
00513 }

Gif_Colormap* colormap_flat_diversity Gif_Color   hist,
int    nhist,
int    adapt_size
 

Definition at line 523 of file quantize.c.

References colormap_diversity().

00524 {
00525   return colormap_diversity(hist, nhist, adapt_size, 0);
00526 }

void colormap_image_floyd_steinberg Gif_Image   gfi,
byte   all_new_data,
Gif_Colormap   old_cm,
Gif_Colormap   new_cm,
color_hash_item **    hash,
u_int32_t   histogram
 

Definition at line 712 of file quantize.c.

References Gif_Color::blue, Gif_Colormap::col, DITHER_SCALE, DITHER_SCALE_M1, Gif_DeleteArray, Gif_NewArray, Gif_Color::green, hash_color(), Gif_Image::height, i, Gif_Image::img, Gif_Image::left, max, min, N_RANDOM_VALUES, RANDOM, Gif_Color::red, Gif_Image::transparent, u_int32_t, and Gif_Image::width.

00715 {
00716   static int32_t *random_values = 0;
00717   
00718   int width = gfi->width;
00719   int dither_direction = 0;
00720   int transparent = gfi->transparent;
00721   int i, j;
00722   int32_t *r_err, *g_err, *b_err, *r_err1, *g_err1, *b_err1;
00723   Gif_Color *col = old_cm->col;
00724   Gif_Color *new_col = new_cm->col;
00725   
00726   /* This code was written with reference to ppmquant by Jef Poskanzer, part
00727      of the pbmplus package. */
00728   
00729   /* Initialize Floyd-Steinberg error vectors to small random values, so we
00730      don't get artifacts on the top row */
00731   r_err = Gif_NewArray(int32_t, width + 2);
00732   g_err = Gif_NewArray(int32_t, width + 2);
00733   b_err = Gif_NewArray(int32_t, width + 2);
00734   r_err1 = Gif_NewArray(int32_t, width + 2);
00735   g_err1 = Gif_NewArray(int32_t, width + 2);
00736   b_err1 = Gif_NewArray(int32_t, width + 2);
00737   /* Use the same random values on each call in an attempt to minimize
00738      "jumping dithering" effects on animations */
00739   if (!random_values) {
00740     random_values = Gif_NewArray(int32_t, N_RANDOM_VALUES);
00741     for (i = 0; i < N_RANDOM_VALUES; i++)
00742       random_values[i] = RANDOM() % (DITHER_SCALE_M1 * 2) - DITHER_SCALE_M1;
00743   }
00744   for (i = 0; i < gfi->width + 2; i++) {
00745     int j = (i + gfi->left) * 3;
00746     r_err[i] = random_values[ (j + 0) % N_RANDOM_VALUES ];
00747     g_err[i] = random_values[ (j + 1) % N_RANDOM_VALUES ];
00748     b_err[i] = random_values[ (j + 2) % N_RANDOM_VALUES ];
00749   }
00750   /* *_err1 initialized below */
00751   
00752   /* Do the image! */
00753   for (j = 0; j < gfi->height; j++) {
00754     int d0, d1, d2, d3;         /* used for error diffusion */
00755     byte *data, *new_data;
00756     int x;
00757     
00758     if (dither_direction) {
00759       x = width - 1;
00760       d0 = 0, d1 = 2, d2 = 1, d3 = 0;
00761     } else {
00762       x = 0;
00763       d0 = 2, d1 = 0, d2 = 1, d3 = 2;
00764     }
00765     data = &gfi->img[j][x];
00766     new_data = all_new_data + j * width + x;
00767     
00768     for (i = 0; i < width + 2; i++)
00769       r_err1[i] = g_err1[i] = b_err1[i] = 0;
00770     
00771     /* Do a single row */
00772     while (x >= 0 && x < width) {
00773       int e, use_r, use_g, use_b;
00774       
00775       /* the transparent color never gets adjusted */
00776       if (*data == transparent)
00777         goto next;
00778       
00779       /* use Floyd-Steinberg errors to adjust actual color */
00780       use_r = col[*data].red + r_err[x+1] / DITHER_SCALE;
00781       use_g = col[*data].green + g_err[x+1] / DITHER_SCALE;
00782       use_b = col[*data].blue + b_err[x+1] / DITHER_SCALE;
00783       use_r = max(use_r, 0);  use_r = min(use_r, 255);
00784       use_g = max(use_g, 0);  use_g = min(use_g, 255);
00785       use_b = max(use_b, 0);  use_b = min(use_b, 255);
00786       
00787       *new_data = hash_color(use_r, use_g, use_b, hash, new_cm);
00788       histogram[*new_data]++;
00789       
00790       /* calculate and propagate the error between desired and selected color.
00791          Assume that, with a large scale (1024), we don't need to worry about
00792          image artifacts caused by error accumulation (the fact that the
00793          error terms might not sum to the error). */
00794       e = (use_r - new_col[*new_data].red) * DITHER_SCALE;
00795       if (e) {
00796         r_err [x+d0] += (e * 7) / 16;
00797         r_err1[x+d1] += (e * 3) / 16;
00798         r_err1[x+d2] += (e * 5) / 16;
00799         r_err1[x+d3] += e / 16;
00800       }
00801       
00802       e = (use_g - new_col[*new_data].green) * DITHER_SCALE;
00803       if (e) {
00804         g_err [x+d0] += (e * 7) / 16;
00805         g_err1[x+d1] += (e * 3) / 16;
00806         g_err1[x+d2] += (e * 5) / 16;
00807         g_err1[x+d3] += e / 16;
00808       }
00809       
00810       e = (use_b - new_col[*new_data].blue) * DITHER_SCALE;
00811       if (e) {
00812         b_err [x+d0] += (e * 7) / 16;
00813         b_err1[x+d1] += (e * 3) / 16;
00814         b_err1[x+d2] += (e * 5) / 16;
00815         b_err1[x+d3] += e / 16;
00816       }
00817       
00818      next:
00819       if (dither_direction)
00820         x--, data--, new_data--;
00821       else
00822         x++, data++, new_data++;
00823     }
00824     /* Did a single row */
00825     
00826     /* change dithering directions */
00827     {
00828       int32_t *temp;
00829       temp = r_err; r_err = r_err1; r_err1 = temp;
00830       temp = g_err; g_err = g_err1; g_err1 = temp;
00831       temp = b_err; b_err = b_err1; b_err1 = temp;
00832       dither_direction = !dither_direction;
00833     }
00834   }
00835   
00836   /* delete temporary storage */
00837   Gif_DeleteArray(r_err);
00838   Gif_DeleteArray(g_err);
00839   Gif_DeleteArray(b_err);
00840   Gif_DeleteArray(r_err1);
00841   Gif_DeleteArray(g_err1);
00842   Gif_DeleteArray(b_err1);
00843 }

void colormap_image_posterize Gif_Image   gfi,
byte   new_data,
Gif_Colormap   old_cm,
Gif_Colormap   new_cm,
color_hash_item **    hash,
u_int32_t   histogram
 

Definition at line 675 of file quantize.c.

References Gif_Colormap::col, hash_color(), Gif_Image::height, i, Gif_Image::img, Gif_Colormap::ncol, ncol, Gif_Image::transparent, u_int32_t, and Gif_Image::width.

00678 {
00679   int ncol = old_cm->ncol;
00680   Gif_Color *col = old_cm->col;
00681   int map[256];
00682   int i, j;
00683   int transparent = gfi->transparent;
00684   
00685   /* find closest colors in new colormap */
00686   for (i = 0; i < ncol; i++)
00687     if (col[i].haspixel)
00688       map[i] = col[i].pixel;
00689     else {
00690       map[i] = col[i].pixel =
00691         hash_color(col[i].red, col[i].green, col[i].blue, hash, new_cm);
00692       col[i].haspixel = 1;
00693     }
00694   
00695   /* map image */
00696   for (j = 0; j < gfi->height; j++) {
00697     byte *data = gfi->img[j];
00698     for (i = 0; i < gfi->width; i++, data++, new_data++)
00699       if (*data != transparent) {
00700         *new_data = map[*data];
00701         histogram[*new_data]++;
00702       }
00703   }
00704 }

Gif_Colormap* colormap_median_cut Gif_Color   hist,
int    nhist,
int    adapt_size
 

Definition at line 236 of file quantize.c.

References assert_hist_transparency(), Gif_Color::blue, blue_sort_compare(), Gif_Colormap::col, adaptive_slot::count, fatal_error(), adaptive_slot::first, Gif_DeleteArray, Gif_NewArray, Gif_NewFullColormap(), Gif_Color::green, green_sort_compare(), Gif_Color::haspixel, i, max, min, Gif_Colormap::ncol, Gif_Color::pixel, adaptive_slot::pixel, pixel_sort_compare(), Gif_Color::red, red_sort_compare(), u_int32_t, and warning().

00237 {
00238   adaptive_slot *slots = Gif_NewArray(adaptive_slot, adapt_size);
00239   Gif_Colormap *gfcm = Gif_NewFullColormap(adapt_size, 256);
00240   Gif_Color *adapt = gfcm->col;
00241   int nadapt;
00242   int i, j;
00243   
00244   /* This code was written with reference to ppmquant by Jef Poskanzer, part
00245      of the pbmplus package. */
00246   
00247   if (adapt_size < 2 || adapt_size > 256)
00248     fatal_error("adaptive palette size must be between 2 and 256");
00249   if (adapt_size >= nhist) {
00250     warning("trivial adaptive palette (only %d colors in source)", nhist);
00251     adapt_size = nhist;
00252   }
00253   
00254   /* 0. remove any transparent color from consideration; reduce adaptive
00255      palette size to accommodate transparency if it looks like that'll be
00256      necessary */
00257   assert_hist_transparency(hist, nhist);
00258   if (adapt_size > 2 && adapt_size < nhist && hist[0].haspixel == 255
00259       && nhist <= 265)
00260     adapt_size--;
00261   if (hist[0].haspixel == 255) {
00262     hist[0] = hist[nhist - 1];
00263     nhist--;
00264   }
00265   
00266   /* 1. set up the first slot, containing all pixels. */
00267   {
00268     u_int32_t total = 0;
00269     for (i = 0; i < nhist; i++)
00270       total += hist[i].pixel;
00271     slots[0].first = 0;
00272     slots[0].count = nhist;
00273     slots[0].pixel = total;
00274     qsort(hist, nhist, sizeof(Gif_Color), pixel_sort_compare);
00275   }
00276   
00277   /* 2. split slots until we have enough. */
00278   for (nadapt = 1; nadapt < adapt_size; nadapt++) {
00279     adaptive_slot *split = 0;
00280     Gif_Color minc, maxc, *slice;
00281     
00282     /* 2.1. pick the slot to split. */
00283     {
00284       u_int32_t split_pixel = 0;
00285       for (i = 0; i < nadapt; i++)
00286         if (slots[i].count >= 2 && slots[i].pixel > split_pixel) {
00287           split = &slots[i];
00288           split_pixel = slots[i].pixel;
00289         }
00290       if (!split)
00291         break;
00292     }
00293     slice = &hist[split->first];
00294     
00295     /* 2.2. find its extent. */
00296     {
00297       Gif_Color *trav = slice;
00298       minc = maxc = *trav;
00299       for (i = 1, trav++; i < split->count; i++, trav++) {
00300         minc.red = min(minc.red, trav->red);
00301         maxc.red = max(maxc.red, trav->red);
00302         minc.green = min(minc.green, trav->green);
00303         maxc.green = max(maxc.green, trav->green);
00304         minc.blue = min(minc.blue, trav->blue);
00305         maxc.blue = max(maxc.blue, trav->blue);
00306       }
00307     }
00308     
00309     /* 2.3. decide how to split it. use the luminance method. also sort the
00310        colors. */
00311     {
00312       double red_diff = 0.299 * (maxc.red - minc.red);
00313       double green_diff = 0.587 * (maxc.green - minc.green);
00314       double blue_diff = 0.114 * (maxc.blue - minc.blue);
00315       if (red_diff >= green_diff && red_diff >= blue_diff)
00316         qsort(slice, split->count, sizeof(Gif_Color), red_sort_compare);
00317       else if (green_diff >= blue_diff)
00318         qsort(slice, split->count, sizeof(Gif_Color), green_sort_compare);
00319       else
00320         qsort(slice, split->count, sizeof(Gif_Color), blue_sort_compare);
00321     }
00322     
00323     /* 2.4. decide where to split the slot and split it there. */
00324     {
00325       u_int32_t half_pixels = split->pixel / 2;
00326       u_int32_t pixel_accum = slice[0].pixel;
00327       u_int32_t diff1, diff2;
00328       for (i = 1; i < split->count - 1 && pixel_accum < half_pixels; i++)
00329         pixel_accum += slice[i].pixel;
00330 
00331       /* We know the area before the split has more pixels than the area
00332          after, possibly by a large margin (bad news). If it would shrink the
00333          margin, change the split. */
00334       diff1 = 2*pixel_accum - split->pixel;
00335       diff2 = split->pixel - 2*(pixel_accum - slice[i-1].pixel);
00336       if (diff2 < diff1 && i > 1) {
00337         i--;
00338         pixel_accum -= slice[i].pixel;
00339       }
00340       
00341       slots[nadapt].first = split->first + i;
00342       slots[nadapt].count = split->count - i;
00343       slots[nadapt].pixel = split->pixel - pixel_accum;
00344       split->count = i;
00345       split->pixel = pixel_accum;
00346     }
00347   }
00348   
00349   /* 3. make the new palette by choosing one color from each slot. */
00350   for (i = 0; i < nadapt; i++) {
00351     double red_total = 0, green_total = 0, blue_total = 0;
00352     Gif_Color *slice = &hist[ slots[i].first ];
00353     for (j = 0; j < slots[i].count; j++) {
00354       red_total += slice[j].red * slice[j].pixel;
00355       green_total += slice[j].green * slice[j].pixel;
00356       blue_total += slice[j].blue * slice[j].pixel;
00357     }
00358     adapt[i].red = (byte)(red_total / slots[i].pixel);
00359     adapt[i].green = (byte)(green_total / slots[i].pixel);
00360     adapt[i].blue = (byte)(blue_total / slots[i].pixel);
00361     adapt[i].haspixel = 0;
00362   }
00363   
00364   Gif_DeleteArray(slots);
00365   gfcm->ncol = nadapt;
00366   return gfcm;
00367 }

void colormap_stream Gif_Stream   gfs,
Gif_Colormap   new_cm,
colormap_image_func    image_changer
 

Definition at line 911 of file quantize.c.

References Gif_Stream::background, Gif_Color::blue, c, Gif_Colormap::capacity, Gif_Colormap::col, colormap_image_func, free_all_color_hash_items(), Gif_CopyColormap(), Gif_DeleteArray, Gif_DeleteArrayFunc, Gif_DeleteColormap(), Gif_NewArray, Gif_ReleaseUncompressedImage(), Gif_SetUncompressedImage(), Gif_Stream::global, Gif_Color::green, hash_color(), Gif_Color::haspixel, Gif_Image::height, Gif_Image::image_data, Gif_Stream::images, Gif_Image::local, Gif_Colormap::ncol, new_color_hash(), Gif_Stream::nimages, Gif_Color::pixel, popularity_sort_compare(), Gif_Color::red, Gif_Image::transparent, try_assign_transparency(), u_int32_t, unmark_colors(), and Gif_Image::width.

Referenced by do_set_colormap().

00913 { 
00914   color_hash_item **hash = new_color_hash();
00915   int background_transparent = gfs->images[0]->transparent >= 0;
00916   Gif_Color *new_col = new_cm->col;
00917   int new_ncol = new_cm->ncol;
00918   int imagei, j;
00919   int compress_new_cm = 1;
00920 
00921   /* make sure colormap has enough space */
00922   if (new_cm->capacity < 256) {
00923     Gif_Color *x = Gif_NewArray(Gif_Color, 256);
00924     memcpy(x, new_col, sizeof(Gif_Color) * new_ncol);
00925     Gif_DeleteArray(new_col);
00926     new_cm->col = new_col = x;
00927     new_cm->capacity = 256;
00928   }
00929   assert(new_cm->capacity >= 256);
00930   
00931   /* new_col[j].pixel == number of pixels with color j in the new image. */
00932   for (j = 0; j < 256; j++)
00933     new_col[j].pixel = 0;
00934   
00935   for (imagei = 0; imagei < gfs->nimages; imagei++) {
00936     Gif_Image *gfi = gfs->images[imagei];
00937     Gif_Colormap *gfcm = gfi->local ? gfi->local : gfs->global;
00938 
00939     if (gfcm) {
00940       /* If there was an old colormap, change the image data */
00941       byte *new_data = Gif_NewArray(byte, gfi->width * gfi->height);
00942       u_int32_t histogram[256];
00943       unmark_colors(new_cm);
00944       unmark_colors(gfcm);
00945       
00946       do {
00947         for (j = 0; j < 256; j++) histogram[j] = 0;
00948         image_changer(gfi, new_data, gfcm, new_cm, hash, histogram);
00949       } while (try_assign_transparency(gfi, gfcm, new_data, new_cm, &new_ncol,
00950                                        histogram));
00951       
00952       Gif_ReleaseUncompressedImage(gfi);
00953       Gif_SetUncompressedImage(gfi, new_data, Gif_DeleteArrayFunc, 0);
00954       
00955       /* update count of used colors */
00956       for (j = 0; j < 256; j++)
00957         new_col[j].pixel += histogram[j];
00958       if (gfi->transparent >= 0)
00959         /* we don't have data on the number of used colors for transparency
00960            so fudge it. */
00961         new_col[gfi->transparent].pixel += gfi->width * gfi->height / 8;
00962       
00963     } else {
00964       /* Can't compress new_cm afterwards if we didn't actively change colors
00965          over */
00966       compress_new_cm = 0;
00967     }
00968     
00969     if (gfi->local) {
00970       Gif_DeleteColormap(gfi->local);
00971       gfi->local = 0;
00972     }
00973   }
00974 
00975   /* Set new_cm->ncol from new_ncol. We didn't update new_cm->ncol before so
00976      the closest-color algorithms wouldn't see any new transparent colors.
00977      That way added transparent colors were only used for transparency. */
00978   new_cm->ncol = new_ncol;
00979   
00980   /* change the background. I hate the background by now */
00981   if (background_transparent)
00982     gfs->background = gfs->images[0]->transparent;
00983   else if (gfs->global && gfs->background < gfs->global->ncol) {
00984     Gif_Color *c = &gfs->global->col[ gfs->background ];
00985     gfs->background = hash_color(c->red, c->green, c->blue, hash, new_cm);
00986     new_col[gfs->background].pixel++;
00987   }
00988   
00989   Gif_DeleteColormap(gfs->global);
00990   
00991   /* We may have used only a subset of the colors in new_cm. We try to store
00992      only that subset, just as if we'd piped the output of `gifsicle
00993      --use-colormap=X' through `gifsicle' another time. */
00994   gfs->global = Gif_CopyColormap(new_cm);
00995   if (compress_new_cm) {
00996     /* only bother to recompress if we'll get anything out of it */
00997     compress_new_cm = 0;
00998     for (j = 0; j < new_cm->ncol - 1; j++)
00999       if (new_col[j].pixel == 0 || new_col[j].pixel < new_col[j+1].pixel) {
01000         compress_new_cm = 1;
01001         break;
01002       }
01003   }
01004   
01005   if (compress_new_cm) {
01006     int map[256];
01007     
01008     /* Gif_CopyColormap copies the `pixel' values as well */
01009     new_col = gfs->global->col;
01010     for (j = 0; j < new_cm->ncol; j++)
01011       new_col[j].haspixel = j;
01012     
01013     /* sort based on popularity */
01014     qsort(new_col, new_cm->ncol, sizeof(Gif_Color), popularity_sort_compare);
01015     
01016     /* set up the map and reduce the number of colors */
01017     for (j = 0; j < new_cm->ncol; j++)
01018       map[ new_col[j].haspixel ] = j;
01019     for (j = 0; j < new_cm->ncol; j++)
01020       if (!new_col[j].pixel) {
01021         gfs->global->ncol = j;
01022         break;
01023       }
01024     
01025     /* map the image data, transparencies, and background */
01026     gfs->background = map[gfs->background];
01027     for (imagei = 0; imagei < gfs->nimages; imagei++) {
01028       Gif_Image *gfi = gfs->images[imagei];
01029       u_int32_t size;
01030       byte *data = gfi->image_data;
01031       for (size = gfi->width * gfi->height; size > 0; size--, data++)
01032         *data = map[*data];
01033       if (gfi->transparent >= 0)
01034         gfi->transparent = map[gfi->transparent];
01035     }
01036   }
01037   
01038   /* free storage */
01039   free_all_color_hash_items();
01040   Gif_DeleteArray(hash);
01041 }

void delete_histogram Gif_Histogram   hist [static]
 

Definition at line 41 of file quantize.c.

References Gif_Histogram::c, and Gif_DeleteArray.

Referenced by add_histogram_color(), and histogram().

00042 {
00043   Gif_DeleteArray(hist->c);
00044 }

void free_all_color_hash_items void    [static]
 

Definition at line 581 of file quantize.c.

References Gif_DeleteArray, HASH_ITEM_ALLOC_AMOUNT, and hash_item_alloc_left.

Referenced by colormap_stream().

00582 {
00583   while (hash_item_alloc_list) {
00584     color_hash_item *next =
00585       hash_item_alloc_list[HASH_ITEM_ALLOC_AMOUNT - 1].next;
00586     Gif_DeleteArray(hash_item_alloc_list);
00587     hash_item_alloc_list = next;
00588   }
00589   hash_item_alloc_left = 0;
00590 }

int green_sort_compare const void *    va,
const void *    vb
[static]
 

Definition at line 201 of file quantize.c.

References a, and Gif_Color::green.

Referenced by colormap_median_cut().

00202 {
00203   const Gif_Color *a = (const Gif_Color *)va;
00204   const Gif_Color *b = (const Gif_Color *)vb;
00205   return a->green - b->green;
00206 }

int hash_color int    red,
int    green,
int    blue,
color_hash_item **    hash,
Gif_Colormap   new_cm
[static]
 

Definition at line 594 of file quantize.c.

References abs, color_hash_item::blue, Gif_Colormap::col, COLOR_HASH_CODE, gray, color_hash_item::green, i, ncol, Gif_Colormap::ncol, new_color_hash_item(), color_hash_item::next, color_hash_item::pixel, color_hash_item::red, and u_int32_t.

Referenced by colormap_image_floyd_steinberg(), colormap_image_posterize(), and colormap_stream().

00596 {
00597   u_int32_t hash_code = COLOR_HASH_CODE(red, green, blue);
00598   color_hash_item *prev = 0, *trav;
00599   
00600   /* Is new_cm grayscale? We cache the answer here. */
00601   static Gif_Colormap *cached_new_cm;
00602   static int new_cm_grayscale;
00603   
00604   for (trav = hash[hash_code]; trav; prev = trav, trav = trav->next)
00605     if (trav->red == red && trav->green == green && trav->blue == blue)
00606       return trav->pixel;
00607   
00608   trav = new_color_hash_item(red, green, blue);
00609   if (prev)
00610     prev->next = trav;
00611   else
00612     hash[hash_code] = trav;
00613   
00614   /* calculate whether new_cm is grayscale */
00615   if (new_cm != cached_new_cm) {
00616     int i;
00617     Gif_Color *col = new_cm->col;
00618     cached_new_cm = new_cm;
00619     new_cm_grayscale = 1;
00620     for (i = 0; i < new_cm->ncol && new_cm_grayscale; i++)
00621       if (col[i].red != col[i].green || col[i].green != col[i].blue
00622           || col[i].blue != col[i].red)
00623         new_cm_grayscale = 0;
00624   }
00625   
00626   /* find the closest color in the new colormap */
00627   {
00628     Gif_Color *col = new_cm->col;
00629     int ncol = new_cm->ncol, i, found;
00630     u_int32_t min_dist = 0xFFFFFFFFU;
00631     
00632     if (new_cm_grayscale) {
00633       /* If the new colormap is 100% grayscale, then use distance in luminance
00634          space instead of distance in RGB space. The weights for the R,G,B
00635          components in luminance space are 0.299,0.587,0.114. We calculate a
00636          gray value for the input color first and compare that against the
00637          available grays in the colormap. Thanks to Christian Kumpf,
00638          <kumpf@igd.fhg.de>, for providing a patch.
00639          
00640          Note on the calculation of `gray': Using the factors 306, 601, and
00641          117 (proportional to 0.299,0.587,0.114) we get a scaled gray value
00642          between 0 and 255 * 1024. */
00643       int gray = 306 * red + 601 * green + 117 * blue;
00644       for (i = 0; i < ncol; i++)
00645         if (col[i].haspixel != 255) {
00646           int in_gray = 1024 * col[i].red;
00647           u_int32_t dist = abs(gray - in_gray);
00648           if (dist < min_dist) {
00649             min_dist = dist;
00650             found = i;
00651           }
00652         }
00653       
00654     } else {
00655       /* Use straight-line Euclidean distance in RGB space */
00656       for (i = 0; i < ncol; i++)
00657         if (col[i].haspixel != 255) {
00658           u_int32_t dist = (red - col[i].red) * (red - col[i].red)
00659             + (green - col[i].green) * (green - col[i].green)
00660             + (blue - col[i].blue) * (blue - col[i].blue);
00661           if (dist < min_dist) {
00662             min_dist = dist;
00663             found = i;
00664           }
00665         }
00666     }
00667     
00668     trav->pixel = found;
00669     return found;
00670   }
00671 }

Gif_Color* histogram Gif_Stream   gfs,
int *    nhist_store
 

Definition at line 100 of file quantize.c.

References add_histogram_color(), Gif_Stream::background, Gif_Histogram::c, Gif_Histogram::cap, Gif_Colormap::col, delete_histogram(), Gif_Image::disposal, GIF_DISPOSAL_BACKGROUND, Gif_NewArray, Gif_Stream::global, Gif_Color::haspixel, Gif_Image::height, i, Gif_Stream::images, Gif_Image::img, init_histogram(), Gif_Image::local, Gif_Histogram::n, Gif_Colormap::ncol, ncol, Gif_Stream::nimages, Gif_Color::pixel, Gif_Image::transparent, u_int32_t, unmark_colors(), and Gif_Image::width.

Referenced by do_colormap_change().

00101 {
00102   Gif_Histogram hist;
00103   Gif_Color *linear;
00104   Gif_Color transparent_color;
00105   unsigned long ntransparent = 0;
00106   unsigned long nbackground = 0;
00107   int x, y, i;
00108   
00109   unmark_colors(gfs->global);
00110   for (i = 0; i < gfs->nimages; i++)
00111     unmark_colors(gfs->images[i]->local);
00112 
00113   init_histogram(&hist, 0);
00114   
00115   /* Count pixels. Be careful about values which are outside the range of the
00116      colormap. */
00117   for (i = 0; i < gfs->nimages; i++) {
00118     Gif_Image *gfi = gfs->images[i];
00119     Gif_Colormap *gfcm = gfi->local ? gfi->local : gfs->global;
00120     u_int32_t count[256];
00121     Gif_Color *col;
00122     int ncol;
00123     int transparent = gfi->transparent;
00124     if (!gfcm) continue;
00125     
00126     /* sweep over the image data, counting pixels */
00127     for (x = 0; x < 256; x++)
00128       count[x] = 0;
00129     for (y = 0; y < gfi->height; y++) {
00130       byte *data = gfi->img[y];
00131       for (x = 0; x < gfi->width; x++, data++)
00132         count[*data]++;
00133     }
00134     
00135     /* add counted colors to global histogram */
00136     col = gfcm->col;
00137     ncol = gfcm->ncol;
00138     for (x = 0; x < ncol; x++)
00139       if (count[x] && x != transparent) {
00140         if (col[x].haspixel)
00141           hist.c[ col[x].pixel ].pixel += count[x];
00142         else
00143           add_histogram_color(&col[x], &hist, count[x]);
00144       }
00145     if (transparent >= 0) {
00146       if (ntransparent == 0) transparent_color = col[transparent];
00147       ntransparent += count[transparent];
00148     }
00149     
00150     /* if this image has background disposal, count its size towards the
00151        background's pixel count */
00152     if (gfi->disposal == GIF_DISPOSAL_BACKGROUND)
00153       nbackground += gfi->width * gfi->height;
00154   }
00155   
00156   /* account for background by adding it to `ntransparent' or the histogram */
00157   if (gfs->images[0]->transparent < 0 && gfs->global
00158       && gfs->background < gfs->global->ncol)
00159     add_histogram_color(&gfs->global->col[gfs->background], &hist, nbackground);
00160   else
00161     ntransparent += nbackground;
00162   
00163   /* now, make the linear histogram from the hashed histogram */
00164   linear = Gif_NewArray(Gif_Color, hist.n + 1);
00165   i = 0;
00166   
00167   /* Put all transparent pixels in histogram slot 0. Transparent pixels are
00168      marked by haspixel == 255. */
00169   if (ntransparent) {
00170     linear[0] = transparent_color;
00171     linear[0].haspixel = 255;
00172     linear[0].pixel = ntransparent;
00173     i++;
00174   }
00175   
00176   /* put hash histogram colors into linear histogram */
00177   for (x = 0; x < hist.cap; x++)
00178     if (hist.c[x].haspixel)
00179       linear[i++] = hist.c[x];
00180 
00181   delete_histogram(&hist);
00182   *nhist_store = i;
00183   return linear;
00184 }

void init_histogram Gif_Histogram   new_hist,
Gif_Histogram   old_hist
[static]
 

Definition at line 24 of file quantize.c.

References add_histogram_color(), Gif_Histogram::c, Gif_Histogram::cap, Gif_NewArray, i, Gif_Histogram::n, and nc.

Referenced by add_histogram_color(), and histogram().

00025 {
00026   int new_cap = (old_hist ? old_hist->cap * 2 : 1024);
00027   Gif_Color *nc = Gif_NewArray(Gif_Color, new_cap);
00028   int i;
00029   new_hist->c = nc;
00030   new_hist->n = 0;
00031   new_hist->cap = new_cap;
00032   for (i = 0; i < new_cap; i++)
00033     new_hist->c[i].haspixel = 0;
00034   if (old_hist)
00035     for (i = 0; i < old_hist->cap; i++)
00036       if (old_hist->c[i].haspixel)
00037         add_histogram_color(&old_hist->c[i], new_hist, old_hist->c[i].pixel);
00038 }

color_hash_item** new_color_hash void    [static]
 

Definition at line 549 of file quantize.c.

References COLOR_HASH_SIZE, Gif_NewArray, and i.

Referenced by colormap_stream().

00550 {
00551   int i;
00552   color_hash_item **hash = Gif_NewArray(color_hash_item *, COLOR_HASH_SIZE);
00553   for (i = 0; i < COLOR_HASH_SIZE; i++)
00554     hash[i] = 0;
00555   return hash;
00556 }

color_hash_item* new_color_hash_item byte    red,
byte    green,
byte    blue
[static]
 

Definition at line 560 of file quantize.c.

References color_hash_item::blue, Gif_NewArray, color_hash_item::green, HASH_ITEM_ALLOC_AMOUNT, hash_item_alloc_left, color_hash_item::next, and color_hash_item::red.

Referenced by hash_color().

00561 {
00562   color_hash_item *chi;
00563   if (hash_item_alloc_left <= 0) {
00564     color_hash_item *new_alloc =
00565       Gif_NewArray(color_hash_item, HASH_ITEM_ALLOC_AMOUNT);
00566     new_alloc[HASH_ITEM_ALLOC_AMOUNT-1].next = hash_item_alloc_list;
00567     hash_item_alloc_list = new_alloc;
00568     hash_item_alloc_left = HASH_ITEM_ALLOC_AMOUNT - 1;
00569   }
00570   
00571   --hash_item_alloc_left;
00572   chi = &hash_item_alloc_list[hash_item_alloc_left];
00573   chi->red = red;
00574   chi->green = green;
00575   chi->blue = blue;
00576   chi->next = 0;
00577   return chi;
00578 }

int pixel_sort_compare const void *    va,
const void *    vb
[static]
 

Definition at line 91 of file quantize.c.

References a, and Gif_Color::pixel.

Referenced by colormap_median_cut().

00092 {
00093   const Gif_Color *a = (const Gif_Color *)va;
00094   const Gif_Color *b = (const Gif_Color *)vb;
00095   return a->pixel - b->pixel;
00096 }

int popularity_sort_compare const void *    va,
const void *    vb
[static]
 

Definition at line 83 of file quantize.c.

References a, and Gif_Color::pixel.

Referenced by colormap_diversity(), and colormap_stream().

00084 {
00085   const Gif_Color *a = (const Gif_Color *)va;
00086   const Gif_Color *b = (const Gif_Color *)vb;
00087   return b->pixel - a->pixel;
00088 }

int red_sort_compare const void *    va,
const void *    vb
[static]
 

Definition at line 193 of file quantize.c.

References a, and Gif_Color::red.

Referenced by colormap_median_cut().

00194 {
00195   const Gif_Color *a = (const Gif_Color *)va;
00196   const Gif_Color *b = (const Gif_Color *)vb;
00197   return a->red - b->red;
00198 }

int try_assign_transparency Gif_Image   gfi,
Gif_Colormap   old_cm,
byte   new_data,
Gif_Colormap   new_cm,
int *    new_ncol,
u_int32_t   histogram
[static]
 

Definition at line 848 of file quantize.c.

References Gif_Colormap::col, GIF_COLOREQ, Gif_Color::haspixel, Gif_Image::height, i, Gif_Image::img, Gif_Image::transparent, u_int32_t, and Gif_Image::width.

Referenced by colormap_stream().

00851 {
00852   u_int32_t min_used;
00853   int i, j;
00854   int transparent = gfi->transparent;
00855   int new_transparent = -1;
00856   Gif_Color transp_value;
00857   
00858   if (transparent < 0)
00859     return 0;
00860 
00861   if (old_cm)
00862     transp_value = old_cm->col[transparent];
00863   
00864   /* look for an unused pixel in the existing colormap; prefer the same color
00865      we had */
00866   for (i = 0; i < *new_ncol; i++)
00867     if (histogram[i] == 0 && GIF_COLOREQ(&transp_value, &new_cm->col[i])) {
00868       new_transparent = i;
00869       goto found;
00870     }
00871   for (i = 0; i < *new_ncol; i++)
00872     if (histogram[i] == 0) {
00873       new_transparent = i;
00874       goto found;
00875     }
00876   
00877   /* try to expand the colormap */
00878   if (*new_ncol < 256) {
00879     assert(*new_ncol < new_cm->capacity);
00880     new_transparent = *new_ncol;
00881     new_cm->col[new_transparent] = transp_value;
00882     (*new_ncol)++;
00883     goto found;
00884   }
00885   
00886   /* not found: mark the least-frequently-used color as the new transparent
00887      color and return 1 (meaning `dither again') */
00888   assert(*new_ncol == 256);
00889   min_used = 0xFFFFFFFFU;
00890   for (i = 0; i < 256; i++)
00891     if (histogram[i] < min_used) {
00892       new_transparent = i;
00893       min_used = histogram[i];
00894     }
00895   new_cm->col[new_transparent].haspixel = 255; /* mark it unusable */
00896   return 1;
00897   
00898  found:
00899   for (j = 0; j < gfi->height; j++) {
00900     byte *data = gfi->img[j];
00901     for (i = 0; i < gfi->width; i++, data++, new_data++)
00902       if (*data == transparent)
00903         *new_data = new_transparent;
00904   }
00905   
00906   gfi->transparent = new_transparent;
00907   return 0;
00908 }

Variable Documentation

int hash_item_alloc_left [static]
 

Definition at line 545 of file quantize.c.

Referenced by free_all_color_hash_items(), and new_color_hash_item().

color_hash_item* hash_item_alloc_list [static]
 

Definition at line 544 of file quantize.c.

 

Powered by Plone

This site conforms to the following standards: