8-bit (or bigger indexed) png files at some point
*/
#include "imager.h"
+#include "imageri.h"
+static void makemap_webmap(i_quantize *);
static void makemap_addi(i_quantize *, i_img **imgs, int count);
static void makemap_mediancut(i_quantize *, i_img **imgs, int count);
static void makemap_mono(i_quantize *);
+static int makemap_palette(i_quantize *, i_img **imgs, int count);
+
static
void
setcol(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
*/
/*
-=item i_quant_makemap(quant, imgs, count)
+=item i_quant_makemap(C<quant>, C<imgs>, C<count>)
=category Image quantization
-Analyzes the I<count> images in I<imgs> according to the rules in
-I<quant> to build a color map (optimal or not depending on
-quant->make_colors).
+Analyzes the C<count> images in C<imgs> according to the rules in
+C<quant> to build a color map (optimal or not depending on
+C<< quant->make_colors >>).
=cut
*/
/* use user's specified map */
break;
case mc_web_map:
- {
- int r, g, b;
- int i = 0;
- for (r = 0; r < 256; r+=0x33)
- for (g = 0; g < 256; g+=0x33)
- for (b = 0; b < 256; b += 0x33)
- setcol(quant->mc_colors+i++, r, g, b, 255);
- quant->mc_count = i;
- }
+ makemap_webmap(quant);
break;
case mc_median_cut:
static void translate_addi(i_quantize *, i_img *, i_palidx *);
/*
-=item i_quant_translate(quant, img)
+=item i_quant_translate(C<quant>, C<img>)
=category Image quantization
-Quantize the image given the palette in quant.
+Quantize the image given the palette in C<quant>.
-On success returns a pointer to a memory block of img->xsize *
-img->ysize i_palidx entries.
+On success returns a pointer to a memory block of C<< img->xsize *
+img->ysize >> C<i_palidx> entries.
On failure returns NULL.
+ PWR2(cv->b - chans[2]);
}
-static
-int
-ceucl_d(i_color *c1, i_color *c2) { return PWR2(c1->channel[0]-c2->channel[0])+PWR2(c1->channel[1]-c2->channel[1])+PWR2(c1->channel[2]-c2->channel[2]); }
+static int
+ceucl_d(i_color *c1, i_color *c2) {
+return PWR2(c1->channel[0]-c2->channel[0])
+ +PWR2(c1->channel[1]-c2->channel[1])
+ +PWR2(c1->channel[2]-c2->channel[2]);
+}
static const int
gray_samples[] = { 0, 0, 0 };
mm_log((1, "makemap_addi(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n",
quant, quant->mc_count, quant->mc_colors, imgs, count));
+
+ if (makemap_palette(quant, imgs, count))
+ return;
i_mempool_init(&mp);
#endif
i_mempool_destroy(&mp);
+
+ mm_log((1, "makemap_addi() - %d colors\n", quant->mc_count));
}
typedef struct {
this isn't terribly efficient, but it should work */
int chan_count;
- /*printf("images %d pal size %d\n", count, quant->mc_size);*/
+ mm_log((1, "makemap_mediancut(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n",
+ quant, quant->mc_count, quant->mc_colors, imgs, count));
+
+ if (makemap_palette(quant, imgs, count))
+ return;
i_mempool_init(&mp);
}
/*printf("out %d colors\n", quant->mc_count);*/
i_mempool_destroy(&mp);
+
+ mm_log((1, "makemap_mediancut() - %d colors\n", quant->mc_count));
}
static void
quant->mc_count = 2;
}
+static void
+makemap_webmap(i_quantize *quant) {
+ int r, g, b;
+
+ int i = 0;
+ for (r = 0; r < 256; r+=0x33)
+ for (g = 0; g < 256; g+=0x33)
+ for (b = 0; b < 256; b += 0x33)
+ setcol(quant->mc_colors+i++, r, g, b, 255);
+ quant->mc_count = i;
+}
+
+static int
+in_palette(i_color *c, i_quantize *quant, int size) {
+ int i;
+
+ for (i = 0; i < size; ++i) {
+ if (c->channel[0] == quant->mc_colors[i].channel[0]
+ && c->channel[1] == quant->mc_colors[i].channel[1]
+ && c->channel[2] == quant->mc_colors[i].channel[2]) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+/*
+=item makemap_palette(quant, imgs, count)
+
+Tests if all the given images are paletted and have a common palette,
+if they do it builds that palette.
+
+A possible improvement might be to eliminate unused colors in the
+images palettes.
+
+=cut
+*/
+
+static int
+makemap_palette(i_quantize *quant, i_img **imgs, int count) {
+ int size = quant->mc_count;
+ int i;
+ int imgn;
+ char used[256];
+ int col_count;
+
+ mm_log((1, "makemap_palette(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n",
+ quant, quant->mc_count, quant->mc_colors, imgs, count));
+ /* we try to build a common palette here, if we can manage that, then
+ that's the palette we use */
+ for (imgn = 0; imgn < count; ++imgn) {
+ int eliminate_unused;
+ if (imgs[imgn]->type != i_palette_type) {
+ mm_log((1, "makemap_palette() -> 0 (non-palette image)\n"));
+ return 0;
+ }
+
+ if (!i_tags_get_int(&imgs[imgn]->tags, "gif_eliminate_unused", 0,
+ &eliminate_unused)) {
+ eliminate_unused = 1;
+ }
+
+ if (eliminate_unused) {
+ i_palidx *line = mymalloc(sizeof(i_palidx) * imgs[imgn]->xsize);
+ int x, y;
+ memset(used, 0, sizeof(used));
+
+ for (y = 0; y < imgs[imgn]->ysize; ++y) {
+ i_gpal(imgs[imgn], 0, imgs[imgn]->xsize, y, line);
+ for (x = 0; x < imgs[imgn]->xsize; ++x)
+ used[line[x]] = 1;
+ }
+
+ myfree(line);
+ }
+ else {
+ /* assume all are in use */
+ memset(used, 1, sizeof(used));
+ }
+
+ col_count = i_colorcount(imgs[imgn]);
+ for (i = 0; i < col_count; ++i) {
+ i_color c;
+
+ i_getcolors(imgs[imgn], i, &c, 1);
+ if (used[i]) {
+ if (in_palette(&c, quant, size) < 0) {
+ if (size < quant->mc_size) {
+ quant->mc_colors[size++] = c;
+ }
+ else {
+ mm_log((1, "makemap_palette() -> 0 (too many colors)\n"));
+ return 0;
+ }
+ }
+ }
+ }
+ }
+
+ mm_log((1, "makemap_palette() -> 1 (%d total colors)\n", size));
+ quant->mc_count = size;
+
+ return 1;
+}
+
#define pboxjump 32
/* Define one of the following 4 symbols to choose a colour search method
/*#define IM_CFRAND2DIST*/
#endif
+/* return true if the color map contains only grays */
+static int
+is_gray_map(const i_quantize *quant) {
+ int i;
+
+ for (i = 0; i < quant->mc_count; ++i) {
+ if (quant->mc_colors[i].rgb.r != quant->mc_colors[i].rgb.g
+ || quant->mc_colors[i].rgb.r != quant->mc_colors[i].rgb.b) {
+ mm_log((1, " not a gray map\n"));
+ return 0;
+ }
+ }
+
+ mm_log((1, " is a gray map\n"));
+ return 1;
+}
+
#ifdef IM_CFHASHBOX
/* The original version I wrote for this used the sort.
int difftotal;
int x, y, dx, dy;
int bst_idx = 0;
+ int is_gray = is_gray_map(quant);
CF_VARS;
if ((quant->errdiff & ed_mask) == ed_custom) {
if (img->channels < 3) {
val.channel[1] = val.channel[2] = val.channel[0];
}
+ else if (is_gray) {
+ int gray = 0.5 + color_to_grey(&val);
+ val.channel[0] = val.channel[1] = val.channel[2] = gray;
+ }
perr = err[x+mapo];
perr.r = perr.r < 0 ? -((-perr.r)/difftotal) : perr.r/difftotal;
perr.g = perr.g < 0 ? -((-perr.g)/difftotal) : perr.g/difftotal;
static void transparent_ordered(i_quantize *, i_palidx *, i_img *, i_palidx);
/*
-=item i_quant_transparent(quant, data, img, trans_index)
+=item i_quant_transparent(C<quant>, C<data>, C<img>, C<trans_index>)
=category Image quantization
-Dither the alpha channel on I<img> into the palette indexes in
-I<data>. Pixels to be transparent are replaced with I<trans_pixel>.
+Dither the alpha channel on C<img> into the palette indexes in
+C<data>. Pixels to be transparent are replaced with C<trans_pixel>.
-The method used depends on the tr_* members of quant.
+The method used depends on the tr_* members of C<quant>.
=cut
*/