/* colors.c -------- */ #include #include /* for rand() */ #include #include #include #ifdef NEED_ALLOCA_H #include #endif #include "../tthimage.h" /*::------------------------------------------------------------------::*/ /* echange de deux composantes d'une image RGB what about swapping with the alpha channel ? */ int Image_swap_colors(Image_Desc *im, char *cols) { uint8_t *buffer; int y, code; #if DEBUG_LEVEL fprintf(stderr, "Echange de couleurs: [%s] %p\n", cols, im); #endif if (strlen(cols) != 2) { fprintf(stderr, "%s: bad control string: '%s'\n", __func__, cols); return INVALID_PARAM; } code = 0; switch (cols[0]) { case 'r': case 'R': code |= 0x10; break; case 'g': case 'G': code |= 0x20; break; case 'b': case 'B': code |= 0x30; break; default: fprintf(stderr, "SwapColors: bad first color '%c'\n", cols[0]); return INVALID_PARAM; } switch (cols[1]) { case 'r': case 'R': code |= 0x1; break; case 'g': case 'G': code |= 0x2; break; case 'b': case 'B': code |= 0x3; break; default: fprintf(stderr, "SwapColors: bad second color '%c'\n", cols[0]); return INVALID_PARAM; } if ( (buffer=(uint8_t *)alloca(im->width)) == NULL ) { fprintf(stderr, "%s: no mem for buffer\n", __func__); return BUFFER_NO_MEM; } #if DEBUG_LEVEL fprintf(stderr, "%s: code is %02x, buffer at %p\n", __func__, code, buffer); #endif for (y=0; yheight; y++) { switch (code) { case 0x12: case 0x21: memcpy(buffer, im->Rpix[y], im->width); memcpy(im->Rpix[y], im->Gpix[y], im->width); memcpy(im->Gpix[y], buffer, im->width); break; case 0x13: case 0x31: memcpy(buffer, im->Rpix[y], im->width); memcpy(im->Rpix[y], im->Bpix[y], im->width); memcpy(im->Bpix[y], buffer, im->width); break; case 0x23: case 0x32: memcpy(buffer, im->Bpix[y], im->width); memcpy(im->Bpix[y], im->Gpix[y], im->width); memcpy(im->Gpix[y], buffer, im->width); break; default: fprintf(stderr, "%s: code=%02x, Aie.\n", __func__, code); exit(1); } } im->modified = 1; return OLL_KORRECT; } /*::------------------------------------------------------------------::*/ /* cette func est cense donner une couleur RVB en fonction de deux parametre [0..1], mais c,a marche pas terrible, alors je vais faire encore des essais */ int Image_color_x(double v1, double v2, int *pr, int *pg, int *pb) { double s, c; s = sin(v1*M_PI) + 1.0; c = cos(v1*M_PI) + 1.0; *pr = (int) (s * 127.0); *pg = (int) (c * 127.0); *pb = (int) (v2 * 255.0); /* printf("%8f %8f %3d %3d %3d\n", v1, v2, *pr, *pg, *pb); */ return OLL_KORRECT; } /*::------------------------------------------------------------------::*/ /* * Calcul de la couleur moyenne sur l'ensemble d'une image * Il doit exister quelque part la meme fonction pour ce * calcul sur une zone rectangulaire d'une image. */ int Image_couleur_moyenne(Image_Desc *im, int *pr, int *pg, int *pb) { int x, y; long sr, sg, sb, surface; sr = sg = sb = 0L; for (y=0; yheight; y++) { for (x=0; xwidth; x++) { sr += im->Rpix[y][x]; sg += im->Gpix[y][x]; sb += im->Bpix[y][x]; } } surface = (long)im->width * (long)im->height; sr /= surface; sg /= surface; sb /= surface; #if DEBUG_LEVEL fprintf(stderr, "couleurs moyennes : r=%ld g=%ld b=%ld\n", sr, sg, sb); #endif *pr = (int)sr; *pg = (int)sg; *pb = (int)sb; return OLL_KORRECT; } /*::------------------------------------------------------------------::*/ /* * nouveau 28 juillet 2008 - avenue St Exupery */ int Image_saturate(Image_Desc *src, Image_Desc *dst, int sr, int sg, int sb) { int x, y, r, g, b; int foo; int minmax[6]; #if DEBUG_LEVEL fprintf(stderr, ">>> %s ( %p %p %d %d %d )", __func__, src, dst, sr, sg, sb); #endif if ( (foo=Image_compare_desc(src, dst)) ) { fprintf(stderr, "%s: images are differents %d\n", __func__, foo); return foo; } foo = Image_minmax_RGB(src, minmax); /* pourquoi faire ce truc ici ? */ #if DEBUG_LEVEL fprintf(stderr, " calcul minmax -> %d\n", foo); #endif for (y=0; yheight; y++) { for (x=0; xwidth; x++) { /* et il faut faire quoi, exactement ? */ r = src->Rpix[y][x]; g = src->Rpix[y][x]; b = src->Rpix[y][x]; /* je n'en ai pas la moindre ideee LOL */ } } return FUNC_IS_ALPHA; } /*::------------------------------------------------------------------::*/ /* * nouveau 12 mars 2009 - avenue St Exupery, avec du "Gros plant nantais" */ int Image_desaturate(Image_Desc *src, Image_Desc *dst, int sr, int sg, int sb) { int x, y, r, g, b; int foo; #if DEBUG_LEVEL fprintf(stderr, ">>> %s ( %p %p %d %d %d )", __func__, src, dst, sr, sg, sb); #endif if ( (foo=Image_compare_desc(src, dst)) ) { fprintf(stderr, "%s: images are differents %d\n", __func__, foo); return foo; } for (y=0; yheight; y++) { for (x=0; xwidth; x++) { r = src->Rpix[y][x]; g = src->Gpix[y][x]; b = src->Bpix[y][x]; if (r < sr) r = sr; if (g < sg) g = sg; if (b < sb) b = sb; if (r > 256-sr) r = (256-sr); if (g > 256-sg) g = (256-sg); if (b > 256-sb) b = (256-sb); src->Rpix[y][x] = r; src->Gpix[y][x] = g; src->Bpix[y][x] = b; } } return FUNC_IS_ALPHA; } /*::------------------------------------------------------------------::*/ /* Je ne sais plus d'ou sort cette formule, ni a quoi elle sert, ni comment faire le calcul inverse. */ int Image_RGB_2_HLS(int r, int g, int b, int *ph, int *pl, int *ps) { double C1, C2, S, L, H; C1 = sqrt(1.5) * (double)(r-g); C2 = b - 0.5 * (double)(r+g); S = sqrt((C1*C1) + (C2*C2)); L = (r+g+b) / 3.0; H = acos(C1/S); if (C2 < 0.0) H = (2*M_PI) - H; *ph = H; *ps = S; *pl = L; return OLL_KORRECT; } /*::------------------------------------------------------------------::*/ /* * nouveau 12Jun2001 * 16 Dec 2001: not fully tested, may be bogus :-( */ int Image_color_shift_rgb(Image_Desc *s, Image_Desc *d, int rs, int gs, int bs) { int x, y, r, g, b; int foo; if ( (foo=Image_compare_desc(s, d)) ) { fprintf(stderr, "%s: src & dst are differents (%d)\n", __func__, foo); return foo; } #if DEBUG_LEVEL fprintf(stderr, "Shift RGB: %d %d %d\n", rs, gs, bs); #endif for (y=0; yheight; y++) { for (x=0; xwidth; x++) { r = (s->Rpix[y][x] + rs) % 256; g = (s->Gpix[y][x] + gs) % 256; b = (s->Bpix[y][x] + bs) % 256; d->Rpix[y][x] = r; d->Gpix[y][x] = g; d->Bpix[y][x] = b; } } d->modified = 1; return FUNC_IS_ALPHA; } /*::------------------------------------------------------------------::*/ /* dans cette fonction, plein de trucs sont calcules en 'double float' mais est-ce bien necessaire ? * 16 Dec 2001: not fully tested, may be bogus :-( */ int Image_colors_recenter_0(Image_Desc *s, Image_Desc *d) { int x, y, r, g, b; int or, og, ob; double cr, cg, cb, surface; fprintf(stderr, "Image_colors_recenter_0 is a work in progress... ymmv.\n"); cr = cg = cb = 0.0; for (y=0; yheight; y++) { for (x=0; xwidth; x++) { Image_getRGB(s, x, y, &r, &g, &b); cr += (double)r; cg += (double)g; cb += (double)b; } } fprintf(stderr, "colors recenter 0: %g %g %g\n", cr, cg, cb); surface = (double)(s->width*s->height); fprintf(stderr, "colors recenter 0: surface image %g\n", surface); or = (int)(cr / surface); og = (int)(cg / surface); ob = (int)(cb / surface); or -= 127; og -= 127; ob -= 127; fprintf(stderr, "colors recenter 0: %d %d %d\n", or, og, ob); for (y=0; yheight; y++) { for (x=0; xwidth; x++) { Image_getRGB(s, x, y, &r, &g, &b); r = Image_clamp_pixel(r + or); g = Image_clamp_pixel(g + og); b = Image_clamp_pixel(b + ob); (d->Rpix[y])[x] = r; (d->Gpix[y])[x] = g; (d->Bpix[y])[x] = b; } } return FUNC_IS_ALPHA; } /*::------------------------------------------------------------------::*/ #define CUB(x) ((x)*(x)) /* * XXX manque des explications sur l'usage du parametre 'mode' */ int Image_colors_2_Map(Image_Desc *s, Image_Desc *d, RGB_map * map, int mode) { int foo, x, y, m; int sr, sg, sb, dr, dg, db; long mindist, pos, dist; if ( (foo=Image_compare_desc(s, d)) ) return foo; if ( map->nbre == 0 ) { fprintf(stderr, "%s: empty map at %p\n", __func__, map); /* * WTF ? we have an empty map ?!? * */ return EMPTY_COL_MAP; } #if DEBUG_LEVEL fprintf(stderr, "Colors 2 Map: %d couleurs dans la map\n", map->nbre); #endif pos = 0; /* XXX verifier a quoi c,a sert ?! */ for (y=0; yheight; y++) { for (x=0; xwidth; x++) { mindist = 99999999; sr = s->Rpix[y][x]; sg = s->Gpix[y][x]; sb = s->Bpix[y][x]; for (m=0; mnbre; m++) { switch (mode) { case 0: dist = CUB(sr-map->red[m]) + CUB(sg-map->green[m]) + CUB(sb-map->blue[m]); break; /* * There was probably a bug in this case... */ case 1: dr = abs(sr - map->red[m]); dg = abs(sg - map->green[m]); db = abs(sb - map->blue[m]); dist = dr; if (dg < dist) dist = dg; if (db < dist) dist = db; break; case 2: dr = abs(sr-map->red[m]); dg = abs(sg-map->green[m]); db = abs(sb-map->blue[m]); dist = dr + dg + db; break; case 11: dist = CUB(sr-map->red[m]); break; case 12: dist = CUB(sg-map->green[m]); break; case 13: dist = CUB(sb-map->blue[m]); break; default: fprintf(stderr, "Colors To Map: invalid mode %d\n", mode); return INVALID_PARAM; } if (dist < mindist) { pos = m; mindist = dist; } } (d->Rpix[y])[x] = map->red[pos]; (d->Gpix[y])[x] = map->green[pos]; (d->Bpix[y])[x] = map->blue[pos]; } #if DEBUG_LEVEL if ( ! (y % 42) ) fprintf(stderr, "remapping line %4d / %d\r", y, s->height); #endif } d->modified = 1; return OLL_KORRECT; } /*::------------------------------------------------------------------::*/ /* ces coeffs viennent de Povray (a verifier) */ #define R_COEF 297 #define G_COEF 589 #define B_COEF 114 #define RGB_DIV (R_COEF+G_COEF+B_COEF) int Image_to_gray_k(Image_Desc *s, Image_Desc *d, int kr, int kg, int kb, int flag) { int x, y, r, g, b, v, foo; int grey, diviseur; int vmax; #if DEBUG_LEVEL fprintf(stderr, "converting image %p to gray in %p, flag %d\n", s, d, flag); #endif if ( (foo=Image_compare_desc(s, d)) ) { fprintf(stderr, "To Gray: src & dst are differents (%d)\n", foo); return foo; } diviseur = kr + kg + kb; #if DEBUG_LEVEL fprintf(stderr, "to Gray K: %d %d %d %d\n", kr, kg, kb, diviseur); #endif #if DEBUG_LEVEL > 1 if (flag==1) { fprintf(stderr, "%s: %d %d %d -> %d\n", __func__, kr, kg, kb, diviseur); } #endif if (diviseur==0) { fprintf(stderr, "%s: divisor is 0\n", __func__); return DIVISOR_IS_ZERO; } vmax = 0; for (y=0; yheight; y++) { for (x=0; xwidth; x++) { r = s->Rpix[y][x]; g = s->Gpix[y][x]; b = s->Bpix[y][x]; grey = (r * kr) + (g * kg) + (b * kb); v = grey / diviseur; if (v > vmax) vmax=v; d->Rpix[y][x] = v; d->Gpix[y][x] = v; d->Bpix[y][x] = v; } } #if DEBUG_LEVEL > 1 if (flag==1) { fprintf(stderr, "%s: max value is %d\n", __func__, vmax); } #endif d->modified = 1; return OLL_KORRECT; } /*::------------------------------------------------------------------::*/ /* what are the three magic constants *_COEF ? */ int Image_to_gray(Image_Desc *s, Image_Desc *d, int flag) { int foo; #if DEBUG_LEVEL > 1 fprintf(stderr, "Image to gray: flag is %d\n", flag); #endif if (flag) foo=Image_to_gray_k(s, d, 100, 100, 100, flag); else foo=Image_to_gray_k(s, d, R_COEF, G_COEF, B_COEF, flag); return foo; } /*::------------------------------------------------------------------::*/ /* 8 Jan 2001 * * et on fait quoi si il y a pas assez de couleurs dans la MAP ? * ben, on patche ? */ int Image_apply_Map(Image_Desc *src, Image_Desc *dst, RGB_map *map) { int x, y, r, g, b; #if DEBUG_LEVEL fprintf(stderr, ">>> %s ( %p %p %p )\n", __func__, src, dst, map); #endif if (map->nbre == 0) { fprintf(stderr, "%s: no colors in palette ?\n", __func__); return EMPTY_COL_MAP; } if (map->nbre < 255) { fprintf(stderr, "%s: only %d cols in palette\n", __func__, map->nbre); } for (y=0; yheight; y++) { for (x=0; xwidth; x++) { r = (src->Rpix[y])[x]; g = (src->Gpix[y])[x]; b = (src->Bpix[y])[x]; r = map->red[r]; g = map->green[g]; b = map->blue[b]; (dst->Rpix[y])[x] = r; (dst->Gpix[y])[x] = g; (dst->Bpix[y])[x] = b; } } dst->modified = 1; return OLL_KORRECT; } /*::------------------------------------------------------------------::*/ /* 8 May 2001 et on fait quoi si il y a pas assez de couleurs dans la MAP ? */ int Image_gray_Map(Image_Desc *src, Image_Desc *dst, RGB_map *map) { int x, y, r, g, b, gray; if (map->nbre == 0) { fprintf(stderr, "%s: no colors in palette ?\n", __func__); return VERY_STRANGE; } if (map->nbre < 255) { fprintf(stderr, "%s: only %d cols in palette\n", __func__, map->nbre); } for (y=0; yheight; y++) { for (x=0; xwidth; x++) { r = (src->Rpix[y])[x]; g = (src->Gpix[y])[x]; b = (src->Bpix[y])[x]; gray = ((r * R_COEF) + (g * G_COEF) + (b * B_COEF)) / RGB_DIV; if (gray<0 || gray>255) { fprintf(stderr, "%s: GRAY---- %d\n", __func__, gray); exit(5); } r = map->red[gray]; g = map->green[gray]; b = map->blue[gray]; (dst->Rpix[y])[x] = r; (dst->Gpix[y])[x] = g; (dst->Bpix[y])[x] = b; } } dst->modified = 1; return OLL_KORRECT; } /*::------------------------------------------------------------------::*/ /* new 10 janvier 2009 - avenue St Exupery */ static int parse_3_ints(char *str, int ints[]) { char *cptr, sep[] = " \t,"; int idx; #if DEBUG_LEVEL fprintf(stderr, ">>> %s ( %p %p )\n", __func__, str, ints); #endif idx = 0; cptr = strtok(str, sep); while (NULL != cptr) { #if DEBUG_LEVEL fprintf(stderr, "%3d %p -> %s\n", idx, cptr, cptr); #endif ints[idx] = atoi(cptr); cptr = strtok(NULL, sep); if (3 == idx) break; idx ++; } return 0; } int Image_default_RGBA(RGBA *ptr, char *texte, int flags) { char *envptr; int foo; int values[4]; #if DEBUG_LEVEL fprintf(stderr, ">>> %s ( %p '%s' 0x%x )\n", __func__, ptr, texte, flags); #endif if ( NULL != (envptr=getenv(ENV_DEFAULT_RGBA)) ) { #if DEBUG_LEVEL fprintf(stderr, "default rgb = '%s'\n", envptr); #endif /* got the env var, parse it now */ foo = parse_3_ints(envptr, values); ptr->r = values[0]; ptr->g = values[1]; ptr->b = values[2]; ptr->a = values[3]; /* wtf ? */ } else { fprintf(stderr, "no '%s' env var defined\n", ENV_DEFAULT_RGBA); ptr->r = ptr->g = ptr->b = ptr->a = 142; } /* quick and dirties default values */ ptr->reserved = 0x42516988; ptr->reserved2 = time(NULL); return FUNC_IS_BETA; } /*::------------------------------------------------------------------::*/