mirror of https://github.com/GNOME/gimp.git
Define accessor function/macro for histogram reads and writes. This slows
2001-03-25 18:16:50 Adam D. Moss <adam@gimp.org> * app/convert.c: Define accessor function/macro for histogram reads and writes. This slows us down a little because we avoid some of the dirty tricks we used when we knew that the histogram was a straight 3d array, so I've recovered some of the speed loss by implementing a 5d accessor function with good locality of reference. This change is the first step towards quantizing in a more interesting colourspace than frumpy old RGB.
This commit is contained in:
parent
6e2104c68e
commit
f05240ac1e
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
||||||
|
2001-03-25 18:16:50 Adam D. Moss <adam@gimp.org>
|
||||||
|
|
||||||
|
* app/convert.c: Define accessor function/macro for histogram
|
||||||
|
reads and writes. This slows us down a little because we avoid
|
||||||
|
some of the dirty tricks we used when we knew that the histogram
|
||||||
|
was a straight 3d array, so I've recovered some of the speed loss
|
||||||
|
by implementing a 5d accessor function with good locality of
|
||||||
|
reference. This change is the first step towards quantizing in a
|
||||||
|
more interesting colourspace than frumpy old RGB.
|
||||||
|
|
||||||
2001-03-24 Nathan Summers <rock@gimp.org>
|
2001-03-24 Nathan Summers <rock@gimp.org>
|
||||||
|
|
||||||
* app/tools/gimpscaletool.[ch]: Made the scale tool work again.
|
* app/tools/gimpscaletool.[ch]: Made the scale tool work again.
|
||||||
|
|
426
app/convert.c
426
app/convert.c
|
@ -19,12 +19,20 @@
|
||||||
/*
|
/*
|
||||||
* TODO for Convert:
|
* TODO for Convert:
|
||||||
*
|
*
|
||||||
* Use palette of another open INDEXED image
|
* . Quantize in (for example) CIE L*a*b*
|
||||||
*
|
* . Use palette of another open INDEXED image
|
||||||
* Do error-splitting trick for GREY->INDEXED
|
* . Do error-splitting trick for GREY->INDEXED
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* 2001-03-25 - Define accessor function/macro for histogram reads and
|
||||||
|
* writes. This slows us down a little because we avoid some of the
|
||||||
|
* dirty tricks we used when we knew that the histogram was a straight
|
||||||
|
* 3d array, so I've recovered some of the speed loss by implementing
|
||||||
|
* a 5d accessor function with good locality of reference. This change
|
||||||
|
* is the first step towards quantizing in a more interesting colourspace
|
||||||
|
* than frumpy old RGB. [Adam]
|
||||||
|
*
|
||||||
* 2000/01/30 - Use palette_selector instead of option_menu for custom
|
* 2000/01/30 - Use palette_selector instead of option_menu for custom
|
||||||
* palette. Use libgimp callback functions. [Sven]
|
* palette. Use libgimp callback functions. [Sven]
|
||||||
*
|
*
|
||||||
|
@ -125,28 +133,8 @@
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
|
||||||
#define PRECISION_R 6
|
|
||||||
#define PRECISION_G 6
|
|
||||||
#define PRECISION_B 6
|
|
||||||
|
|
||||||
#define HIST_R_ELEMS (1<<PRECISION_R)
|
|
||||||
#define HIST_G_ELEMS (1<<PRECISION_G)
|
|
||||||
#define HIST_B_ELEMS (1<<PRECISION_B)
|
|
||||||
|
|
||||||
#define MR HIST_G_ELEMS*HIST_B_ELEMS
|
|
||||||
#define MG HIST_B_ELEMS
|
|
||||||
|
|
||||||
#define BITS_IN_SAMPLE 8
|
|
||||||
|
|
||||||
#define R_SHIFT (BITS_IN_SAMPLE-PRECISION_R)
|
|
||||||
#define G_SHIFT (BITS_IN_SAMPLE-PRECISION_G)
|
|
||||||
#define B_SHIFT (BITS_IN_SAMPLE-PRECISION_B)
|
|
||||||
|
|
||||||
/* this has to match the INTENSITY definition in libgimp/gimpcolorspace.h */
|
|
||||||
#define R_SCALE 30 /* scale R distances by this much */
|
|
||||||
#define G_SCALE 59 /* scale G distances by this much */
|
|
||||||
#define B_SCALE 11 /* and B by this much */
|
|
||||||
|
|
||||||
|
/* bleh! */
|
||||||
static const unsigned char webpal[] =
|
static const unsigned char webpal[] =
|
||||||
{
|
{
|
||||||
255,255,255,255,255,204,255,255,153,255,255,102,255,255,51,255,255,0,255,
|
255,255,255,255,255,204,255,255,153,255,255,102,255,255,51,255,255,0,255,
|
||||||
|
@ -327,6 +315,30 @@ static const guchar DM[128][128] =
|
||||||
{ 51, 14, 61, 29, 59, 20, 55, 31, 0, 49, 11, 60, 3, 26, 22, 56, 0, 40, 12, 43, 41, 8, 36, 0, 17, 57, 24, 2, 46, 26, 61, 18, 0, 38, 12, 59, 6, 49, 3, 57, 19, 63, 5, 33, 18, 54, 28, 56, 0, 43, 26, 46, 63, 27, 56, 22, 27, 54, 38, 28, 63, 24, 10, 45, 0, 31, 42, 21, 12, 25, 44, 49, 59, 6, 26, 50, 3, 34, 27, 59, 0, 35, 62, 16, 4, 58, 47, 0, 43, 24, 37, 2, 54, 20, 46, 31, 0, 56, 34, 5, 55, 45, 60, 37, 0, 40, 10, 38, 63, 46, 15, 20, 0, 53, 21, 62, 30, 11, 24, 27, 40, 0, 57, 26, 3, 45, 27, 35 },
|
{ 51, 14, 61, 29, 59, 20, 55, 31, 0, 49, 11, 60, 3, 26, 22, 56, 0, 40, 12, 43, 41, 8, 36, 0, 17, 57, 24, 2, 46, 26, 61, 18, 0, 38, 12, 59, 6, 49, 3, 57, 19, 63, 5, 33, 18, 54, 28, 56, 0, 43, 26, 46, 63, 27, 56, 22, 27, 54, 38, 28, 63, 24, 10, 45, 0, 31, 42, 21, 12, 25, 44, 49, 59, 6, 26, 50, 3, 34, 27, 59, 0, 35, 62, 16, 4, 58, 47, 0, 43, 24, 37, 2, 54, 20, 46, 31, 0, 56, 34, 5, 55, 45, 60, 37, 0, 40, 10, 38, 63, 46, 15, 20, 0, 53, 21, 62, 30, 11, 24, 27, 40, 0, 57, 26, 3, 45, 27, 35 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define PRECISION_R 6
|
||||||
|
#define PRECISION_G 6
|
||||||
|
#define PRECISION_B 6
|
||||||
|
|
||||||
|
#define HIST_R_ELEMS (1<<PRECISION_R)
|
||||||
|
#define HIST_G_ELEMS (1<<PRECISION_G)
|
||||||
|
#define HIST_B_ELEMS (1<<PRECISION_B)
|
||||||
|
|
||||||
|
#define MR (HIST_G_ELEMS*HIST_B_ELEMS)
|
||||||
|
#define MG HIST_B_ELEMS
|
||||||
|
|
||||||
|
#define BITS_IN_SAMPLE 8
|
||||||
|
|
||||||
|
#define R_SHIFT (BITS_IN_SAMPLE-PRECISION_R)
|
||||||
|
#define G_SHIFT (BITS_IN_SAMPLE-PRECISION_G)
|
||||||
|
#define B_SHIFT (BITS_IN_SAMPLE-PRECISION_B)
|
||||||
|
|
||||||
|
/* this has to match the INTENSITY definition in libgimp/gimpcolorspace.h */
|
||||||
|
#define R_SCALE 30 /* scale R distances by this much */
|
||||||
|
#define G_SCALE 59 /* scale G distances by this much */
|
||||||
|
#define B_SCALE 11 /* and B by this much */
|
||||||
|
|
||||||
|
|
||||||
typedef struct _Color Color;
|
typedef struct _Color Color;
|
||||||
typedef struct _QuantizeObj QuantizeObj;
|
typedef struct _QuantizeObj QuantizeObj;
|
||||||
typedef void (* Pass1_Func) (QuantizeObj *);
|
typedef void (* Pass1_Func) (QuantizeObj *);
|
||||||
|
@ -336,6 +348,82 @@ typedef void (* Cleanup_Func) (QuantizeObj *);
|
||||||
typedef unsigned long ColorFreq;
|
typedef unsigned long ColorFreq;
|
||||||
typedef ColorFreq *CFHistogram;
|
typedef ColorFreq *CFHistogram;
|
||||||
|
|
||||||
|
|
||||||
|
/* We effectively pull our three-dimensional space into five dimensions
|
||||||
|
such that the most-entropic bits lay in the lowest bits of the resulting
|
||||||
|
array index. This gives significantly better locality of reference
|
||||||
|
and hence a small speedup despite the extra work involved in calculating
|
||||||
|
the index.
|
||||||
|
|
||||||
|
Why not six dimensions? The expansion of dimensionality is good for random
|
||||||
|
access such as histogram population and the query pattern typical of
|
||||||
|
dithering but we have some code which iterates in a scanning manner, for
|
||||||
|
which the expansion is suboptimal. The compromise is to leave the B
|
||||||
|
dimension unmolested in the lower-order bits of the index, since this is
|
||||||
|
the dimension most commonly iterated through in the inner loop of the
|
||||||
|
scans.
|
||||||
|
|
||||||
|
--adam
|
||||||
|
|
||||||
|
RhGhRlGlB
|
||||||
|
*/
|
||||||
|
#define VOL_GBITS (PRECISION_G)
|
||||||
|
#define VOL_BBITS (PRECISION_B)
|
||||||
|
#define VOL_RBITS (PRECISION_R)
|
||||||
|
#define VOL_GBITSh (VOL_GBITS - 3)
|
||||||
|
#define VOL_GBITSl (VOL_GBITS - VOL_GBITSh)
|
||||||
|
#define VOL_BBITSh (VOL_BBITS - 4)
|
||||||
|
#define VOL_BBITSl (VOL_BBITS - VOL_BBITSh)
|
||||||
|
#define VOL_RBITSh (VOL_RBITS - 3)
|
||||||
|
#define VOL_RBITSl (VOL_RBITS - VOL_RBITSh)
|
||||||
|
#define VOL_GMASKh (((1<<VOL_GBITSh)-1) << VOL_GBITSl)
|
||||||
|
#define VOL_GMASKl ((1<<VOL_GBITSl)-1)
|
||||||
|
#define VOL_BMASKh (((1<<VOL_BBITSh)-1) << VOL_BBITSl)
|
||||||
|
#define VOL_BMASKl ((1<<VOL_BBITSl)-1)
|
||||||
|
#define VOL_RMASKh (((1<<VOL_RBITSh)-1) << VOL_RBITSl)
|
||||||
|
#define VOL_RMASKl ((1<<VOL_RBITSl)-1)
|
||||||
|
/* The 5d compromise thing. */
|
||||||
|
#define REF_FUNC(r,g,b) \
|
||||||
|
( \
|
||||||
|
(((r) & VOL_RMASKh) << (VOL_BBITS + VOL_GBITS)) | \
|
||||||
|
(((r) & VOL_RMASKl) << (VOL_GBITSl + VOL_BBITS)) | \
|
||||||
|
(((g) & VOL_GMASKh) << (VOL_RBITSl + VOL_BBITS)) | \
|
||||||
|
(((g) & VOL_GMASKl) << (VOL_BBITS)) | \
|
||||||
|
(b) \
|
||||||
|
)
|
||||||
|
/* The full-on 6d thing. */
|
||||||
|
/*
|
||||||
|
#define REF_FUNC(r,g,b) \
|
||||||
|
( \
|
||||||
|
(((r) & VOL_RMASKh) << (VOL_BBITS + VOL_GBITS)) | \
|
||||||
|
(((r) & VOL_RMASKl) << (VOL_GBITSl + VOL_BBITSl)) | \
|
||||||
|
(((g) & VOL_GMASKh) << (VOL_RBITSl + VOL_BBITS)) | \
|
||||||
|
(((g) & VOL_GMASKl) << (VOL_BBITSl)) | \
|
||||||
|
(((b) & VOL_BMASKh) << (VOL_RBITSl + VOL_GBITSl)) | \
|
||||||
|
((b) & VOL_BMASKl) \
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
/* The boring old 3d thing. */
|
||||||
|
/*
|
||||||
|
#define REF_FUNC(r,g,b) (((r)<<(PRECISION_G+PRECISION_B)) | ((g)<<(PRECISION_B)) | (b))
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* You even get to choose whether you want the accessor function
|
||||||
|
implemented as a macro or an inline function. Don't say I never
|
||||||
|
give you anything. */
|
||||||
|
/*
|
||||||
|
#define HIST_RGB(hist_ptr,r,g,b) (&(hist_ptr)[REF_FUNC((r),(g),(b))])
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
ColorFreq * HIST_RGB(const ColorFreq *hist_ptr,
|
||||||
|
const int r, const int g, const int b)
|
||||||
|
{
|
||||||
|
return (&(hist_ptr)[
|
||||||
|
REF_FUNC(r,g,b)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct _Color
|
struct _Color
|
||||||
{
|
{
|
||||||
int red;
|
int red;
|
||||||
|
@ -1608,12 +1696,8 @@ zero_histogram_gray (CFHistogram histogram)
|
||||||
static void
|
static void
|
||||||
zero_histogram_rgb (CFHistogram histogram)
|
zero_histogram_rgb (CFHistogram histogram)
|
||||||
{
|
{
|
||||||
int r, g, b;
|
memset(histogram, 0,
|
||||||
|
HIST_R_ELEMS * HIST_G_ELEMS * HIST_B_ELEMS * sizeof(ColorFreq));
|
||||||
for (r = 0; r < HIST_R_ELEMS; r++)
|
|
||||||
for (g = 0; g < HIST_G_ELEMS; g++)
|
|
||||||
for (b = 0; b < HIST_B_ELEMS; b++)
|
|
||||||
histogram[r*MR + g*MG + b] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1701,9 +1785,10 @@ generate_histogram_rgb (CFHistogram histogram,
|
||||||
)
|
)
|
||||||
|| (!has_alpha))
|
|| (!has_alpha))
|
||||||
{
|
{
|
||||||
colfreq = & histogram[(data[RED_PIX] >> R_SHIFT) * MR +
|
colfreq = HIST_RGB(histogram,
|
||||||
(data[GREEN_PIX] >> G_SHIFT) * MG +
|
data[RED_PIX] >> R_SHIFT,
|
||||||
(data[BLUE_PIX] >> B_SHIFT)];
|
data[GREEN_PIX] >> G_SHIFT,
|
||||||
|
data[BLUE_PIX] >> B_SHIFT);
|
||||||
(*colfreq)++;
|
(*colfreq)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1729,9 +1814,10 @@ generate_histogram_rgb (CFHistogram histogram,
|
||||||
)
|
)
|
||||||
|| (!has_alpha))
|
|| (!has_alpha))
|
||||||
{
|
{
|
||||||
colfreq = & histogram[(data[RED_PIX] >> R_SHIFT) * MR +
|
colfreq = HIST_RGB(histogram,
|
||||||
(data[GREEN_PIX] >> G_SHIFT) * MG +
|
data[RED_PIX] >> R_SHIFT,
|
||||||
(data[BLUE_PIX] >> B_SHIFT)];
|
data[GREEN_PIX] >> G_SHIFT,
|
||||||
|
data[BLUE_PIX] >> B_SHIFT);
|
||||||
(*colfreq)++;
|
(*colfreq)++;
|
||||||
}
|
}
|
||||||
data += srcPR.bytes;
|
data += srcPR.bytes;
|
||||||
|
@ -1751,9 +1837,10 @@ generate_histogram_rgb (CFHistogram histogram,
|
||||||
((data[ALPHA_PIX] << 6) > (255 * DM[col&DM_WIDTHMASK][row&DM_HEIGHTMASK])) :
|
((data[ALPHA_PIX] << 6) > (255 * DM[col&DM_WIDTHMASK][row&DM_HEIGHTMASK])) :
|
||||||
(data[ALPHA_PIX] > 127))) || (!has_alpha))
|
(data[ALPHA_PIX] > 127))) || (!has_alpha))
|
||||||
{
|
{
|
||||||
colfreq = & histogram[(data[RED_PIX] >> R_SHIFT) * MR +
|
colfreq = HIST_RGB(histogram,
|
||||||
(data[GREEN_PIX] >> G_SHIFT) * MG +
|
data[RED_PIX] >> R_SHIFT,
|
||||||
(data[BLUE_PIX] >> B_SHIFT)];
|
data[GREEN_PIX] >> G_SHIFT,
|
||||||
|
data[BLUE_PIX] >> B_SHIFT);
|
||||||
(*colfreq)++;
|
(*colfreq)++;
|
||||||
|
|
||||||
if (!needs_quantize)
|
if (!needs_quantize)
|
||||||
|
@ -1894,7 +1981,7 @@ update_box_gray (CFHistogram histogram,
|
||||||
/* and recompute its volume and population */
|
/* and recompute its volume and population */
|
||||||
{
|
{
|
||||||
int i, min, max, dist;
|
int i, min, max, dist;
|
||||||
long ccount;
|
ColorFreq ccount;
|
||||||
|
|
||||||
min = boxp->Rmin;
|
min = boxp->Rmin;
|
||||||
max = boxp->Rmax;
|
max = boxp->Rmax;
|
||||||
|
@ -1945,11 +2032,10 @@ update_box_rgb (CFHistogram histogram,
|
||||||
/* Shrink the min/max bounds of a box to enclose only nonzero elements, */
|
/* Shrink the min/max bounds of a box to enclose only nonzero elements, */
|
||||||
/* and recompute its volume, population and error */
|
/* and recompute its volume, population and error */
|
||||||
{
|
{
|
||||||
ColorFreq * histp;
|
|
||||||
int R,G,B;
|
int R,G,B;
|
||||||
int Rmin,Rmax,Gmin,Gmax,Bmin,Bmax;
|
int Rmin,Rmax,Gmin,Gmax,Bmin,Bmax;
|
||||||
int dist0,dist1,dist2;
|
int dist0,dist1,dist2;
|
||||||
long ccount;
|
ColorFreq ccount;
|
||||||
guint64 tempRerror;
|
guint64 tempRerror;
|
||||||
guint64 tempGerror;
|
guint64 tempGerror;
|
||||||
guint64 tempBerror;
|
guint64 tempBerror;
|
||||||
|
@ -1964,78 +2050,84 @@ update_box_rgb (CFHistogram histogram,
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
if (*histp++ != 0)
|
{
|
||||||
{
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
boxp->Rmin = Rmin = R;
|
{
|
||||||
goto have_Rmin;
|
boxp->Rmin = Rmin = R;
|
||||||
}
|
goto have_Rmin;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Rmin:
|
have_Rmin:
|
||||||
if (Rmax > Rmin)
|
if (Rmax > Rmin)
|
||||||
for (R = Rmax; R >= Rmin; R--)
|
for (R = Rmax; R >= Rmin; R--)
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
if (*histp++ != 0)
|
{
|
||||||
{
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
boxp->Rmax = Rmax = R;
|
{
|
||||||
goto have_Rmax;
|
boxp->Rmax = Rmax = R;
|
||||||
}
|
goto have_Rmax;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Rmax:
|
have_Rmax:
|
||||||
if (Gmax > Gmin)
|
if (Gmax > Gmin)
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
if (*histp++ != 0)
|
{
|
||||||
{
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
boxp->Gmin = Gmin = G;
|
{
|
||||||
goto have_Gmin;
|
boxp->Gmin = Gmin = G;
|
||||||
}
|
goto have_Gmin;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Gmin:
|
have_Gmin:
|
||||||
if (Gmax > Gmin)
|
if (Gmax > Gmin)
|
||||||
for (G = Gmax; G >= Gmin; G--)
|
for (G = Gmax; G >= Gmin; G--)
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
if (*histp++ != 0)
|
{
|
||||||
{
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
boxp->Gmax = Gmax = G;
|
{
|
||||||
goto have_Gmax;
|
boxp->Gmax = Gmax = G;
|
||||||
}
|
goto have_Gmax;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Gmax:
|
have_Gmax:
|
||||||
if (Bmax > Bmin)
|
if (Bmax > Bmin)
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + Gmin*MG + B;
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
for (G = Gmin; G <= Gmax; G++, histp += MG)
|
{
|
||||||
if (*histp != 0)
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
{
|
{
|
||||||
boxp->Bmin = Bmin = B;
|
boxp->Bmin = Bmin = B;
|
||||||
goto have_Bmin;
|
goto have_Bmin;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Bmin:
|
have_Bmin:
|
||||||
if (Bmax > Bmin)
|
if (Bmax > Bmin)
|
||||||
for (B = Bmax; B >= Bmin; B--)
|
for (B = Bmax; B >= Bmin; B--)
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + Gmin*MG + B;
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
for (G = Gmin; G <= Gmax; G++, histp += MG)
|
{
|
||||||
if (*histp != 0)
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
{
|
{
|
||||||
boxp->Bmax = Bmax = B;
|
boxp->Bmax = Bmax = B;
|
||||||
goto have_Bmax;
|
goto have_Bmax;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Bmax:
|
have_Bmax:
|
||||||
|
|
||||||
|
@ -2066,32 +2158,35 @@ update_box_rgb (CFHistogram histogram,
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
for (B = Bmin; B <= Bmax; B++, histp++)
|
{
|
||||||
if (*histp != 0)
|
ColorFreq freq_here;
|
||||||
{
|
freq_here = *HIST_RGB(histogram, R, G, B);
|
||||||
int ge, be, re;
|
if (freq_here != 0)
|
||||||
|
{
|
||||||
dummybox.Rmin = dummybox.Rmax = R;
|
int ge, be, re;
|
||||||
dummybox.Gmin = dummybox.Gmax = G;
|
|
||||||
dummybox.Bmin = dummybox.Bmax = B;
|
dummybox.Rmin = dummybox.Rmax = R;
|
||||||
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
dummybox.Gmin = dummybox.Gmax = G;
|
||||||
|
dummybox.Bmin = dummybox.Bmax = B;
|
||||||
re = dummyqo.cmap[0].red - dummyqo.cmap[1].red;
|
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
||||||
ge = dummyqo.cmap[0].green - dummyqo.cmap[1].green;
|
|
||||||
be = dummyqo.cmap[0].blue - dummyqo.cmap[1].blue;
|
re = dummyqo.cmap[0].red - dummyqo.cmap[1].red;
|
||||||
|
ge = dummyqo.cmap[0].green - dummyqo.cmap[1].green;
|
||||||
boxp->rerror += (*histp) * re*re;
|
be = dummyqo.cmap[0].blue - dummyqo.cmap[1].blue;
|
||||||
boxp->gerror += (*histp) * ge*ge;
|
|
||||||
boxp->berror += (*histp) * be*be;
|
boxp->rerror += freq_here * re*re;
|
||||||
|
boxp->gerror += freq_here * ge*ge;
|
||||||
boxp->error += (*histp) *
|
boxp->berror += freq_here * be*be;
|
||||||
(
|
|
||||||
re*re*R_SCALE + ge*ge*G_SCALE + be*be*B_SCALE
|
boxp->error += freq_here *
|
||||||
);
|
(
|
||||||
|
re*re*R_SCALE + ge*ge*G_SCALE + be*be*B_SCALE
|
||||||
ccount += *histp;
|
);
|
||||||
}
|
|
||||||
|
ccount += freq_here;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scan again, taking note of halfway error point for red axis */
|
/* Scan again, taking note of halfway error point for red axis */
|
||||||
|
@ -2103,23 +2198,26 @@ update_box_rgb (CFHistogram histogram,
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
dummybox.Gmin = dummybox.Gmax = G;
|
dummybox.Gmin = dummybox.Gmax = G;
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
for (B = Bmin; B <= Bmax; B++, histp++)
|
{
|
||||||
if (*histp != 0)
|
ColorFreq freq_here;
|
||||||
{
|
freq_here = *HIST_RGB(histogram, R, G, B);
|
||||||
int re;
|
if (freq_here != 0)
|
||||||
dummybox.Bmin = dummybox.Bmax = B;
|
{
|
||||||
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
int re;
|
||||||
|
dummybox.Bmin = dummybox.Bmax = B;
|
||||||
re = dummyqo.cmap[0].red - dummyqo.cmap[1].red;
|
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
||||||
|
|
||||||
tempRerror += (*histp)*re*re;
|
re = dummyqo.cmap[0].red - dummyqo.cmap[1].red;
|
||||||
|
|
||||||
if (tempRerror*2 > boxp->rerror)
|
tempRerror += freq_here * re*re;
|
||||||
goto green_axisscan;
|
|
||||||
else
|
if (tempRerror*2 > boxp->rerror)
|
||||||
boxp->Rhalferror = R;
|
goto green_axisscan;
|
||||||
}
|
else
|
||||||
|
boxp->Rhalferror = R;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2133,23 +2231,26 @@ update_box_rgb (CFHistogram histogram,
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
{
|
{
|
||||||
dummybox.Rmin = dummybox.Rmax = R;
|
dummybox.Rmin = dummybox.Rmax = R;
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
for (B = Bmin; B <= Bmax; B++, histp++)
|
{
|
||||||
if (*histp != 0)
|
ColorFreq freq_here;
|
||||||
{
|
freq_here = *HIST_RGB(histogram, R, G, B);
|
||||||
int ge;
|
if (freq_here != 0)
|
||||||
dummybox.Bmin = dummybox.Bmax = B;
|
{
|
||||||
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
int ge;
|
||||||
|
dummybox.Bmin = dummybox.Bmax = B;
|
||||||
ge = dummyqo.cmap[0].green - dummyqo.cmap[1].green;
|
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
||||||
|
|
||||||
tempGerror += (*histp)*ge*ge;
|
ge = dummyqo.cmap[0].green - dummyqo.cmap[1].green;
|
||||||
|
|
||||||
if (tempGerror*2 > boxp->gerror)
|
tempGerror += freq_here * ge*ge;
|
||||||
goto blue_axisscan;
|
|
||||||
else
|
if (tempGerror*2 > boxp->gerror)
|
||||||
boxp->Ghalferror = G;
|
goto blue_axisscan;
|
||||||
}
|
else
|
||||||
|
boxp->Ghalferror = G;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2165,8 +2266,9 @@ update_box_rgb (CFHistogram histogram,
|
||||||
dummybox.Rmin = dummybox.Rmax = R;
|
dummybox.Rmin = dummybox.Rmax = R;
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + B;
|
ColorFreq freq_here;
|
||||||
if (*histp != 0)
|
freq_here = *HIST_RGB(histogram, R, G, B);
|
||||||
|
if (freq_here != 0)
|
||||||
{
|
{
|
||||||
int be;
|
int be;
|
||||||
dummybox.Gmin = dummybox.Gmax = G;
|
dummybox.Gmin = dummybox.Gmax = G;
|
||||||
|
@ -2174,7 +2276,7 @@ update_box_rgb (CFHistogram histogram,
|
||||||
|
|
||||||
be = dummyqo.cmap[0].blue - dummyqo.cmap[1].blue;
|
be = dummyqo.cmap[0].blue - dummyqo.cmap[1].blue;
|
||||||
|
|
||||||
tempBerror += (*histp)*be*be;
|
tempBerror += freq_here * be*be;
|
||||||
|
|
||||||
if (tempBerror*2 > boxp->berror)
|
if (tempBerror*2 > boxp->berror)
|
||||||
goto finished_axesscan;
|
goto finished_axesscan;
|
||||||
|
@ -2402,16 +2504,14 @@ compute_color_rgb (QuantizeObj *quantobj,
|
||||||
{
|
{
|
||||||
/* Current algorithm: mean weighted by pixels (not colors) */
|
/* Current algorithm: mean weighted by pixels (not colors) */
|
||||||
/* Note it is important to get the rounding correct! */
|
/* Note it is important to get the rounding correct! */
|
||||||
ColorFreq * histp;
|
|
||||||
int R, G, B;
|
int R, G, B;
|
||||||
int Rmin, Rmax;
|
int Rmin, Rmax;
|
||||||
int Gmin, Gmax;
|
int Gmin, Gmax;
|
||||||
int Bmin, Bmax;
|
int Bmin, Bmax;
|
||||||
long count;
|
ColorFreq total = 0;
|
||||||
long total = 0;
|
ColorFreq Rtotal = 0;
|
||||||
long Rtotal = 0;
|
ColorFreq Gtotal = 0;
|
||||||
long Gtotal = 0;
|
ColorFreq Btotal = 0;
|
||||||
long Btotal = 0;
|
|
||||||
|
|
||||||
Rmin = boxp->Rmin; Rmax = boxp->Rmax;
|
Rmin = boxp->Rmin; Rmax = boxp->Rmax;
|
||||||
Gmin = boxp->Gmin; Gmax = boxp->Gmax;
|
Gmin = boxp->Gmin; Gmax = boxp->Gmax;
|
||||||
|
@ -2420,24 +2520,24 @@ compute_color_rgb (QuantizeObj *quantobj,
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
{
|
{
|
||||||
if ((count = *histp++) != 0)
|
ColorFreq this_freq = *HIST_RGB(histogram, R, G, B);
|
||||||
|
if (this_freq != 0)
|
||||||
{
|
{
|
||||||
total += count;
|
total += this_freq;
|
||||||
Rtotal += ((R << R_SHIFT) + ((1<<R_SHIFT)>>1)) * count;
|
Rtotal += ((R << R_SHIFT) + ((1<<R_SHIFT)>>1)) * this_freq;
|
||||||
Gtotal += ((G << G_SHIFT) + ((1<<G_SHIFT)>>1)) * count;
|
Gtotal += ((G << G_SHIFT) + ((1<<G_SHIFT)>>1)) * this_freq;
|
||||||
Btotal += ((B << B_SHIFT) + ((1<<B_SHIFT)>>1)) * count;
|
Btotal += ((B << B_SHIFT) + ((1<<B_SHIFT)>>1)) * this_freq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (total != 0)
|
if (total != 0)
|
||||||
{
|
{
|
||||||
quantobj->cmap[icolor].red = (Rtotal + (total>>1)) / total;
|
quantobj->cmap[icolor].red = (Rtotal + (total>>1)) / total;
|
||||||
quantobj->cmap[icolor].green = (Gtotal + (total>>1)) / total;
|
quantobj->cmap[icolor].green = (Gtotal + (total>>1)) / total;
|
||||||
quantobj->cmap[icolor].blue = (Btotal + (total>>1)) / total;
|
quantobj->cmap[icolor].blue = (Btotal + (total>>1)) / total;
|
||||||
}
|
}
|
||||||
else /* The only situation where total==0 is if the image was null or
|
else /* The only situation where total==0 is if the image was null or
|
||||||
* all-transparent. In that case we just put a dummy value in
|
* all-transparent. In that case we just put a dummy value in
|
||||||
|
@ -2856,7 +2956,6 @@ fill_inverse_cmap_rgb (QuantizeObj *quantobj,
|
||||||
int minR, minG, minB; /* lower left corner of update box */
|
int minR, minG, minB; /* lower left corner of update box */
|
||||||
int iR, iG, iB;
|
int iR, iG, iB;
|
||||||
int * cptr; /* pointer into bestcolor[] array */
|
int * cptr; /* pointer into bestcolor[] array */
|
||||||
ColorFreq * cachep; /* pointer into main cache array */
|
|
||||||
/* This array lists the candidate colormap indexes. */
|
/* This array lists the candidate colormap indexes. */
|
||||||
int colorlist[MAXNUMCOLORS];
|
int colorlist[MAXNUMCOLORS];
|
||||||
int numcolors; /* number of candidate colors */
|
int numcolors; /* number of candidate colors */
|
||||||
|
@ -2892,9 +2991,8 @@ fill_inverse_cmap_rgb (QuantizeObj *quantobj,
|
||||||
cptr = bestcolor;
|
cptr = bestcolor;
|
||||||
for (iR = 0; iR < BOX_R_ELEMS; iR++) {
|
for (iR = 0; iR < BOX_R_ELEMS; iR++) {
|
||||||
for (iG = 0; iG < BOX_G_ELEMS; iG++) {
|
for (iG = 0; iG < BOX_G_ELEMS; iG++) {
|
||||||
cachep = & histogram[(R+iR)*MR+(G+iG)*MG+B];
|
|
||||||
for (iB = 0; iB < BOX_B_ELEMS; iB++) {
|
for (iB = 0; iB < BOX_B_ELEMS; iB++) {
|
||||||
*cachep++ = (*cptr++) + 1;
|
*HIST_RGB(histogram, R+iR, G+iG, B+iB) = (*cptr++) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3165,7 +3263,7 @@ median_cut_pass2_no_dither_rgb (QuantizeObj *quantobj,
|
||||||
R = (src[red_pix]) >> R_SHIFT;
|
R = (src[red_pix]) >> R_SHIFT;
|
||||||
G = (src[green_pix]) >> G_SHIFT;
|
G = (src[green_pix]) >> G_SHIFT;
|
||||||
B = (src[blue_pix]) >> B_SHIFT;
|
B = (src[blue_pix]) >> B_SHIFT;
|
||||||
cachep = &histogram[R*MR + G*MG + B];
|
cachep = HIST_RGB(histogram,R,G,B);
|
||||||
/* If we have not seen this color before, find nearest
|
/* If we have not seen this color before, find nearest
|
||||||
colormap entry and update the cache */
|
colormap entry and update the cache */
|
||||||
if (*cachep == 0)
|
if (*cachep == 0)
|
||||||
|
@ -3246,7 +3344,7 @@ median_cut_pass2_fixed_dither_rgb (QuantizeObj *quantobj,
|
||||||
R = (src[red_pix]) >> R_SHIFT;
|
R = (src[red_pix]) >> R_SHIFT;
|
||||||
G = (src[green_pix]) >> G_SHIFT;
|
G = (src[green_pix]) >> G_SHIFT;
|
||||||
B = (src[blue_pix]) >> B_SHIFT;
|
B = (src[blue_pix]) >> B_SHIFT;
|
||||||
cachep = &histogram[R*MR + G*MG + B];
|
cachep = HIST_RGB(histogram,R,G,B);
|
||||||
/* If we have not seen this color before, find nearest
|
/* If we have not seen this color before, find nearest
|
||||||
colormap entry and update the cache */
|
colormap entry and update the cache */
|
||||||
if (*cachep == 0)
|
if (*cachep == 0)
|
||||||
|
@ -3271,7 +3369,7 @@ median_cut_pass2_fixed_dither_rgb (QuantizeObj *quantobj,
|
||||||
G = (CLAMP0255(color->green + ge)) >> G_SHIFT;
|
G = (CLAMP0255(color->green + ge)) >> G_SHIFT;
|
||||||
B = (CLAMP0255(color->blue + be)) >> B_SHIFT;
|
B = (CLAMP0255(color->blue + be)) >> B_SHIFT;
|
||||||
|
|
||||||
cachep = &histogram[R*MR + G*MG + B];
|
cachep = HIST_RGB(histogram,R,G,B);
|
||||||
/* If we have not seen this color before, find nearest
|
/* If we have not seen this color before, find nearest
|
||||||
colormap entry and update the cache */
|
colormap entry and update the cache */
|
||||||
if (*cachep == 0)
|
if (*cachep == 0)
|
||||||
|
@ -3824,7 +3922,7 @@ median_cut_pass2_fs_dither_rgb (QuantizeObj *quantobj,
|
||||||
ge = g >> G_SHIFT;
|
ge = g >> G_SHIFT;
|
||||||
be = b >> B_SHIFT;
|
be = b >> B_SHIFT;
|
||||||
|
|
||||||
cachep = &histogram[re*MR + ge*MG + be];
|
cachep = HIST_RGB(histogram, re, ge, be);
|
||||||
/* If we have not seen this color before, find nearest
|
/* If we have not seen this color before, find nearest
|
||||||
colormap entry and update the cache */
|
colormap entry and update the cache */
|
||||||
if (*cachep == 0)
|
if (*cachep == 0)
|
||||||
|
|
|
@ -19,12 +19,20 @@
|
||||||
/*
|
/*
|
||||||
* TODO for Convert:
|
* TODO for Convert:
|
||||||
*
|
*
|
||||||
* Use palette of another open INDEXED image
|
* . Quantize in (for example) CIE L*a*b*
|
||||||
*
|
* . Use palette of another open INDEXED image
|
||||||
* Do error-splitting trick for GREY->INDEXED
|
* . Do error-splitting trick for GREY->INDEXED
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* 2001-03-25 - Define accessor function/macro for histogram reads and
|
||||||
|
* writes. This slows us down a little because we avoid some of the
|
||||||
|
* dirty tricks we used when we knew that the histogram was a straight
|
||||||
|
* 3d array, so I've recovered some of the speed loss by implementing
|
||||||
|
* a 5d accessor function with good locality of reference. This change
|
||||||
|
* is the first step towards quantizing in a more interesting colourspace
|
||||||
|
* than frumpy old RGB. [Adam]
|
||||||
|
*
|
||||||
* 2000/01/30 - Use palette_selector instead of option_menu for custom
|
* 2000/01/30 - Use palette_selector instead of option_menu for custom
|
||||||
* palette. Use libgimp callback functions. [Sven]
|
* palette. Use libgimp callback functions. [Sven]
|
||||||
*
|
*
|
||||||
|
@ -125,28 +133,8 @@
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
|
||||||
#define PRECISION_R 6
|
|
||||||
#define PRECISION_G 6
|
|
||||||
#define PRECISION_B 6
|
|
||||||
|
|
||||||
#define HIST_R_ELEMS (1<<PRECISION_R)
|
|
||||||
#define HIST_G_ELEMS (1<<PRECISION_G)
|
|
||||||
#define HIST_B_ELEMS (1<<PRECISION_B)
|
|
||||||
|
|
||||||
#define MR HIST_G_ELEMS*HIST_B_ELEMS
|
|
||||||
#define MG HIST_B_ELEMS
|
|
||||||
|
|
||||||
#define BITS_IN_SAMPLE 8
|
|
||||||
|
|
||||||
#define R_SHIFT (BITS_IN_SAMPLE-PRECISION_R)
|
|
||||||
#define G_SHIFT (BITS_IN_SAMPLE-PRECISION_G)
|
|
||||||
#define B_SHIFT (BITS_IN_SAMPLE-PRECISION_B)
|
|
||||||
|
|
||||||
/* this has to match the INTENSITY definition in libgimp/gimpcolorspace.h */
|
|
||||||
#define R_SCALE 30 /* scale R distances by this much */
|
|
||||||
#define G_SCALE 59 /* scale G distances by this much */
|
|
||||||
#define B_SCALE 11 /* and B by this much */
|
|
||||||
|
|
||||||
|
/* bleh! */
|
||||||
static const unsigned char webpal[] =
|
static const unsigned char webpal[] =
|
||||||
{
|
{
|
||||||
255,255,255,255,255,204,255,255,153,255,255,102,255,255,51,255,255,0,255,
|
255,255,255,255,255,204,255,255,153,255,255,102,255,255,51,255,255,0,255,
|
||||||
|
@ -327,6 +315,30 @@ static const guchar DM[128][128] =
|
||||||
{ 51, 14, 61, 29, 59, 20, 55, 31, 0, 49, 11, 60, 3, 26, 22, 56, 0, 40, 12, 43, 41, 8, 36, 0, 17, 57, 24, 2, 46, 26, 61, 18, 0, 38, 12, 59, 6, 49, 3, 57, 19, 63, 5, 33, 18, 54, 28, 56, 0, 43, 26, 46, 63, 27, 56, 22, 27, 54, 38, 28, 63, 24, 10, 45, 0, 31, 42, 21, 12, 25, 44, 49, 59, 6, 26, 50, 3, 34, 27, 59, 0, 35, 62, 16, 4, 58, 47, 0, 43, 24, 37, 2, 54, 20, 46, 31, 0, 56, 34, 5, 55, 45, 60, 37, 0, 40, 10, 38, 63, 46, 15, 20, 0, 53, 21, 62, 30, 11, 24, 27, 40, 0, 57, 26, 3, 45, 27, 35 },
|
{ 51, 14, 61, 29, 59, 20, 55, 31, 0, 49, 11, 60, 3, 26, 22, 56, 0, 40, 12, 43, 41, 8, 36, 0, 17, 57, 24, 2, 46, 26, 61, 18, 0, 38, 12, 59, 6, 49, 3, 57, 19, 63, 5, 33, 18, 54, 28, 56, 0, 43, 26, 46, 63, 27, 56, 22, 27, 54, 38, 28, 63, 24, 10, 45, 0, 31, 42, 21, 12, 25, 44, 49, 59, 6, 26, 50, 3, 34, 27, 59, 0, 35, 62, 16, 4, 58, 47, 0, 43, 24, 37, 2, 54, 20, 46, 31, 0, 56, 34, 5, 55, 45, 60, 37, 0, 40, 10, 38, 63, 46, 15, 20, 0, 53, 21, 62, 30, 11, 24, 27, 40, 0, 57, 26, 3, 45, 27, 35 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define PRECISION_R 6
|
||||||
|
#define PRECISION_G 6
|
||||||
|
#define PRECISION_B 6
|
||||||
|
|
||||||
|
#define HIST_R_ELEMS (1<<PRECISION_R)
|
||||||
|
#define HIST_G_ELEMS (1<<PRECISION_G)
|
||||||
|
#define HIST_B_ELEMS (1<<PRECISION_B)
|
||||||
|
|
||||||
|
#define MR (HIST_G_ELEMS*HIST_B_ELEMS)
|
||||||
|
#define MG HIST_B_ELEMS
|
||||||
|
|
||||||
|
#define BITS_IN_SAMPLE 8
|
||||||
|
|
||||||
|
#define R_SHIFT (BITS_IN_SAMPLE-PRECISION_R)
|
||||||
|
#define G_SHIFT (BITS_IN_SAMPLE-PRECISION_G)
|
||||||
|
#define B_SHIFT (BITS_IN_SAMPLE-PRECISION_B)
|
||||||
|
|
||||||
|
/* this has to match the INTENSITY definition in libgimp/gimpcolorspace.h */
|
||||||
|
#define R_SCALE 30 /* scale R distances by this much */
|
||||||
|
#define G_SCALE 59 /* scale G distances by this much */
|
||||||
|
#define B_SCALE 11 /* and B by this much */
|
||||||
|
|
||||||
|
|
||||||
typedef struct _Color Color;
|
typedef struct _Color Color;
|
||||||
typedef struct _QuantizeObj QuantizeObj;
|
typedef struct _QuantizeObj QuantizeObj;
|
||||||
typedef void (* Pass1_Func) (QuantizeObj *);
|
typedef void (* Pass1_Func) (QuantizeObj *);
|
||||||
|
@ -336,6 +348,82 @@ typedef void (* Cleanup_Func) (QuantizeObj *);
|
||||||
typedef unsigned long ColorFreq;
|
typedef unsigned long ColorFreq;
|
||||||
typedef ColorFreq *CFHistogram;
|
typedef ColorFreq *CFHistogram;
|
||||||
|
|
||||||
|
|
||||||
|
/* We effectively pull our three-dimensional space into five dimensions
|
||||||
|
such that the most-entropic bits lay in the lowest bits of the resulting
|
||||||
|
array index. This gives significantly better locality of reference
|
||||||
|
and hence a small speedup despite the extra work involved in calculating
|
||||||
|
the index.
|
||||||
|
|
||||||
|
Why not six dimensions? The expansion of dimensionality is good for random
|
||||||
|
access such as histogram population and the query pattern typical of
|
||||||
|
dithering but we have some code which iterates in a scanning manner, for
|
||||||
|
which the expansion is suboptimal. The compromise is to leave the B
|
||||||
|
dimension unmolested in the lower-order bits of the index, since this is
|
||||||
|
the dimension most commonly iterated through in the inner loop of the
|
||||||
|
scans.
|
||||||
|
|
||||||
|
--adam
|
||||||
|
|
||||||
|
RhGhRlGlB
|
||||||
|
*/
|
||||||
|
#define VOL_GBITS (PRECISION_G)
|
||||||
|
#define VOL_BBITS (PRECISION_B)
|
||||||
|
#define VOL_RBITS (PRECISION_R)
|
||||||
|
#define VOL_GBITSh (VOL_GBITS - 3)
|
||||||
|
#define VOL_GBITSl (VOL_GBITS - VOL_GBITSh)
|
||||||
|
#define VOL_BBITSh (VOL_BBITS - 4)
|
||||||
|
#define VOL_BBITSl (VOL_BBITS - VOL_BBITSh)
|
||||||
|
#define VOL_RBITSh (VOL_RBITS - 3)
|
||||||
|
#define VOL_RBITSl (VOL_RBITS - VOL_RBITSh)
|
||||||
|
#define VOL_GMASKh (((1<<VOL_GBITSh)-1) << VOL_GBITSl)
|
||||||
|
#define VOL_GMASKl ((1<<VOL_GBITSl)-1)
|
||||||
|
#define VOL_BMASKh (((1<<VOL_BBITSh)-1) << VOL_BBITSl)
|
||||||
|
#define VOL_BMASKl ((1<<VOL_BBITSl)-1)
|
||||||
|
#define VOL_RMASKh (((1<<VOL_RBITSh)-1) << VOL_RBITSl)
|
||||||
|
#define VOL_RMASKl ((1<<VOL_RBITSl)-1)
|
||||||
|
/* The 5d compromise thing. */
|
||||||
|
#define REF_FUNC(r,g,b) \
|
||||||
|
( \
|
||||||
|
(((r) & VOL_RMASKh) << (VOL_BBITS + VOL_GBITS)) | \
|
||||||
|
(((r) & VOL_RMASKl) << (VOL_GBITSl + VOL_BBITS)) | \
|
||||||
|
(((g) & VOL_GMASKh) << (VOL_RBITSl + VOL_BBITS)) | \
|
||||||
|
(((g) & VOL_GMASKl) << (VOL_BBITS)) | \
|
||||||
|
(b) \
|
||||||
|
)
|
||||||
|
/* The full-on 6d thing. */
|
||||||
|
/*
|
||||||
|
#define REF_FUNC(r,g,b) \
|
||||||
|
( \
|
||||||
|
(((r) & VOL_RMASKh) << (VOL_BBITS + VOL_GBITS)) | \
|
||||||
|
(((r) & VOL_RMASKl) << (VOL_GBITSl + VOL_BBITSl)) | \
|
||||||
|
(((g) & VOL_GMASKh) << (VOL_RBITSl + VOL_BBITS)) | \
|
||||||
|
(((g) & VOL_GMASKl) << (VOL_BBITSl)) | \
|
||||||
|
(((b) & VOL_BMASKh) << (VOL_RBITSl + VOL_GBITSl)) | \
|
||||||
|
((b) & VOL_BMASKl) \
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
/* The boring old 3d thing. */
|
||||||
|
/*
|
||||||
|
#define REF_FUNC(r,g,b) (((r)<<(PRECISION_G+PRECISION_B)) | ((g)<<(PRECISION_B)) | (b))
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* You even get to choose whether you want the accessor function
|
||||||
|
implemented as a macro or an inline function. Don't say I never
|
||||||
|
give you anything. */
|
||||||
|
/*
|
||||||
|
#define HIST_RGB(hist_ptr,r,g,b) (&(hist_ptr)[REF_FUNC((r),(g),(b))])
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
ColorFreq * HIST_RGB(const ColorFreq *hist_ptr,
|
||||||
|
const int r, const int g, const int b)
|
||||||
|
{
|
||||||
|
return (&(hist_ptr)[
|
||||||
|
REF_FUNC(r,g,b)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct _Color
|
struct _Color
|
||||||
{
|
{
|
||||||
int red;
|
int red;
|
||||||
|
@ -1608,12 +1696,8 @@ zero_histogram_gray (CFHistogram histogram)
|
||||||
static void
|
static void
|
||||||
zero_histogram_rgb (CFHistogram histogram)
|
zero_histogram_rgb (CFHistogram histogram)
|
||||||
{
|
{
|
||||||
int r, g, b;
|
memset(histogram, 0,
|
||||||
|
HIST_R_ELEMS * HIST_G_ELEMS * HIST_B_ELEMS * sizeof(ColorFreq));
|
||||||
for (r = 0; r < HIST_R_ELEMS; r++)
|
|
||||||
for (g = 0; g < HIST_G_ELEMS; g++)
|
|
||||||
for (b = 0; b < HIST_B_ELEMS; b++)
|
|
||||||
histogram[r*MR + g*MG + b] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1701,9 +1785,10 @@ generate_histogram_rgb (CFHistogram histogram,
|
||||||
)
|
)
|
||||||
|| (!has_alpha))
|
|| (!has_alpha))
|
||||||
{
|
{
|
||||||
colfreq = & histogram[(data[RED_PIX] >> R_SHIFT) * MR +
|
colfreq = HIST_RGB(histogram,
|
||||||
(data[GREEN_PIX] >> G_SHIFT) * MG +
|
data[RED_PIX] >> R_SHIFT,
|
||||||
(data[BLUE_PIX] >> B_SHIFT)];
|
data[GREEN_PIX] >> G_SHIFT,
|
||||||
|
data[BLUE_PIX] >> B_SHIFT);
|
||||||
(*colfreq)++;
|
(*colfreq)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1729,9 +1814,10 @@ generate_histogram_rgb (CFHistogram histogram,
|
||||||
)
|
)
|
||||||
|| (!has_alpha))
|
|| (!has_alpha))
|
||||||
{
|
{
|
||||||
colfreq = & histogram[(data[RED_PIX] >> R_SHIFT) * MR +
|
colfreq = HIST_RGB(histogram,
|
||||||
(data[GREEN_PIX] >> G_SHIFT) * MG +
|
data[RED_PIX] >> R_SHIFT,
|
||||||
(data[BLUE_PIX] >> B_SHIFT)];
|
data[GREEN_PIX] >> G_SHIFT,
|
||||||
|
data[BLUE_PIX] >> B_SHIFT);
|
||||||
(*colfreq)++;
|
(*colfreq)++;
|
||||||
}
|
}
|
||||||
data += srcPR.bytes;
|
data += srcPR.bytes;
|
||||||
|
@ -1751,9 +1837,10 @@ generate_histogram_rgb (CFHistogram histogram,
|
||||||
((data[ALPHA_PIX] << 6) > (255 * DM[col&DM_WIDTHMASK][row&DM_HEIGHTMASK])) :
|
((data[ALPHA_PIX] << 6) > (255 * DM[col&DM_WIDTHMASK][row&DM_HEIGHTMASK])) :
|
||||||
(data[ALPHA_PIX] > 127))) || (!has_alpha))
|
(data[ALPHA_PIX] > 127))) || (!has_alpha))
|
||||||
{
|
{
|
||||||
colfreq = & histogram[(data[RED_PIX] >> R_SHIFT) * MR +
|
colfreq = HIST_RGB(histogram,
|
||||||
(data[GREEN_PIX] >> G_SHIFT) * MG +
|
data[RED_PIX] >> R_SHIFT,
|
||||||
(data[BLUE_PIX] >> B_SHIFT)];
|
data[GREEN_PIX] >> G_SHIFT,
|
||||||
|
data[BLUE_PIX] >> B_SHIFT);
|
||||||
(*colfreq)++;
|
(*colfreq)++;
|
||||||
|
|
||||||
if (!needs_quantize)
|
if (!needs_quantize)
|
||||||
|
@ -1894,7 +1981,7 @@ update_box_gray (CFHistogram histogram,
|
||||||
/* and recompute its volume and population */
|
/* and recompute its volume and population */
|
||||||
{
|
{
|
||||||
int i, min, max, dist;
|
int i, min, max, dist;
|
||||||
long ccount;
|
ColorFreq ccount;
|
||||||
|
|
||||||
min = boxp->Rmin;
|
min = boxp->Rmin;
|
||||||
max = boxp->Rmax;
|
max = boxp->Rmax;
|
||||||
|
@ -1945,11 +2032,10 @@ update_box_rgb (CFHistogram histogram,
|
||||||
/* Shrink the min/max bounds of a box to enclose only nonzero elements, */
|
/* Shrink the min/max bounds of a box to enclose only nonzero elements, */
|
||||||
/* and recompute its volume, population and error */
|
/* and recompute its volume, population and error */
|
||||||
{
|
{
|
||||||
ColorFreq * histp;
|
|
||||||
int R,G,B;
|
int R,G,B;
|
||||||
int Rmin,Rmax,Gmin,Gmax,Bmin,Bmax;
|
int Rmin,Rmax,Gmin,Gmax,Bmin,Bmax;
|
||||||
int dist0,dist1,dist2;
|
int dist0,dist1,dist2;
|
||||||
long ccount;
|
ColorFreq ccount;
|
||||||
guint64 tempRerror;
|
guint64 tempRerror;
|
||||||
guint64 tempGerror;
|
guint64 tempGerror;
|
||||||
guint64 tempBerror;
|
guint64 tempBerror;
|
||||||
|
@ -1964,78 +2050,84 @@ update_box_rgb (CFHistogram histogram,
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
if (*histp++ != 0)
|
{
|
||||||
{
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
boxp->Rmin = Rmin = R;
|
{
|
||||||
goto have_Rmin;
|
boxp->Rmin = Rmin = R;
|
||||||
}
|
goto have_Rmin;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Rmin:
|
have_Rmin:
|
||||||
if (Rmax > Rmin)
|
if (Rmax > Rmin)
|
||||||
for (R = Rmax; R >= Rmin; R--)
|
for (R = Rmax; R >= Rmin; R--)
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
if (*histp++ != 0)
|
{
|
||||||
{
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
boxp->Rmax = Rmax = R;
|
{
|
||||||
goto have_Rmax;
|
boxp->Rmax = Rmax = R;
|
||||||
}
|
goto have_Rmax;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Rmax:
|
have_Rmax:
|
||||||
if (Gmax > Gmin)
|
if (Gmax > Gmin)
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
if (*histp++ != 0)
|
{
|
||||||
{
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
boxp->Gmin = Gmin = G;
|
{
|
||||||
goto have_Gmin;
|
boxp->Gmin = Gmin = G;
|
||||||
}
|
goto have_Gmin;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Gmin:
|
have_Gmin:
|
||||||
if (Gmax > Gmin)
|
if (Gmax > Gmin)
|
||||||
for (G = Gmax; G >= Gmin; G--)
|
for (G = Gmax; G >= Gmin; G--)
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
if (*histp++ != 0)
|
{
|
||||||
{
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
boxp->Gmax = Gmax = G;
|
{
|
||||||
goto have_Gmax;
|
boxp->Gmax = Gmax = G;
|
||||||
}
|
goto have_Gmax;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Gmax:
|
have_Gmax:
|
||||||
if (Bmax > Bmin)
|
if (Bmax > Bmin)
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + Gmin*MG + B;
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
for (G = Gmin; G <= Gmax; G++, histp += MG)
|
{
|
||||||
if (*histp != 0)
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
{
|
{
|
||||||
boxp->Bmin = Bmin = B;
|
boxp->Bmin = Bmin = B;
|
||||||
goto have_Bmin;
|
goto have_Bmin;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Bmin:
|
have_Bmin:
|
||||||
if (Bmax > Bmin)
|
if (Bmax > Bmin)
|
||||||
for (B = Bmax; B >= Bmin; B--)
|
for (B = Bmax; B >= Bmin; B--)
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + Gmin*MG + B;
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
for (G = Gmin; G <= Gmax; G++, histp += MG)
|
{
|
||||||
if (*histp != 0)
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
{
|
{
|
||||||
boxp->Bmax = Bmax = B;
|
boxp->Bmax = Bmax = B;
|
||||||
goto have_Bmax;
|
goto have_Bmax;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Bmax:
|
have_Bmax:
|
||||||
|
|
||||||
|
@ -2066,32 +2158,35 @@ update_box_rgb (CFHistogram histogram,
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
for (B = Bmin; B <= Bmax; B++, histp++)
|
{
|
||||||
if (*histp != 0)
|
ColorFreq freq_here;
|
||||||
{
|
freq_here = *HIST_RGB(histogram, R, G, B);
|
||||||
int ge, be, re;
|
if (freq_here != 0)
|
||||||
|
{
|
||||||
dummybox.Rmin = dummybox.Rmax = R;
|
int ge, be, re;
|
||||||
dummybox.Gmin = dummybox.Gmax = G;
|
|
||||||
dummybox.Bmin = dummybox.Bmax = B;
|
dummybox.Rmin = dummybox.Rmax = R;
|
||||||
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
dummybox.Gmin = dummybox.Gmax = G;
|
||||||
|
dummybox.Bmin = dummybox.Bmax = B;
|
||||||
re = dummyqo.cmap[0].red - dummyqo.cmap[1].red;
|
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
||||||
ge = dummyqo.cmap[0].green - dummyqo.cmap[1].green;
|
|
||||||
be = dummyqo.cmap[0].blue - dummyqo.cmap[1].blue;
|
re = dummyqo.cmap[0].red - dummyqo.cmap[1].red;
|
||||||
|
ge = dummyqo.cmap[0].green - dummyqo.cmap[1].green;
|
||||||
boxp->rerror += (*histp) * re*re;
|
be = dummyqo.cmap[0].blue - dummyqo.cmap[1].blue;
|
||||||
boxp->gerror += (*histp) * ge*ge;
|
|
||||||
boxp->berror += (*histp) * be*be;
|
boxp->rerror += freq_here * re*re;
|
||||||
|
boxp->gerror += freq_here * ge*ge;
|
||||||
boxp->error += (*histp) *
|
boxp->berror += freq_here * be*be;
|
||||||
(
|
|
||||||
re*re*R_SCALE + ge*ge*G_SCALE + be*be*B_SCALE
|
boxp->error += freq_here *
|
||||||
);
|
(
|
||||||
|
re*re*R_SCALE + ge*ge*G_SCALE + be*be*B_SCALE
|
||||||
ccount += *histp;
|
);
|
||||||
}
|
|
||||||
|
ccount += freq_here;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scan again, taking note of halfway error point for red axis */
|
/* Scan again, taking note of halfway error point for red axis */
|
||||||
|
@ -2103,23 +2198,26 @@ update_box_rgb (CFHistogram histogram,
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
dummybox.Gmin = dummybox.Gmax = G;
|
dummybox.Gmin = dummybox.Gmax = G;
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
for (B = Bmin; B <= Bmax; B++, histp++)
|
{
|
||||||
if (*histp != 0)
|
ColorFreq freq_here;
|
||||||
{
|
freq_here = *HIST_RGB(histogram, R, G, B);
|
||||||
int re;
|
if (freq_here != 0)
|
||||||
dummybox.Bmin = dummybox.Bmax = B;
|
{
|
||||||
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
int re;
|
||||||
|
dummybox.Bmin = dummybox.Bmax = B;
|
||||||
re = dummyqo.cmap[0].red - dummyqo.cmap[1].red;
|
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
||||||
|
|
||||||
tempRerror += (*histp)*re*re;
|
re = dummyqo.cmap[0].red - dummyqo.cmap[1].red;
|
||||||
|
|
||||||
if (tempRerror*2 > boxp->rerror)
|
tempRerror += freq_here * re*re;
|
||||||
goto green_axisscan;
|
|
||||||
else
|
if (tempRerror*2 > boxp->rerror)
|
||||||
boxp->Rhalferror = R;
|
goto green_axisscan;
|
||||||
}
|
else
|
||||||
|
boxp->Rhalferror = R;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2133,23 +2231,26 @@ update_box_rgb (CFHistogram histogram,
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
{
|
{
|
||||||
dummybox.Rmin = dummybox.Rmax = R;
|
dummybox.Rmin = dummybox.Rmax = R;
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
for (B = Bmin; B <= Bmax; B++, histp++)
|
{
|
||||||
if (*histp != 0)
|
ColorFreq freq_here;
|
||||||
{
|
freq_here = *HIST_RGB(histogram, R, G, B);
|
||||||
int ge;
|
if (freq_here != 0)
|
||||||
dummybox.Bmin = dummybox.Bmax = B;
|
{
|
||||||
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
int ge;
|
||||||
|
dummybox.Bmin = dummybox.Bmax = B;
|
||||||
ge = dummyqo.cmap[0].green - dummyqo.cmap[1].green;
|
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
||||||
|
|
||||||
tempGerror += (*histp)*ge*ge;
|
ge = dummyqo.cmap[0].green - dummyqo.cmap[1].green;
|
||||||
|
|
||||||
if (tempGerror*2 > boxp->gerror)
|
tempGerror += freq_here * ge*ge;
|
||||||
goto blue_axisscan;
|
|
||||||
else
|
if (tempGerror*2 > boxp->gerror)
|
||||||
boxp->Ghalferror = G;
|
goto blue_axisscan;
|
||||||
}
|
else
|
||||||
|
boxp->Ghalferror = G;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2165,8 +2266,9 @@ update_box_rgb (CFHistogram histogram,
|
||||||
dummybox.Rmin = dummybox.Rmax = R;
|
dummybox.Rmin = dummybox.Rmax = R;
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + B;
|
ColorFreq freq_here;
|
||||||
if (*histp != 0)
|
freq_here = *HIST_RGB(histogram, R, G, B);
|
||||||
|
if (freq_here != 0)
|
||||||
{
|
{
|
||||||
int be;
|
int be;
|
||||||
dummybox.Gmin = dummybox.Gmax = G;
|
dummybox.Gmin = dummybox.Gmax = G;
|
||||||
|
@ -2174,7 +2276,7 @@ update_box_rgb (CFHistogram histogram,
|
||||||
|
|
||||||
be = dummyqo.cmap[0].blue - dummyqo.cmap[1].blue;
|
be = dummyqo.cmap[0].blue - dummyqo.cmap[1].blue;
|
||||||
|
|
||||||
tempBerror += (*histp)*be*be;
|
tempBerror += freq_here * be*be;
|
||||||
|
|
||||||
if (tempBerror*2 > boxp->berror)
|
if (tempBerror*2 > boxp->berror)
|
||||||
goto finished_axesscan;
|
goto finished_axesscan;
|
||||||
|
@ -2402,16 +2504,14 @@ compute_color_rgb (QuantizeObj *quantobj,
|
||||||
{
|
{
|
||||||
/* Current algorithm: mean weighted by pixels (not colors) */
|
/* Current algorithm: mean weighted by pixels (not colors) */
|
||||||
/* Note it is important to get the rounding correct! */
|
/* Note it is important to get the rounding correct! */
|
||||||
ColorFreq * histp;
|
|
||||||
int R, G, B;
|
int R, G, B;
|
||||||
int Rmin, Rmax;
|
int Rmin, Rmax;
|
||||||
int Gmin, Gmax;
|
int Gmin, Gmax;
|
||||||
int Bmin, Bmax;
|
int Bmin, Bmax;
|
||||||
long count;
|
ColorFreq total = 0;
|
||||||
long total = 0;
|
ColorFreq Rtotal = 0;
|
||||||
long Rtotal = 0;
|
ColorFreq Gtotal = 0;
|
||||||
long Gtotal = 0;
|
ColorFreq Btotal = 0;
|
||||||
long Btotal = 0;
|
|
||||||
|
|
||||||
Rmin = boxp->Rmin; Rmax = boxp->Rmax;
|
Rmin = boxp->Rmin; Rmax = boxp->Rmax;
|
||||||
Gmin = boxp->Gmin; Gmax = boxp->Gmax;
|
Gmin = boxp->Gmin; Gmax = boxp->Gmax;
|
||||||
|
@ -2420,24 +2520,24 @@ compute_color_rgb (QuantizeObj *quantobj,
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
{
|
{
|
||||||
if ((count = *histp++) != 0)
|
ColorFreq this_freq = *HIST_RGB(histogram, R, G, B);
|
||||||
|
if (this_freq != 0)
|
||||||
{
|
{
|
||||||
total += count;
|
total += this_freq;
|
||||||
Rtotal += ((R << R_SHIFT) + ((1<<R_SHIFT)>>1)) * count;
|
Rtotal += ((R << R_SHIFT) + ((1<<R_SHIFT)>>1)) * this_freq;
|
||||||
Gtotal += ((G << G_SHIFT) + ((1<<G_SHIFT)>>1)) * count;
|
Gtotal += ((G << G_SHIFT) + ((1<<G_SHIFT)>>1)) * this_freq;
|
||||||
Btotal += ((B << B_SHIFT) + ((1<<B_SHIFT)>>1)) * count;
|
Btotal += ((B << B_SHIFT) + ((1<<B_SHIFT)>>1)) * this_freq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (total != 0)
|
if (total != 0)
|
||||||
{
|
{
|
||||||
quantobj->cmap[icolor].red = (Rtotal + (total>>1)) / total;
|
quantobj->cmap[icolor].red = (Rtotal + (total>>1)) / total;
|
||||||
quantobj->cmap[icolor].green = (Gtotal + (total>>1)) / total;
|
quantobj->cmap[icolor].green = (Gtotal + (total>>1)) / total;
|
||||||
quantobj->cmap[icolor].blue = (Btotal + (total>>1)) / total;
|
quantobj->cmap[icolor].blue = (Btotal + (total>>1)) / total;
|
||||||
}
|
}
|
||||||
else /* The only situation where total==0 is if the image was null or
|
else /* The only situation where total==0 is if the image was null or
|
||||||
* all-transparent. In that case we just put a dummy value in
|
* all-transparent. In that case we just put a dummy value in
|
||||||
|
@ -2856,7 +2956,6 @@ fill_inverse_cmap_rgb (QuantizeObj *quantobj,
|
||||||
int minR, minG, minB; /* lower left corner of update box */
|
int minR, minG, minB; /* lower left corner of update box */
|
||||||
int iR, iG, iB;
|
int iR, iG, iB;
|
||||||
int * cptr; /* pointer into bestcolor[] array */
|
int * cptr; /* pointer into bestcolor[] array */
|
||||||
ColorFreq * cachep; /* pointer into main cache array */
|
|
||||||
/* This array lists the candidate colormap indexes. */
|
/* This array lists the candidate colormap indexes. */
|
||||||
int colorlist[MAXNUMCOLORS];
|
int colorlist[MAXNUMCOLORS];
|
||||||
int numcolors; /* number of candidate colors */
|
int numcolors; /* number of candidate colors */
|
||||||
|
@ -2892,9 +2991,8 @@ fill_inverse_cmap_rgb (QuantizeObj *quantobj,
|
||||||
cptr = bestcolor;
|
cptr = bestcolor;
|
||||||
for (iR = 0; iR < BOX_R_ELEMS; iR++) {
|
for (iR = 0; iR < BOX_R_ELEMS; iR++) {
|
||||||
for (iG = 0; iG < BOX_G_ELEMS; iG++) {
|
for (iG = 0; iG < BOX_G_ELEMS; iG++) {
|
||||||
cachep = & histogram[(R+iR)*MR+(G+iG)*MG+B];
|
|
||||||
for (iB = 0; iB < BOX_B_ELEMS; iB++) {
|
for (iB = 0; iB < BOX_B_ELEMS; iB++) {
|
||||||
*cachep++ = (*cptr++) + 1;
|
*HIST_RGB(histogram, R+iR, G+iG, B+iB) = (*cptr++) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3165,7 +3263,7 @@ median_cut_pass2_no_dither_rgb (QuantizeObj *quantobj,
|
||||||
R = (src[red_pix]) >> R_SHIFT;
|
R = (src[red_pix]) >> R_SHIFT;
|
||||||
G = (src[green_pix]) >> G_SHIFT;
|
G = (src[green_pix]) >> G_SHIFT;
|
||||||
B = (src[blue_pix]) >> B_SHIFT;
|
B = (src[blue_pix]) >> B_SHIFT;
|
||||||
cachep = &histogram[R*MR + G*MG + B];
|
cachep = HIST_RGB(histogram,R,G,B);
|
||||||
/* If we have not seen this color before, find nearest
|
/* If we have not seen this color before, find nearest
|
||||||
colormap entry and update the cache */
|
colormap entry and update the cache */
|
||||||
if (*cachep == 0)
|
if (*cachep == 0)
|
||||||
|
@ -3246,7 +3344,7 @@ median_cut_pass2_fixed_dither_rgb (QuantizeObj *quantobj,
|
||||||
R = (src[red_pix]) >> R_SHIFT;
|
R = (src[red_pix]) >> R_SHIFT;
|
||||||
G = (src[green_pix]) >> G_SHIFT;
|
G = (src[green_pix]) >> G_SHIFT;
|
||||||
B = (src[blue_pix]) >> B_SHIFT;
|
B = (src[blue_pix]) >> B_SHIFT;
|
||||||
cachep = &histogram[R*MR + G*MG + B];
|
cachep = HIST_RGB(histogram,R,G,B);
|
||||||
/* If we have not seen this color before, find nearest
|
/* If we have not seen this color before, find nearest
|
||||||
colormap entry and update the cache */
|
colormap entry and update the cache */
|
||||||
if (*cachep == 0)
|
if (*cachep == 0)
|
||||||
|
@ -3271,7 +3369,7 @@ median_cut_pass2_fixed_dither_rgb (QuantizeObj *quantobj,
|
||||||
G = (CLAMP0255(color->green + ge)) >> G_SHIFT;
|
G = (CLAMP0255(color->green + ge)) >> G_SHIFT;
|
||||||
B = (CLAMP0255(color->blue + be)) >> B_SHIFT;
|
B = (CLAMP0255(color->blue + be)) >> B_SHIFT;
|
||||||
|
|
||||||
cachep = &histogram[R*MR + G*MG + B];
|
cachep = HIST_RGB(histogram,R,G,B);
|
||||||
/* If we have not seen this color before, find nearest
|
/* If we have not seen this color before, find nearest
|
||||||
colormap entry and update the cache */
|
colormap entry and update the cache */
|
||||||
if (*cachep == 0)
|
if (*cachep == 0)
|
||||||
|
@ -3824,7 +3922,7 @@ median_cut_pass2_fs_dither_rgb (QuantizeObj *quantobj,
|
||||||
ge = g >> G_SHIFT;
|
ge = g >> G_SHIFT;
|
||||||
be = b >> B_SHIFT;
|
be = b >> B_SHIFT;
|
||||||
|
|
||||||
cachep = &histogram[re*MR + ge*MG + be];
|
cachep = HIST_RGB(histogram, re, ge, be);
|
||||||
/* If we have not seen this color before, find nearest
|
/* If we have not seen this color before, find nearest
|
||||||
colormap entry and update the cache */
|
colormap entry and update the cache */
|
||||||
if (*cachep == 0)
|
if (*cachep == 0)
|
||||||
|
|
|
@ -19,12 +19,20 @@
|
||||||
/*
|
/*
|
||||||
* TODO for Convert:
|
* TODO for Convert:
|
||||||
*
|
*
|
||||||
* Use palette of another open INDEXED image
|
* . Quantize in (for example) CIE L*a*b*
|
||||||
*
|
* . Use palette of another open INDEXED image
|
||||||
* Do error-splitting trick for GREY->INDEXED
|
* . Do error-splitting trick for GREY->INDEXED
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* 2001-03-25 - Define accessor function/macro for histogram reads and
|
||||||
|
* writes. This slows us down a little because we avoid some of the
|
||||||
|
* dirty tricks we used when we knew that the histogram was a straight
|
||||||
|
* 3d array, so I've recovered some of the speed loss by implementing
|
||||||
|
* a 5d accessor function with good locality of reference. This change
|
||||||
|
* is the first step towards quantizing in a more interesting colourspace
|
||||||
|
* than frumpy old RGB. [Adam]
|
||||||
|
*
|
||||||
* 2000/01/30 - Use palette_selector instead of option_menu for custom
|
* 2000/01/30 - Use palette_selector instead of option_menu for custom
|
||||||
* palette. Use libgimp callback functions. [Sven]
|
* palette. Use libgimp callback functions. [Sven]
|
||||||
*
|
*
|
||||||
|
@ -125,28 +133,8 @@
|
||||||
#include "libgimp/gimpintl.h"
|
#include "libgimp/gimpintl.h"
|
||||||
|
|
||||||
|
|
||||||
#define PRECISION_R 6
|
|
||||||
#define PRECISION_G 6
|
|
||||||
#define PRECISION_B 6
|
|
||||||
|
|
||||||
#define HIST_R_ELEMS (1<<PRECISION_R)
|
|
||||||
#define HIST_G_ELEMS (1<<PRECISION_G)
|
|
||||||
#define HIST_B_ELEMS (1<<PRECISION_B)
|
|
||||||
|
|
||||||
#define MR HIST_G_ELEMS*HIST_B_ELEMS
|
|
||||||
#define MG HIST_B_ELEMS
|
|
||||||
|
|
||||||
#define BITS_IN_SAMPLE 8
|
|
||||||
|
|
||||||
#define R_SHIFT (BITS_IN_SAMPLE-PRECISION_R)
|
|
||||||
#define G_SHIFT (BITS_IN_SAMPLE-PRECISION_G)
|
|
||||||
#define B_SHIFT (BITS_IN_SAMPLE-PRECISION_B)
|
|
||||||
|
|
||||||
/* this has to match the INTENSITY definition in libgimp/gimpcolorspace.h */
|
|
||||||
#define R_SCALE 30 /* scale R distances by this much */
|
|
||||||
#define G_SCALE 59 /* scale G distances by this much */
|
|
||||||
#define B_SCALE 11 /* and B by this much */
|
|
||||||
|
|
||||||
|
/* bleh! */
|
||||||
static const unsigned char webpal[] =
|
static const unsigned char webpal[] =
|
||||||
{
|
{
|
||||||
255,255,255,255,255,204,255,255,153,255,255,102,255,255,51,255,255,0,255,
|
255,255,255,255,255,204,255,255,153,255,255,102,255,255,51,255,255,0,255,
|
||||||
|
@ -327,6 +315,30 @@ static const guchar DM[128][128] =
|
||||||
{ 51, 14, 61, 29, 59, 20, 55, 31, 0, 49, 11, 60, 3, 26, 22, 56, 0, 40, 12, 43, 41, 8, 36, 0, 17, 57, 24, 2, 46, 26, 61, 18, 0, 38, 12, 59, 6, 49, 3, 57, 19, 63, 5, 33, 18, 54, 28, 56, 0, 43, 26, 46, 63, 27, 56, 22, 27, 54, 38, 28, 63, 24, 10, 45, 0, 31, 42, 21, 12, 25, 44, 49, 59, 6, 26, 50, 3, 34, 27, 59, 0, 35, 62, 16, 4, 58, 47, 0, 43, 24, 37, 2, 54, 20, 46, 31, 0, 56, 34, 5, 55, 45, 60, 37, 0, 40, 10, 38, 63, 46, 15, 20, 0, 53, 21, 62, 30, 11, 24, 27, 40, 0, 57, 26, 3, 45, 27, 35 },
|
{ 51, 14, 61, 29, 59, 20, 55, 31, 0, 49, 11, 60, 3, 26, 22, 56, 0, 40, 12, 43, 41, 8, 36, 0, 17, 57, 24, 2, 46, 26, 61, 18, 0, 38, 12, 59, 6, 49, 3, 57, 19, 63, 5, 33, 18, 54, 28, 56, 0, 43, 26, 46, 63, 27, 56, 22, 27, 54, 38, 28, 63, 24, 10, 45, 0, 31, 42, 21, 12, 25, 44, 49, 59, 6, 26, 50, 3, 34, 27, 59, 0, 35, 62, 16, 4, 58, 47, 0, 43, 24, 37, 2, 54, 20, 46, 31, 0, 56, 34, 5, 55, 45, 60, 37, 0, 40, 10, 38, 63, 46, 15, 20, 0, 53, 21, 62, 30, 11, 24, 27, 40, 0, 57, 26, 3, 45, 27, 35 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define PRECISION_R 6
|
||||||
|
#define PRECISION_G 6
|
||||||
|
#define PRECISION_B 6
|
||||||
|
|
||||||
|
#define HIST_R_ELEMS (1<<PRECISION_R)
|
||||||
|
#define HIST_G_ELEMS (1<<PRECISION_G)
|
||||||
|
#define HIST_B_ELEMS (1<<PRECISION_B)
|
||||||
|
|
||||||
|
#define MR (HIST_G_ELEMS*HIST_B_ELEMS)
|
||||||
|
#define MG HIST_B_ELEMS
|
||||||
|
|
||||||
|
#define BITS_IN_SAMPLE 8
|
||||||
|
|
||||||
|
#define R_SHIFT (BITS_IN_SAMPLE-PRECISION_R)
|
||||||
|
#define G_SHIFT (BITS_IN_SAMPLE-PRECISION_G)
|
||||||
|
#define B_SHIFT (BITS_IN_SAMPLE-PRECISION_B)
|
||||||
|
|
||||||
|
/* this has to match the INTENSITY definition in libgimp/gimpcolorspace.h */
|
||||||
|
#define R_SCALE 30 /* scale R distances by this much */
|
||||||
|
#define G_SCALE 59 /* scale G distances by this much */
|
||||||
|
#define B_SCALE 11 /* and B by this much */
|
||||||
|
|
||||||
|
|
||||||
typedef struct _Color Color;
|
typedef struct _Color Color;
|
||||||
typedef struct _QuantizeObj QuantizeObj;
|
typedef struct _QuantizeObj QuantizeObj;
|
||||||
typedef void (* Pass1_Func) (QuantizeObj *);
|
typedef void (* Pass1_Func) (QuantizeObj *);
|
||||||
|
@ -336,6 +348,82 @@ typedef void (* Cleanup_Func) (QuantizeObj *);
|
||||||
typedef unsigned long ColorFreq;
|
typedef unsigned long ColorFreq;
|
||||||
typedef ColorFreq *CFHistogram;
|
typedef ColorFreq *CFHistogram;
|
||||||
|
|
||||||
|
|
||||||
|
/* We effectively pull our three-dimensional space into five dimensions
|
||||||
|
such that the most-entropic bits lay in the lowest bits of the resulting
|
||||||
|
array index. This gives significantly better locality of reference
|
||||||
|
and hence a small speedup despite the extra work involved in calculating
|
||||||
|
the index.
|
||||||
|
|
||||||
|
Why not six dimensions? The expansion of dimensionality is good for random
|
||||||
|
access such as histogram population and the query pattern typical of
|
||||||
|
dithering but we have some code which iterates in a scanning manner, for
|
||||||
|
which the expansion is suboptimal. The compromise is to leave the B
|
||||||
|
dimension unmolested in the lower-order bits of the index, since this is
|
||||||
|
the dimension most commonly iterated through in the inner loop of the
|
||||||
|
scans.
|
||||||
|
|
||||||
|
--adam
|
||||||
|
|
||||||
|
RhGhRlGlB
|
||||||
|
*/
|
||||||
|
#define VOL_GBITS (PRECISION_G)
|
||||||
|
#define VOL_BBITS (PRECISION_B)
|
||||||
|
#define VOL_RBITS (PRECISION_R)
|
||||||
|
#define VOL_GBITSh (VOL_GBITS - 3)
|
||||||
|
#define VOL_GBITSl (VOL_GBITS - VOL_GBITSh)
|
||||||
|
#define VOL_BBITSh (VOL_BBITS - 4)
|
||||||
|
#define VOL_BBITSl (VOL_BBITS - VOL_BBITSh)
|
||||||
|
#define VOL_RBITSh (VOL_RBITS - 3)
|
||||||
|
#define VOL_RBITSl (VOL_RBITS - VOL_RBITSh)
|
||||||
|
#define VOL_GMASKh (((1<<VOL_GBITSh)-1) << VOL_GBITSl)
|
||||||
|
#define VOL_GMASKl ((1<<VOL_GBITSl)-1)
|
||||||
|
#define VOL_BMASKh (((1<<VOL_BBITSh)-1) << VOL_BBITSl)
|
||||||
|
#define VOL_BMASKl ((1<<VOL_BBITSl)-1)
|
||||||
|
#define VOL_RMASKh (((1<<VOL_RBITSh)-1) << VOL_RBITSl)
|
||||||
|
#define VOL_RMASKl ((1<<VOL_RBITSl)-1)
|
||||||
|
/* The 5d compromise thing. */
|
||||||
|
#define REF_FUNC(r,g,b) \
|
||||||
|
( \
|
||||||
|
(((r) & VOL_RMASKh) << (VOL_BBITS + VOL_GBITS)) | \
|
||||||
|
(((r) & VOL_RMASKl) << (VOL_GBITSl + VOL_BBITS)) | \
|
||||||
|
(((g) & VOL_GMASKh) << (VOL_RBITSl + VOL_BBITS)) | \
|
||||||
|
(((g) & VOL_GMASKl) << (VOL_BBITS)) | \
|
||||||
|
(b) \
|
||||||
|
)
|
||||||
|
/* The full-on 6d thing. */
|
||||||
|
/*
|
||||||
|
#define REF_FUNC(r,g,b) \
|
||||||
|
( \
|
||||||
|
(((r) & VOL_RMASKh) << (VOL_BBITS + VOL_GBITS)) | \
|
||||||
|
(((r) & VOL_RMASKl) << (VOL_GBITSl + VOL_BBITSl)) | \
|
||||||
|
(((g) & VOL_GMASKh) << (VOL_RBITSl + VOL_BBITS)) | \
|
||||||
|
(((g) & VOL_GMASKl) << (VOL_BBITSl)) | \
|
||||||
|
(((b) & VOL_BMASKh) << (VOL_RBITSl + VOL_GBITSl)) | \
|
||||||
|
((b) & VOL_BMASKl) \
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
/* The boring old 3d thing. */
|
||||||
|
/*
|
||||||
|
#define REF_FUNC(r,g,b) (((r)<<(PRECISION_G+PRECISION_B)) | ((g)<<(PRECISION_B)) | (b))
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* You even get to choose whether you want the accessor function
|
||||||
|
implemented as a macro or an inline function. Don't say I never
|
||||||
|
give you anything. */
|
||||||
|
/*
|
||||||
|
#define HIST_RGB(hist_ptr,r,g,b) (&(hist_ptr)[REF_FUNC((r),(g),(b))])
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
ColorFreq * HIST_RGB(const ColorFreq *hist_ptr,
|
||||||
|
const int r, const int g, const int b)
|
||||||
|
{
|
||||||
|
return (&(hist_ptr)[
|
||||||
|
REF_FUNC(r,g,b)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct _Color
|
struct _Color
|
||||||
{
|
{
|
||||||
int red;
|
int red;
|
||||||
|
@ -1608,12 +1696,8 @@ zero_histogram_gray (CFHistogram histogram)
|
||||||
static void
|
static void
|
||||||
zero_histogram_rgb (CFHistogram histogram)
|
zero_histogram_rgb (CFHistogram histogram)
|
||||||
{
|
{
|
||||||
int r, g, b;
|
memset(histogram, 0,
|
||||||
|
HIST_R_ELEMS * HIST_G_ELEMS * HIST_B_ELEMS * sizeof(ColorFreq));
|
||||||
for (r = 0; r < HIST_R_ELEMS; r++)
|
|
||||||
for (g = 0; g < HIST_G_ELEMS; g++)
|
|
||||||
for (b = 0; b < HIST_B_ELEMS; b++)
|
|
||||||
histogram[r*MR + g*MG + b] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1701,9 +1785,10 @@ generate_histogram_rgb (CFHistogram histogram,
|
||||||
)
|
)
|
||||||
|| (!has_alpha))
|
|| (!has_alpha))
|
||||||
{
|
{
|
||||||
colfreq = & histogram[(data[RED_PIX] >> R_SHIFT) * MR +
|
colfreq = HIST_RGB(histogram,
|
||||||
(data[GREEN_PIX] >> G_SHIFT) * MG +
|
data[RED_PIX] >> R_SHIFT,
|
||||||
(data[BLUE_PIX] >> B_SHIFT)];
|
data[GREEN_PIX] >> G_SHIFT,
|
||||||
|
data[BLUE_PIX] >> B_SHIFT);
|
||||||
(*colfreq)++;
|
(*colfreq)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1729,9 +1814,10 @@ generate_histogram_rgb (CFHistogram histogram,
|
||||||
)
|
)
|
||||||
|| (!has_alpha))
|
|| (!has_alpha))
|
||||||
{
|
{
|
||||||
colfreq = & histogram[(data[RED_PIX] >> R_SHIFT) * MR +
|
colfreq = HIST_RGB(histogram,
|
||||||
(data[GREEN_PIX] >> G_SHIFT) * MG +
|
data[RED_PIX] >> R_SHIFT,
|
||||||
(data[BLUE_PIX] >> B_SHIFT)];
|
data[GREEN_PIX] >> G_SHIFT,
|
||||||
|
data[BLUE_PIX] >> B_SHIFT);
|
||||||
(*colfreq)++;
|
(*colfreq)++;
|
||||||
}
|
}
|
||||||
data += srcPR.bytes;
|
data += srcPR.bytes;
|
||||||
|
@ -1751,9 +1837,10 @@ generate_histogram_rgb (CFHistogram histogram,
|
||||||
((data[ALPHA_PIX] << 6) > (255 * DM[col&DM_WIDTHMASK][row&DM_HEIGHTMASK])) :
|
((data[ALPHA_PIX] << 6) > (255 * DM[col&DM_WIDTHMASK][row&DM_HEIGHTMASK])) :
|
||||||
(data[ALPHA_PIX] > 127))) || (!has_alpha))
|
(data[ALPHA_PIX] > 127))) || (!has_alpha))
|
||||||
{
|
{
|
||||||
colfreq = & histogram[(data[RED_PIX] >> R_SHIFT) * MR +
|
colfreq = HIST_RGB(histogram,
|
||||||
(data[GREEN_PIX] >> G_SHIFT) * MG +
|
data[RED_PIX] >> R_SHIFT,
|
||||||
(data[BLUE_PIX] >> B_SHIFT)];
|
data[GREEN_PIX] >> G_SHIFT,
|
||||||
|
data[BLUE_PIX] >> B_SHIFT);
|
||||||
(*colfreq)++;
|
(*colfreq)++;
|
||||||
|
|
||||||
if (!needs_quantize)
|
if (!needs_quantize)
|
||||||
|
@ -1894,7 +1981,7 @@ update_box_gray (CFHistogram histogram,
|
||||||
/* and recompute its volume and population */
|
/* and recompute its volume and population */
|
||||||
{
|
{
|
||||||
int i, min, max, dist;
|
int i, min, max, dist;
|
||||||
long ccount;
|
ColorFreq ccount;
|
||||||
|
|
||||||
min = boxp->Rmin;
|
min = boxp->Rmin;
|
||||||
max = boxp->Rmax;
|
max = boxp->Rmax;
|
||||||
|
@ -1945,11 +2032,10 @@ update_box_rgb (CFHistogram histogram,
|
||||||
/* Shrink the min/max bounds of a box to enclose only nonzero elements, */
|
/* Shrink the min/max bounds of a box to enclose only nonzero elements, */
|
||||||
/* and recompute its volume, population and error */
|
/* and recompute its volume, population and error */
|
||||||
{
|
{
|
||||||
ColorFreq * histp;
|
|
||||||
int R,G,B;
|
int R,G,B;
|
||||||
int Rmin,Rmax,Gmin,Gmax,Bmin,Bmax;
|
int Rmin,Rmax,Gmin,Gmax,Bmin,Bmax;
|
||||||
int dist0,dist1,dist2;
|
int dist0,dist1,dist2;
|
||||||
long ccount;
|
ColorFreq ccount;
|
||||||
guint64 tempRerror;
|
guint64 tempRerror;
|
||||||
guint64 tempGerror;
|
guint64 tempGerror;
|
||||||
guint64 tempBerror;
|
guint64 tempBerror;
|
||||||
|
@ -1964,78 +2050,84 @@ update_box_rgb (CFHistogram histogram,
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
if (*histp++ != 0)
|
{
|
||||||
{
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
boxp->Rmin = Rmin = R;
|
{
|
||||||
goto have_Rmin;
|
boxp->Rmin = Rmin = R;
|
||||||
}
|
goto have_Rmin;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Rmin:
|
have_Rmin:
|
||||||
if (Rmax > Rmin)
|
if (Rmax > Rmin)
|
||||||
for (R = Rmax; R >= Rmin; R--)
|
for (R = Rmax; R >= Rmin; R--)
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
if (*histp++ != 0)
|
{
|
||||||
{
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
boxp->Rmax = Rmax = R;
|
{
|
||||||
goto have_Rmax;
|
boxp->Rmax = Rmax = R;
|
||||||
}
|
goto have_Rmax;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Rmax:
|
have_Rmax:
|
||||||
if (Gmax > Gmin)
|
if (Gmax > Gmin)
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
if (*histp++ != 0)
|
{
|
||||||
{
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
boxp->Gmin = Gmin = G;
|
{
|
||||||
goto have_Gmin;
|
boxp->Gmin = Gmin = G;
|
||||||
}
|
goto have_Gmin;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Gmin:
|
have_Gmin:
|
||||||
if (Gmax > Gmin)
|
if (Gmax > Gmin)
|
||||||
for (G = Gmax; G >= Gmin; G--)
|
for (G = Gmax; G >= Gmin; G--)
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
if (*histp++ != 0)
|
{
|
||||||
{
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
boxp->Gmax = Gmax = G;
|
{
|
||||||
goto have_Gmax;
|
boxp->Gmax = Gmax = G;
|
||||||
}
|
goto have_Gmax;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Gmax:
|
have_Gmax:
|
||||||
if (Bmax > Bmin)
|
if (Bmax > Bmin)
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + Gmin*MG + B;
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
for (G = Gmin; G <= Gmax; G++, histp += MG)
|
{
|
||||||
if (*histp != 0)
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
{
|
{
|
||||||
boxp->Bmin = Bmin = B;
|
boxp->Bmin = Bmin = B;
|
||||||
goto have_Bmin;
|
goto have_Bmin;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Bmin:
|
have_Bmin:
|
||||||
if (Bmax > Bmin)
|
if (Bmax > Bmin)
|
||||||
for (B = Bmax; B >= Bmin; B--)
|
for (B = Bmax; B >= Bmin; B--)
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + Gmin*MG + B;
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
for (G = Gmin; G <= Gmax; G++, histp += MG)
|
{
|
||||||
if (*histp != 0)
|
if (*HIST_RGB(histogram, R, G, B) != 0)
|
||||||
{
|
{
|
||||||
boxp->Bmax = Bmax = B;
|
boxp->Bmax = Bmax = B;
|
||||||
goto have_Bmax;
|
goto have_Bmax;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
have_Bmax:
|
have_Bmax:
|
||||||
|
|
||||||
|
@ -2066,32 +2158,35 @@ update_box_rgb (CFHistogram histogram,
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
for (B = Bmin; B <= Bmax; B++, histp++)
|
{
|
||||||
if (*histp != 0)
|
ColorFreq freq_here;
|
||||||
{
|
freq_here = *HIST_RGB(histogram, R, G, B);
|
||||||
int ge, be, re;
|
if (freq_here != 0)
|
||||||
|
{
|
||||||
dummybox.Rmin = dummybox.Rmax = R;
|
int ge, be, re;
|
||||||
dummybox.Gmin = dummybox.Gmax = G;
|
|
||||||
dummybox.Bmin = dummybox.Bmax = B;
|
dummybox.Rmin = dummybox.Rmax = R;
|
||||||
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
dummybox.Gmin = dummybox.Gmax = G;
|
||||||
|
dummybox.Bmin = dummybox.Bmax = B;
|
||||||
re = dummyqo.cmap[0].red - dummyqo.cmap[1].red;
|
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
||||||
ge = dummyqo.cmap[0].green - dummyqo.cmap[1].green;
|
|
||||||
be = dummyqo.cmap[0].blue - dummyqo.cmap[1].blue;
|
re = dummyqo.cmap[0].red - dummyqo.cmap[1].red;
|
||||||
|
ge = dummyqo.cmap[0].green - dummyqo.cmap[1].green;
|
||||||
boxp->rerror += (*histp) * re*re;
|
be = dummyqo.cmap[0].blue - dummyqo.cmap[1].blue;
|
||||||
boxp->gerror += (*histp) * ge*ge;
|
|
||||||
boxp->berror += (*histp) * be*be;
|
boxp->rerror += freq_here * re*re;
|
||||||
|
boxp->gerror += freq_here * ge*ge;
|
||||||
boxp->error += (*histp) *
|
boxp->berror += freq_here * be*be;
|
||||||
(
|
|
||||||
re*re*R_SCALE + ge*ge*G_SCALE + be*be*B_SCALE
|
boxp->error += freq_here *
|
||||||
);
|
(
|
||||||
|
re*re*R_SCALE + ge*ge*G_SCALE + be*be*B_SCALE
|
||||||
ccount += *histp;
|
);
|
||||||
}
|
|
||||||
|
ccount += freq_here;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scan again, taking note of halfway error point for red axis */
|
/* Scan again, taking note of halfway error point for red axis */
|
||||||
|
@ -2103,23 +2198,26 @@ update_box_rgb (CFHistogram histogram,
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
dummybox.Gmin = dummybox.Gmax = G;
|
dummybox.Gmin = dummybox.Gmax = G;
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
for (B = Bmin; B <= Bmax; B++, histp++)
|
{
|
||||||
if (*histp != 0)
|
ColorFreq freq_here;
|
||||||
{
|
freq_here = *HIST_RGB(histogram, R, G, B);
|
||||||
int re;
|
if (freq_here != 0)
|
||||||
dummybox.Bmin = dummybox.Bmax = B;
|
{
|
||||||
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
int re;
|
||||||
|
dummybox.Bmin = dummybox.Bmax = B;
|
||||||
re = dummyqo.cmap[0].red - dummyqo.cmap[1].red;
|
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
||||||
|
|
||||||
tempRerror += (*histp)*re*re;
|
re = dummyqo.cmap[0].red - dummyqo.cmap[1].red;
|
||||||
|
|
||||||
if (tempRerror*2 > boxp->rerror)
|
tempRerror += freq_here * re*re;
|
||||||
goto green_axisscan;
|
|
||||||
else
|
if (tempRerror*2 > boxp->rerror)
|
||||||
boxp->Rhalferror = R;
|
goto green_axisscan;
|
||||||
}
|
else
|
||||||
|
boxp->Rhalferror = R;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2133,23 +2231,26 @@ update_box_rgb (CFHistogram histogram,
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
{
|
{
|
||||||
dummybox.Rmin = dummybox.Rmax = R;
|
dummybox.Rmin = dummybox.Rmax = R;
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
for (B = Bmin; B <= Bmax; B++, histp++)
|
{
|
||||||
if (*histp != 0)
|
ColorFreq freq_here;
|
||||||
{
|
freq_here = *HIST_RGB(histogram, R, G, B);
|
||||||
int ge;
|
if (freq_here != 0)
|
||||||
dummybox.Bmin = dummybox.Bmax = B;
|
{
|
||||||
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
int ge;
|
||||||
|
dummybox.Bmin = dummybox.Bmax = B;
|
||||||
ge = dummyqo.cmap[0].green - dummyqo.cmap[1].green;
|
compute_color_rgb(&dummyqo, histogram, &dummybox, 1);
|
||||||
|
|
||||||
tempGerror += (*histp)*ge*ge;
|
ge = dummyqo.cmap[0].green - dummyqo.cmap[1].green;
|
||||||
|
|
||||||
if (tempGerror*2 > boxp->gerror)
|
tempGerror += freq_here * ge*ge;
|
||||||
goto blue_axisscan;
|
|
||||||
else
|
if (tempGerror*2 > boxp->gerror)
|
||||||
boxp->Ghalferror = G;
|
goto blue_axisscan;
|
||||||
}
|
else
|
||||||
|
boxp->Ghalferror = G;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2165,8 +2266,9 @@ update_box_rgb (CFHistogram histogram,
|
||||||
dummybox.Rmin = dummybox.Rmax = R;
|
dummybox.Rmin = dummybox.Rmax = R;
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + B;
|
ColorFreq freq_here;
|
||||||
if (*histp != 0)
|
freq_here = *HIST_RGB(histogram, R, G, B);
|
||||||
|
if (freq_here != 0)
|
||||||
{
|
{
|
||||||
int be;
|
int be;
|
||||||
dummybox.Gmin = dummybox.Gmax = G;
|
dummybox.Gmin = dummybox.Gmax = G;
|
||||||
|
@ -2174,7 +2276,7 @@ update_box_rgb (CFHistogram histogram,
|
||||||
|
|
||||||
be = dummyqo.cmap[0].blue - dummyqo.cmap[1].blue;
|
be = dummyqo.cmap[0].blue - dummyqo.cmap[1].blue;
|
||||||
|
|
||||||
tempBerror += (*histp)*be*be;
|
tempBerror += freq_here * be*be;
|
||||||
|
|
||||||
if (tempBerror*2 > boxp->berror)
|
if (tempBerror*2 > boxp->berror)
|
||||||
goto finished_axesscan;
|
goto finished_axesscan;
|
||||||
|
@ -2402,16 +2504,14 @@ compute_color_rgb (QuantizeObj *quantobj,
|
||||||
{
|
{
|
||||||
/* Current algorithm: mean weighted by pixels (not colors) */
|
/* Current algorithm: mean weighted by pixels (not colors) */
|
||||||
/* Note it is important to get the rounding correct! */
|
/* Note it is important to get the rounding correct! */
|
||||||
ColorFreq * histp;
|
|
||||||
int R, G, B;
|
int R, G, B;
|
||||||
int Rmin, Rmax;
|
int Rmin, Rmax;
|
||||||
int Gmin, Gmax;
|
int Gmin, Gmax;
|
||||||
int Bmin, Bmax;
|
int Bmin, Bmax;
|
||||||
long count;
|
ColorFreq total = 0;
|
||||||
long total = 0;
|
ColorFreq Rtotal = 0;
|
||||||
long Rtotal = 0;
|
ColorFreq Gtotal = 0;
|
||||||
long Gtotal = 0;
|
ColorFreq Btotal = 0;
|
||||||
long Btotal = 0;
|
|
||||||
|
|
||||||
Rmin = boxp->Rmin; Rmax = boxp->Rmax;
|
Rmin = boxp->Rmin; Rmax = boxp->Rmax;
|
||||||
Gmin = boxp->Gmin; Gmax = boxp->Gmax;
|
Gmin = boxp->Gmin; Gmax = boxp->Gmax;
|
||||||
|
@ -2420,24 +2520,24 @@ compute_color_rgb (QuantizeObj *quantobj,
|
||||||
for (R = Rmin; R <= Rmax; R++)
|
for (R = Rmin; R <= Rmax; R++)
|
||||||
for (G = Gmin; G <= Gmax; G++)
|
for (G = Gmin; G <= Gmax; G++)
|
||||||
{
|
{
|
||||||
histp = histogram + R*MR + G*MG + Bmin;
|
|
||||||
for (B = Bmin; B <= Bmax; B++)
|
for (B = Bmin; B <= Bmax; B++)
|
||||||
{
|
{
|
||||||
if ((count = *histp++) != 0)
|
ColorFreq this_freq = *HIST_RGB(histogram, R, G, B);
|
||||||
|
if (this_freq != 0)
|
||||||
{
|
{
|
||||||
total += count;
|
total += this_freq;
|
||||||
Rtotal += ((R << R_SHIFT) + ((1<<R_SHIFT)>>1)) * count;
|
Rtotal += ((R << R_SHIFT) + ((1<<R_SHIFT)>>1)) * this_freq;
|
||||||
Gtotal += ((G << G_SHIFT) + ((1<<G_SHIFT)>>1)) * count;
|
Gtotal += ((G << G_SHIFT) + ((1<<G_SHIFT)>>1)) * this_freq;
|
||||||
Btotal += ((B << B_SHIFT) + ((1<<B_SHIFT)>>1)) * count;
|
Btotal += ((B << B_SHIFT) + ((1<<B_SHIFT)>>1)) * this_freq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (total != 0)
|
if (total != 0)
|
||||||
{
|
{
|
||||||
quantobj->cmap[icolor].red = (Rtotal + (total>>1)) / total;
|
quantobj->cmap[icolor].red = (Rtotal + (total>>1)) / total;
|
||||||
quantobj->cmap[icolor].green = (Gtotal + (total>>1)) / total;
|
quantobj->cmap[icolor].green = (Gtotal + (total>>1)) / total;
|
||||||
quantobj->cmap[icolor].blue = (Btotal + (total>>1)) / total;
|
quantobj->cmap[icolor].blue = (Btotal + (total>>1)) / total;
|
||||||
}
|
}
|
||||||
else /* The only situation where total==0 is if the image was null or
|
else /* The only situation where total==0 is if the image was null or
|
||||||
* all-transparent. In that case we just put a dummy value in
|
* all-transparent. In that case we just put a dummy value in
|
||||||
|
@ -2856,7 +2956,6 @@ fill_inverse_cmap_rgb (QuantizeObj *quantobj,
|
||||||
int minR, minG, minB; /* lower left corner of update box */
|
int minR, minG, minB; /* lower left corner of update box */
|
||||||
int iR, iG, iB;
|
int iR, iG, iB;
|
||||||
int * cptr; /* pointer into bestcolor[] array */
|
int * cptr; /* pointer into bestcolor[] array */
|
||||||
ColorFreq * cachep; /* pointer into main cache array */
|
|
||||||
/* This array lists the candidate colormap indexes. */
|
/* This array lists the candidate colormap indexes. */
|
||||||
int colorlist[MAXNUMCOLORS];
|
int colorlist[MAXNUMCOLORS];
|
||||||
int numcolors; /* number of candidate colors */
|
int numcolors; /* number of candidate colors */
|
||||||
|
@ -2892,9 +2991,8 @@ fill_inverse_cmap_rgb (QuantizeObj *quantobj,
|
||||||
cptr = bestcolor;
|
cptr = bestcolor;
|
||||||
for (iR = 0; iR < BOX_R_ELEMS; iR++) {
|
for (iR = 0; iR < BOX_R_ELEMS; iR++) {
|
||||||
for (iG = 0; iG < BOX_G_ELEMS; iG++) {
|
for (iG = 0; iG < BOX_G_ELEMS; iG++) {
|
||||||
cachep = & histogram[(R+iR)*MR+(G+iG)*MG+B];
|
|
||||||
for (iB = 0; iB < BOX_B_ELEMS; iB++) {
|
for (iB = 0; iB < BOX_B_ELEMS; iB++) {
|
||||||
*cachep++ = (*cptr++) + 1;
|
*HIST_RGB(histogram, R+iR, G+iG, B+iB) = (*cptr++) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3165,7 +3263,7 @@ median_cut_pass2_no_dither_rgb (QuantizeObj *quantobj,
|
||||||
R = (src[red_pix]) >> R_SHIFT;
|
R = (src[red_pix]) >> R_SHIFT;
|
||||||
G = (src[green_pix]) >> G_SHIFT;
|
G = (src[green_pix]) >> G_SHIFT;
|
||||||
B = (src[blue_pix]) >> B_SHIFT;
|
B = (src[blue_pix]) >> B_SHIFT;
|
||||||
cachep = &histogram[R*MR + G*MG + B];
|
cachep = HIST_RGB(histogram,R,G,B);
|
||||||
/* If we have not seen this color before, find nearest
|
/* If we have not seen this color before, find nearest
|
||||||
colormap entry and update the cache */
|
colormap entry and update the cache */
|
||||||
if (*cachep == 0)
|
if (*cachep == 0)
|
||||||
|
@ -3246,7 +3344,7 @@ median_cut_pass2_fixed_dither_rgb (QuantizeObj *quantobj,
|
||||||
R = (src[red_pix]) >> R_SHIFT;
|
R = (src[red_pix]) >> R_SHIFT;
|
||||||
G = (src[green_pix]) >> G_SHIFT;
|
G = (src[green_pix]) >> G_SHIFT;
|
||||||
B = (src[blue_pix]) >> B_SHIFT;
|
B = (src[blue_pix]) >> B_SHIFT;
|
||||||
cachep = &histogram[R*MR + G*MG + B];
|
cachep = HIST_RGB(histogram,R,G,B);
|
||||||
/* If we have not seen this color before, find nearest
|
/* If we have not seen this color before, find nearest
|
||||||
colormap entry and update the cache */
|
colormap entry and update the cache */
|
||||||
if (*cachep == 0)
|
if (*cachep == 0)
|
||||||
|
@ -3271,7 +3369,7 @@ median_cut_pass2_fixed_dither_rgb (QuantizeObj *quantobj,
|
||||||
G = (CLAMP0255(color->green + ge)) >> G_SHIFT;
|
G = (CLAMP0255(color->green + ge)) >> G_SHIFT;
|
||||||
B = (CLAMP0255(color->blue + be)) >> B_SHIFT;
|
B = (CLAMP0255(color->blue + be)) >> B_SHIFT;
|
||||||
|
|
||||||
cachep = &histogram[R*MR + G*MG + B];
|
cachep = HIST_RGB(histogram,R,G,B);
|
||||||
/* If we have not seen this color before, find nearest
|
/* If we have not seen this color before, find nearest
|
||||||
colormap entry and update the cache */
|
colormap entry and update the cache */
|
||||||
if (*cachep == 0)
|
if (*cachep == 0)
|
||||||
|
@ -3824,7 +3922,7 @@ median_cut_pass2_fs_dither_rgb (QuantizeObj *quantobj,
|
||||||
ge = g >> G_SHIFT;
|
ge = g >> G_SHIFT;
|
||||||
be = b >> B_SHIFT;
|
be = b >> B_SHIFT;
|
||||||
|
|
||||||
cachep = &histogram[re*MR + ge*MG + be];
|
cachep = HIST_RGB(histogram, re, ge, be);
|
||||||
/* If we have not seen this color before, find nearest
|
/* If we have not seen this color before, find nearest
|
||||||
colormap entry and update the cache */
|
colormap entry and update the cache */
|
||||||
if (*cachep == 0)
|
if (*cachep == 0)
|
||||||
|
|
Loading…
Reference in New Issue