libtthimage/Lib/colors.c

649 lines
15 KiB
C

/*
colors.c
--------
*/
#include <stdio.h>
#include <stdlib.h> /* for rand() */
#include <time.h>
#include <string.h>
#include <math.h>
#ifdef NEED_ALLOCA_H
#include <alloca.h>
#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; y<im->height; 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; y<im->height; y++) {
for (x=0; x<im->width; 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; y<src->height; y++) {
for (x=0; x<src->width; 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; y<src->height; y++) {
for (x=0; x<src->width; 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; y<s->height; y++) {
for (x=0; x<s->width; 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; y<s->height; y++) {
for (x=0; x<s->width; 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; y<s->height; y++) {
for (x=0; x<s->width; 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; y<s->height; y++) {
for (x=0; x<s->width; x++) {
mindist = 99999999;
sr = s->Rpix[y][x];
sg = s->Gpix[y][x];
sb = s->Bpix[y][x];
for (m=0; m<map->nbre; 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; y<s->height; y++) {
for (x=0; x<s->width; 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; y<src->height; y++) {
for (x=0; x<src->width; 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; y<src->height; y++) {
for (x=0; x<src->width; 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;
}
/*::------------------------------------------------------------------::*/