From 233036b3cbee596d2bd8e2a8c08a8dd7b9b52270 Mon Sep 17 00:00:00 2001 From: Eddie Kohler Date: Mon, 19 Feb 2024 15:18:03 -0500 Subject: [PATCH] Change kcolor signatures, add helpers. --- src/kcolor.c | 58 +++++++++++--------------------- src/kcolor.h | 91 +++++++++++++++++++++++++++----------------------- src/quantize.c | 91 +++++++++++++++++++++++++------------------------- src/xform.c | 11 +++--- 4 files changed, 121 insertions(+), 130 deletions(-) diff --git a/src/kcolor.c b/src/kcolor.c index ad4cf43..bebfc66 100644 --- a/src/kcolor.c +++ b/src/kcolor.c @@ -101,10 +101,10 @@ pthread_mutex_t kd3_sort_lock; const char* kc_debug_str(kcolor x) { static int whichbuf = 0; - static char buf[4][64]; - whichbuf = (whichbuf + 1) % 4; + static char buf[8][64]; + whichbuf = (whichbuf + 1) % 8; if (x.a[0] >= 0 && x.a[1] >= 0 && x.a[2] >= 0) { - kc_revgamma_transform(&x); + x = kc_revgamma_transform(x); snprintf(buf[whichbuf], sizeof(buf[whichbuf]), "#%02X%02X%02X", x.a[0] >> 7, x.a[1] >> 7, x.a[2] >> 7); } else @@ -154,14 +154,15 @@ void kc_set_gamma(int type, double gamma) { #endif } -void kc_revgamma_transform(kcolor* x) { +kcolor kc_revgamma_transform(kcolor x) { int d; for (d = 0; d != 3; ++d) { - int c = gamma_tables[1][x->a[d] >> 7]; - while (c < 0x7F80 && x->a[d] >= gamma_tables[0][(c + 0x80) >> 7]) + int c = gamma_tables[1][x.a[d] >> 7]; + while (c < 0x7F80 && x.a[d] >= gamma_tables[0][(c + 0x80) >> 7]) c += 0x80; - x->a[d] = c; + x.a[d] = c; } + return x; } #if 0 @@ -170,13 +171,11 @@ static void kc_test_gamma() { for (x = 0; x != 256; ++x) for (y = 0; y != 256; ++y) for (z = 0; z != 256; ++z) { - kcolor k; - kc_set8g(&k, x, y, z); + kcolor k = kc_make8g(x, y, z); kc_revgamma_transform(&k); if ((k.a[0] >> 7) != x || (k.a[1] >> 7) != y || (k.a[2] >> 7) != z) { - kcolor kg; - kc_set8g(&kg, x, y, z); + kcolor kg = kc_make8g(x, y, z); fprintf(stderr, "#%02X%02X%02X ->g #%04X%04X%04X ->revg #%02X%02X%02X!\n", x, y, z, kg.a[0], kg.a[1], kg.a[2], k.a[0] >> 7, k.a[1] >> 7, k.a[2] >> 7); @@ -359,12 +358,12 @@ struct kd3_treepos { int offset; }; -void kd3_init(kd3_tree* kd3, void (*transform)(kcolor*)) { +void kd3_init(kd3_tree* kd3, kcolor (*transform)(int, int, int)) { kd3->tree = NULL; kd3->ks = Gif_NewArray(kcolor, 256); kd3->nitems = 0; kd3->items_cap = 256; - kd3->transform = transform; + kd3->transform = transform ? transform : kc_make8g; kd3->xradius = NULL; kd3->disabled = -1; } @@ -375,12 +374,12 @@ void kd3_cleanup(kd3_tree* kd3) { Gif_DeleteArray(kd3->xradius); } -void kd3_add_transformed(kd3_tree* kd3, const kcolor* k) { +void kd3_add_transformed(kd3_tree* kd3, kcolor k) { if (kd3->nitems == kd3->items_cap) { kd3->items_cap *= 2; Gif_ReArray(kd3->ks, kcolor, kd3->items_cap); } - kd3->ks[kd3->nitems] = *k; + kd3->ks[kd3->nitems] = k; ++kd3->nitems; if (kd3->tree) { Gif_DeleteArray(kd3->tree); @@ -390,14 +389,6 @@ void kd3_add_transformed(kd3_tree* kd3, const kcolor* k) { } } -void kd3_add8g(kd3_tree* kd3, int a0, int a1, int a2) { - kcolor k; - kc_set8g(&k, a0, a1, a2); - if (kd3->transform) - kd3->transform(&k); - kd3_add_transformed(kd3, &k); -} - static kd3_tree* kd3_sorter; static int kd3_item_compare_0(const void* a, const void* b) { @@ -525,7 +516,7 @@ void kd3_build_xradius(kd3_tree* kd3) { kd3->xradius[i] = (unsigned) -1; for (i = 0; i != kd3->nitems; ++i) for (j = i + 1; j != kd3->nitems; ++j) { - unsigned dist = kc_distance(&kd3->ks[i], &kd3->ks[j]); + unsigned dist = kc_distance(kd3->ks[i], kd3->ks[j]); unsigned radius = dist / 4; if (radius < kd3->xradius[i]) kd3->xradius[i] = radius; @@ -574,7 +565,7 @@ void kd3_build(kd3_tree* kd3) { Gif_DeleteArray(perm); } -void kd3_init_build(kd3_tree* kd3, void (*transform)(kcolor*), +void kd3_init_build(kd3_tree* kd3, kcolor (*transform)(int, int, int), const Gif_Colormap* gfcm) { int i; kd3_init(kd3, transform); @@ -584,8 +575,7 @@ void kd3_init_build(kd3_tree* kd3, void (*transform)(kcolor*), kd3_build(kd3); } -int kd3_closest_transformed(kd3_tree* kd3, const kcolor* k, - unsigned* dist_store) { +int kd3_closest_transformed(kd3_tree* kd3, kcolor k, unsigned* dist_store) { const kd3_treepos* stack[32]; uint8_t state[32]; int stackpos = 0; @@ -605,7 +595,7 @@ int kd3_closest_transformed(kd3_tree* kd3, const kcolor* k, if (p->offset < 0) { if (p->pivot >= 0 && kd3->disabled != p->pivot) { - unsigned dist = kc_distance(&kd3->ks[p->pivot], k); + unsigned dist = kc_distance(kd3->ks[p->pivot], k); if (dist < mindist) { mindist = dist; result = p->pivot; @@ -614,14 +604,14 @@ int kd3_closest_transformed(kd3_tree* kd3, const kcolor* k, if (--stackpos >= 0) ++state[stackpos]; } else if (state[stackpos] == 0) { - if (k->a[stackpos % 3] < p->pivot) + if (k.a[stackpos % 3] < p->pivot) stack[stackpos + 1] = p + 1; else stack[stackpos + 1] = p + p->offset; ++stackpos; state[stackpos] = 0; } else { - int delta = k->a[stackpos % 3] - p->pivot; + int delta = k.a[stackpos % 3] - p->pivot; if (state[stackpos] == 1 && (unsigned) delta * (unsigned) delta < mindist) { if (delta < 0) @@ -639,11 +629,3 @@ int kd3_closest_transformed(kd3_tree* kd3, const kcolor* k, *dist_store = mindist; return result; } - -int kd3_closest8g(kd3_tree* kd3, int a0, int a1, int a2) { - kcolor k; - kc_set8g(&k, a0, a1, a2); - if (kd3->transform) - kd3->transform(&k); - return kd3_closest_transformed(kd3, &k, NULL); -} diff --git a/src/kcolor.h b/src/kcolor.h index 2934a00..dab14e1 100644 --- a/src/kcolor.h +++ b/src/kcolor.h @@ -46,17 +46,12 @@ typedef union kacolor { extern uint16_t* gamma_tables[2]; -/* set `*kc` to the gamma transformation of `a0/a1/a2` [RGB] */ -static inline void kc_set8g(kcolor* kc, int a0, int a1, int a2) { - kc->a[0] = gamma_tables[0][a0]; - kc->a[1] = gamma_tables[0][a1]; - kc->a[2] = gamma_tables[0][a2]; -} - /* return the gamma transformation of `a0/a1/a2` [RGB] */ static inline kcolor kc_make8g(int a0, int a1, int a2) { kcolor kc; - kc_set8g(&kc, a0, a1, a2); + kc.a[0] = gamma_tables[0][a0]; + kc.a[1] = gamma_tables[0][a1]; + kc.a[2] = gamma_tables[0][a2]; return kc; } @@ -90,38 +85,37 @@ static inline kacolor kac_transparent() { const char* kc_debug_str(kcolor x); /* set `*x` to the reverse gamma transformation of `*x` */ -void kc_revgamma_transform(kcolor* x); +kcolor kc_revgamma_transform(kcolor x); /* return the reverse gramma transformation of `*x` as a Gif_Color */ -static inline Gif_Color kc_togfcg(const kcolor* x) { - kcolor xx = *x; +static inline Gif_Color kc_togfcg(kcolor x) { Gif_Color gfc; - kc_revgamma_transform(&xx); - gfc.gfc_red = (uint8_t) (xx.a[0] >> 7); - gfc.gfc_green = (uint8_t) (xx.a[1] >> 7); - gfc.gfc_blue = (uint8_t) (xx.a[2] >> 7); + x = kc_revgamma_transform(x); + gfc.gfc_red = (uint8_t) (x.a[0] >> 7); + gfc.gfc_green = (uint8_t) (x.a[1] >> 7); + gfc.gfc_blue = (uint8_t) (x.a[2] >> 7); gfc.haspixel = 0; return gfc; } /* return the squared Euclidean distance between `*x` and `*y` */ -static inline uint32_t kc_distance(const kcolor* x, const kcolor* y) { +static inline uint32_t kc_distance(kcolor x, kcolor y) { /* It’s OK to use unsigned multiplication for this: the low 32 bits are the same either way. Unsigned avoids undefined behavior. */ - uint32_t d0 = x->a[0] - y->a[0]; - uint32_t d1 = x->a[1] - y->a[1]; - uint32_t d2 = x->a[2] - y->a[2]; + uint32_t d0 = x.a[0] - y.a[0]; + uint32_t d1 = x.a[1] - y.a[1]; + uint32_t d2 = x.a[2] - y.a[2]; return d0 * d0 + d1 * d1 + d2 * d2; } /* return the luminance value for `*x`; result is between 0 and KC_MAX */ -static inline int kc_luminance(const kcolor* x) { - return (55 * x->a[0] + 183 * x->a[1] + 19 * x->a[2]) >> 8; +static inline int kc_luminance(kcolor kc) { + return (55 * kc.a[0] + 183 * kc.a[1] + 19 * kc.a[2]) >> 8; } /* set `*x` to the grayscale version of `*x`, transformed by luminance */ -static inline void kc_luminance_transform(kcolor* x) { +static inline kcolor kc_luminance_transform(int a0, int a1, int a2) { /* For grayscale colormaps, use distance in luminance space instead of distance in RGB space. The weights for the R,G,B components in luminance space are 0.2126,0.7152,0.0722. (That's ITU primaries, which @@ -129,8 +123,10 @@ static inline void kc_luminance_transform(kcolor* x) { 0.299,0.587,0.114.) Using the proportional factors 55,183,19 we get a scaled gray value between 0 and 255 * 257; dividing by 256 gives us what we want. Thanks to Christian Kumpf, , for - providing a patch.*/ - x->a[0] = x->a[1] = x->a[2] = kc_luminance(x); + providing a patch. */ + kcolor kc = kc_make8g(a0, a1, a2); + kc.a[0] = kc.a[1] = kc.a[2] = kc_luminance(kc); + return kc; } @@ -158,22 +154,34 @@ struct kd3_tree { int nitems; int items_cap; int maxdepth; - void (*transform)(kcolor*); + kcolor (*transform)(int, int, int); unsigned* xradius; }; /* initialize `kd3` with the given color `transform` (may be NULL) */ -void kd3_init(kd3_tree* kd3, void (*transform)(kcolor*)); +void kd3_init(kd3_tree* kd3, kcolor (*transform)(int, int, int)); /* free `kd3` */ void kd3_cleanup(kd3_tree* kd3); +/* return the transformed color for 8-bit color `a0/a1/a2` (RGB) */ +static inline kcolor kd3_make8g(kd3_tree* kd3, int a0, int a1, int a2) { + return kd3->transform(a0, a1, a2); +} + +/* return the transformed color for `*gfc` */ +static inline kcolor kd3_makegfcg(kd3_tree* kd3, const Gif_Color* gfc) { + return kd3_make8g(kd3, gfc->gfc_red, gfc->gfc_green, gfc->gfc_blue); +} + /* add the transformed color `k` to `*kd3` (do not apply `kd3->transform`). */ -void kd3_add_transformed(kd3_tree* kd3, const kcolor* k); +void kd3_add_transformed(kd3_tree* kd3, kcolor k); -/* given 8-bit color `a0/a1/a2` (RGB), gamma-transform it, transform it - by `kd3->transform` if necessary, and add it to `*kd3` */ -void kd3_add8g(kd3_tree* kd3, int a0, int a1, int a2); +/* given 8-bit color `a0/a1/a2` (RGB), transform it by `kd3->transform` + (e.g., apply gamma), and add it to `*kd3` */ +static inline void kd3_add8g(kd3_tree* kd3, int a0, int a1, int a2) { + kd3_add_transformed(kd3, kd3_make8g(kd3, a0, a1, a2)); +} /* set `kd3->xradius`. given color `i`, `kd3->xradius[i]` is the square of the color's uniquely owned neighborhood. @@ -185,18 +193,19 @@ void kd3_build_xradius(kd3_tree* kd3); void kd3_build(kd3_tree* kd3); /* kd3_init + kd3_add8g for all colors in `gfcm` + kd3_build */ -void kd3_init_build(kd3_tree* kd3, void (*transform)(kcolor*), +void kd3_init_build(kd3_tree* kd3, kcolor (*transform)(int, int, int), const Gif_Colormap* gfcm); /* return the index of the color in `*kd3` closest to `k`. if `dist!=NULL`, store the distance from `k` to that index in `*dist`. */ -int kd3_closest_transformed(kd3_tree* kd3, const kcolor* k, - unsigned* dist); +int kd3_closest_transformed(kd3_tree* kd3, kcolor k, unsigned* dist); -/* given 8-bit color `a0/a1/a2` (RGB), gamma-transform it, transform it by - `kd3->transform` if necessary, and return the index of the color in - `*kd3` closest to it. */ -int kd3_closest8g(kd3_tree* kd3, int a0, int a1, int a2); +/* given 8-bit color `a0/a1/a2` (RGB), transform it by `kd3->transform` + (e.g., apply gamma), and return the index of the color in `*kd3` + closest to the result. */ +static inline int kd3_closest8g(kd3_tree* kd3, int a0, int a1, int a2) { + return kd3_closest_transformed(kd3, kd3_make8g(kd3, a0, a1, a2), NULL); +} /* disable color index `i` in `*kd3`: it will never be returned by `kd3_closest*` */ @@ -293,11 +302,11 @@ static inline void sc_clear(scale_color* x) { x->a[0] = x->a[1] = x->a[2] = x->a[3] = 0; } -static inline scale_color sc_makekc(const kcolor* k) { +static inline scale_color sc_makekc(kcolor k) { scale_color sc; - sc.a[0] = k->a[0]; - sc.a[1] = k->a[1]; - sc.a[2] = k->a[2]; + sc.a[0] = k.a[0]; + sc.a[1] = k.a[1]; + sc.a[2] = k.a[2]; sc.a[3] = KC_MAX; return sc; } diff --git a/src/quantize.c b/src/quantize.c index f206f64..243c79b 100644 --- a/src/quantize.c +++ b/src/quantize.c @@ -143,7 +143,7 @@ Gif_Colormap* colormap_median_cut(kchist* kch, Gt_OutputData* od) kc.a[0] = (int) (px[0] / slots[i].pixel); kc.a[1] = (int) (px[1] / slots[i].pixel); kc.a[2] = (int) (px[2] / slots[i].pixel); - adapt[i] = kc_togfcg(&kc); + adapt[i] = kc_togfcg(kc); } Gif_DeleteArray(slots); @@ -218,7 +218,7 @@ int kcdiversity_choose(kcdiversity* div, int chosen, int dodither) { /* adjust the min_dist array */ for (i = 0; i != n; ++i) if (div->min_dist[i]) { - uint32_t dist = kc_distance(&hist[i].ka.k, &hist[chosen].ka.k); + uint32_t dist = kc_distance(hist[i].ka.k, hist[chosen].ka.k); if (dist < div->min_dist[i]) { div->min_dist[i] = dist; div->closest[i] = chosen; @@ -230,7 +230,7 @@ int kcdiversity_choose(kcdiversity* div, int chosen, int dodither) { for (i = 0; i != div->nchosen; ++i) { kcolor x = hist[chosen].ka.k, *y = &hist[div->chosen[i]].ka.k; /* penalize combinations with large luminance difference */ - double dL = abs(kc_luminance(&x) - kc_luminance(y)); + double dL = abs(kc_luminance(x) - kc_luminance(*y)); dL = (dL > 8192 ? dL * 4 / 32767. : 1); /* create combination */ for (k = 0; k != 3; ++k) @@ -238,7 +238,7 @@ int kcdiversity_choose(kcdiversity* div, int chosen, int dodither) { /* track closeness of combination to other colors */ for (j = 0; j != n; ++j) if (div->min_dist[j]) { - double dist = kc_distance(&hist[j].ka.k, &x) * dL; + double dist = kc_distance(hist[j].ka.k, x) * dL; if (dist < div->min_dither_dist[j]) div->min_dither_dist[j] = (uint32_t) dist; } @@ -350,7 +350,7 @@ colormap_diversity(kchist* kch, Gt_OutputData* od, int blend) colormap_diversity_do_blend(&div); for (nadapt = 0; nadapt != div.nchosen; ++nadapt) - gfcm->col[nadapt] = kc_togfcg(&kch->h[div.chosen[nadapt]].ka.k); + gfcm->col[nadapt] = kc_togfcg(kch->h[div.chosen[nadapt]].ka.k); gfcm->ncol = nadapt; kcdiversity_cleanup(&div); @@ -418,17 +418,21 @@ colormap_image_floyd_steinberg(Gif_Image *gfi, uint8_t *all_new_data, int dither_direction = 0; int transparent = gfi->transparent; int i, j, k; + kcolor *old_kc; wkcolor *err, *err1; /* Initialize distances; beware uninitialized colors */ assert(old_cm->capacity >= 256); + old_kc = Gif_NewArray(kcolor, old_cm->capacity); for (i = 0; i < old_cm->ncol; ++i) { Gif_Color* c = &old_cm->col[i]; - c->pixel = kd3_closest8g(kd3, c->gfc_red, c->gfc_green, c->gfc_blue); + old_kc[i] = kd3_makegfcg(kd3, c); + c->pixel = kd3_closest_transformed(kd3, old_kc[i], NULL); c->haspixel = 1; } for (i = old_cm->ncol; i < 256; ++i) { Gif_Color* c = &old_cm->col[i]; + old_kc[i] = kd3_makegfcg(kd3, c); c->pixel = 0; c->haspixel = 1; } @@ -485,10 +489,8 @@ colormap_image_floyd_steinberg(Gif_Image *gfi, uint8_t *all_new_data, goto next; /* find desired new color */ - kc_set8g(&use, old_cm->col[*data].gfc_red, old_cm->col[*data].gfc_green, - old_cm->col[*data].gfc_blue); - if (kd3->transform) - kd3->transform(&use); + use = old_kc[*data]; + /* use Floyd-Steinberg errors to adjust */ for (k = 0; k < 3; ++k) { int v = use.a[k] @@ -497,10 +499,10 @@ colormap_image_floyd_steinberg(Gif_Image *gfi, uint8_t *all_new_data, } e = old_cm->col[*data].pixel; - if (kc_distance(&kd3->ks[e], &use) < kd3->xradius[e]) + if (kc_distance(kd3->ks[e], use) < kd3->xradius[e]) *new_data = e; else - *new_data = kd3_closest_transformed(kd3, &use, NULL); + *new_data = kd3_closest_transformed(kd3, use, NULL); histogram[*new_data]++; /* calculate and propagate the error between desired and selected color. @@ -537,6 +539,7 @@ colormap_image_floyd_steinberg(Gif_Image *gfi, uint8_t *all_new_data, /* delete temporary storage */ Gif_DeleteArray(err); Gif_DeleteArray(err1); + Gif_DeleteArray(old_kc); } /* This function is a variant of the colormap_image_floyd_steinberg function @@ -549,17 +552,21 @@ colormap_image_atkinson(Gif_Image *gfi, uint8_t *all_new_data, static int32_t *random_values = 0; int transparent = gfi->transparent; int i, j, k; + kcolor *old_kc; wkcolor *err[3]; /* Initialize distances; beware uninitialized colors */ assert(old_cm->capacity >= 256); + old_kc = Gif_NewArray(kcolor, old_cm->capacity); for (i = 0; i < old_cm->ncol; ++i) { Gif_Color* c = &old_cm->col[i]; - c->pixel = kd3_closest8g(kd3, c->gfc_red, c->gfc_green, c->gfc_blue); + old_kc[i] = kd3_makegfcg(kd3, c); + c->pixel = kd3_closest_transformed(kd3, old_kc[i], NULL); c->haspixel = 1; } for (i = old_cm->ncol; i < 256; ++i) { Gif_Color* c = &old_cm->col[i]; + old_kc[i] = kd3_makegfcg(kd3, c); c->pixel = 0; c->haspixel = 1; } @@ -604,18 +611,17 @@ colormap_image_atkinson(Gif_Image *gfi, uint8_t *all_new_data, } /* Calculate desired new color including current error */ - kc_set8g(&use, old_cm->col[*data].gfc_red, old_cm->col[*data].gfc_green, - old_cm->col[*data].gfc_blue); + use = old_kc[*data]; for (k = 0; k < 3; ++k) use.a[k] = KC_CLAMPV(use.a[k] + err[0][x].a[k] / DITHER_SCALE); /* Find the closest color in the colormap */ e = old_cm->col[*data].pixel; - if (kc_distance(&kd3->ks[e], &use) < kd3->xradius[e]) + if (kc_distance(kd3->ks[e], use) < kd3->xradius[e]) *new_data = e; else - *new_data = kd3_closest_transformed(kd3, &use, NULL); + *new_data = kd3_closest_transformed(kd3, use, NULL); histogram[*new_data]++; /* Calculate and propagate the error using the Atkinson dithering @@ -643,11 +649,9 @@ colormap_image_atkinson(Gif_Image *gfi, uint8_t *all_new_data, /* Delete temporary storage */ for (i = 0; i < 3; i++) { - if (err[i]) { - Gif_DeleteArray(err[i]); - err[i] = NULL; - } + Gif_DeleteArray(err[i]); } + Gif_DeleteArray(old_kc); } typedef struct odselect_planitem { @@ -678,15 +682,15 @@ static int ordered_dither_plan_compare(const void* xa, const void* xb) { return *a - *b; } -static int kc_line_closest(const kcolor* p0, const kcolor* p1, - const kcolor* ref, double* t, unsigned* dist) { +static int kc_line_closest(kcolor p0, kcolor p1, kcolor ref, + double* t, unsigned* dist) { wkcolor p01, p0ref; kcolor online; unsigned den; int d; for (d = 0; d != 3; ++d) { - p01.a[d] = p1->a[d] - p0->a[d]; - p0ref.a[d] = ref->a[d] - p0->a[d]; + p01.a[d] = p1.a[d] - p0.a[d]; + p0ref.a[d] = ref.a[d] - p0.a[d]; } den = (unsigned) (p01.a[0]*p01.a[0] + p01.a[1]*p01.a[1] + p01.a[2]*p01.a[2]); @@ -701,15 +705,14 @@ static int kc_line_closest(const kcolor* p0, const kcolor* p1, if (*t < 0 || *t > 1) return 0; for (d = 0; d != 3; ++d) { - int v = (int) (p01.a[d] * *t) + p0->a[d]; + int v = (int) (p01.a[d] * *t) + p0.a[d]; online.a[d] = KC_CLAMPV(v); } - *dist = kc_distance(&online, ref); + *dist = kc_distance(online, ref); return 1; } -static int kc_plane_closest(const kcolor* p0, const kcolor* p1, - const kcolor* p2, const kcolor* ref, +static int kc_plane_closest(kcolor p0, kcolor p1, kcolor p2, kcolor ref, double* t, unsigned* dist) { wkcolor p0ref, p01, p02; double n[3], pvec[3], det, qvec[3], u, v; @@ -718,9 +721,9 @@ static int kc_plane_closest(const kcolor* p0, const kcolor* p1, /* Calculate the non-unit normal of the plane determined by the input colors (p0-p2) */ for (d = 0; d != 3; ++d) { - p0ref.a[d] = ref->a[d] - p0->a[d]; - p01.a[d] = p1->a[d] - p0->a[d]; - p02.a[d] = p2->a[d] - p0->a[d]; + p0ref.a[d] = ref.a[d] - p0.a[d]; + p01.a[d] = p1.a[d] - p0.a[d]; + p02.a[d] = p2.a[d] - p0.a[d]; } n[0] = p01.a[1]*p02.a[2] - p01.a[2]*p02.a[1]; n[1] = p01.a[2]*p02.a[0] - p01.a[0]*p02.a[2]; @@ -761,7 +764,7 @@ static int kc_plane_closest(const kcolor* p0, const kcolor* p1, } static void limit_ordered_dither_plan(uint8_t* plan, int nplan, int nc, - const kcolor* want, kd3_tree* kd3) { + kcolor want, kd3_tree* kd3) { unsigned mindist, dist; int ncp = 0, nbestcp = 0, i, j, k; double t[2]; @@ -784,7 +787,7 @@ static void limit_ordered_dither_plan(uint8_t* plan, int nplan, int nc, mindist = (unsigned) -1; for (i = 0; i != ncp; ++i) { /* check for closest single color */ - dist = kc_distance(&kd3->ks[cp[i].plan], want); + dist = kc_distance(kd3->ks[cp[i].plan], want); if (dist < mindist) { bestcp[0].plan = cp[i].plan; bestcp[0].frac = KC_WHOLE; @@ -794,8 +797,8 @@ static void limit_ordered_dither_plan(uint8_t* plan, int nplan, int nc, for (j = i + 1; nc >= 2 && j < ncp; ++j) { /* check for closest blend of two colors */ - if (kc_line_closest(&kd3->ks[cp[i].plan], - &kd3->ks[cp[j].plan], + if (kc_line_closest(kd3->ks[cp[i].plan], + kd3->ks[cp[j].plan], want, &t[0], &dist) && dist < mindist) { bestcp[0].plan = cp[i].plan; @@ -808,9 +811,9 @@ static void limit_ordered_dither_plan(uint8_t* plan, int nplan, int nc, for (k = j + 1; nc >= 3 && k < ncp; ++k) /* check for closest blend of three colors */ - if (kc_plane_closest(&kd3->ks[cp[i].plan], - &kd3->ks[cp[j].plan], - &kd3->ks[cp[k].plan], + if (kc_plane_closest(kd3->ks[cp[i].plan], + kd3->ks[cp[j].plan], + kd3->ks[cp[k].plan], want, &t[0], &dist) && dist < mindist) { bestcp[0].plan = cp[i].plan; @@ -834,9 +837,7 @@ static void set_ordered_dither_plan(uint8_t* plan, int nplan, int nc, wkcolor err; int i, d; - kc_set8g(&want, gfc->gfc_red, gfc->gfc_green, gfc->gfc_blue); - if (kd3->transform) - kd3->transform(&want); + want = kd3_makegfcg(kd3, gfc); wkc_clear(&err); for (i = 0; i != nplan; ++i) { @@ -844,7 +845,7 @@ static void set_ordered_dither_plan(uint8_t* plan, int nplan, int nc, int v = want.a[d] + err.a[d]; cur.a[d] = KC_CLAMPV(v); } - plan[i] = kd3_closest_transformed(kd3, &cur, NULL); + plan[i] = kd3_closest_transformed(kd3, cur, NULL); for (d = 0; d != 3; ++d) err.a[d] += want.a[d] - kd3->ks[plan[i]].a[d]; } @@ -856,7 +857,7 @@ static void set_ordered_dither_plan(uint8_t* plan, int nplan, int nc, for (i = 1; i != nplan; ++i) ncp += plan[i-1] != plan[i]; if (ncp > nc) - limit_ordered_dither_plan(plan, nplan, nc, &want, kd3); + limit_ordered_dither_plan(plan, nplan, nc, want, kd3); } gfc->haspixel = 1; @@ -910,7 +911,7 @@ static void colormap_image_ordered(Gif_Image* gfi, uint8_t* all_new_data, /* Initialize luminances, create luminance sorter */ ordered_dither_lum = Gif_NewArray(int, kd3->nitems); for (i = 0; i != kd3->nitems; ++i) - ordered_dither_lum[i] = kc_luminance(&kd3->ks[i]); + ordered_dither_lum[i] = kc_luminance(kd3->ks[i]); /* Do the image! */ if ((mw & (mw - 1)) == 0 && (mh & (mh - 1)) == 0 diff --git a/src/xform.c b/src/xform.c index 2f36364..06c2843 100644 --- a/src/xform.c +++ b/src/xform.c @@ -482,8 +482,7 @@ static void ksscreen_init(ksscreen* kss, Gif_Stream* gfs, int sw, int sh) { kss->data = Gif_NewArray(scale_color, sz); if ((gfs->nimages == 0 || gfs->images[0]->transparent < 0) && gfs->global && gfs->background < gfs->global->ncol) { - kcolor k = kc_makegfcg(&gfs->global->col[gfs->background]); - kss->bg = sc_makekc(&k); + kss->bg = sc_makekc(kc_makegfcg(&gfs->global->col[gfs->background])); } else sc_clear(&kss->bg); for (i = 0; i != sz; ++i) @@ -517,7 +516,7 @@ static void ksscreen_apply(ksscreen* kss, const Gif_Image* gfi, scale_color* lineout = &kss->data[y * kss->width + gfi->left]; for (x = 0; x != gfi->width; ++x) if (linein[x] != gfi->transparent) - lineout[x] = sc_makekc(&ks[linein[x]]); + lineout[x] = sc_makekc(ks[linein[x]]); } } @@ -726,7 +725,7 @@ static int scale_image_add_colors(scale_context* sctx, Gif_Image* gfo) { if (chosen >= kch.n || div.min_dist[chosen] <= sctx->max_desired_dist) break; kcdiversity_choose(&div, chosen, 0); - gfc = kc_togfcg(&kch.h[chosen].ka.k); + gfc = kc_togfcg(kch.h[chosen].ka.k); Gif_AddColor(gfcm, &gfc, gfcm->ncol); kd3_add8g(sctx->kd3, gfc.gfc_red, gfc.gfc_green, gfc.gfc_blue); ++nadded; @@ -752,10 +751,10 @@ static void scale_image_complete(scale_context* sctx, Gif_Image* gfo) { + gfo->left]; for (xo = 0; xo != gfo->width; ++xo) if (xscr[xo].a[3]) { - data[xo] = kd3_closest_transformed(sctx->kd3, &xscr[xo].k, &dist); + data[xo] = kd3_closest_transformed(sctx->kd3, xscr[xo].k, &dist); /* maybe previous color is actually closer to desired */ if (transparent >= 0 && oscr[xo].a[3]) { - dist2 = kc_distance(&oscr[xo].k, &xscr[xo].k); + dist2 = kc_distance(oscr[xo].k, xscr[xo].k); if (dist2 <= dist) { data[xo] = transparent; dist = dist2;