/* Operations diverses sur les images ---------------------------------- 25 Aout 1999: certaines fonctions utilisent 'alloca'. 4 Fevrier 2001: je me rend compte que certaines interfaces sont trop simplistes, et que définir des structures contenant de multiples paramètres ne serait peut-être pas une mauvaise idée... 16 Oct 2001: je deplace quelques fonctions dans d'autres modules. */ #include #include #include #ifdef NEED_ALLOCA_H #include #endif #include "../tthimage.h" /*::------------------------------------------------------------------::*/ /* * XXX il y a un "Zero Divide" cache dans cette fonction ! */ int Image_adjust_minmax_0(Image_Desc *src, Image_Desc *dst, int yo, int minstone, int maxstone) { long histR[256], histG[256], histB[256]; long surface; int foo; long mini, maxi, kmini, kmaxi, delta; int idxmini, idxmaxi, val, lut[256], level; if (yo != 0) { fprintf(stderr, "Yo is %d\n", yo); } Image_histo_RGB(src, histR, histG, histB); surface = (src->width * src->height); kmini = (minstone * surface) / 100; kmaxi = (maxstone * surface) / 100; #if DEBUG_LEVEL fprintf(stderr, "adjust minmax:\n"); fprintf(stderr, " minstone= %d\n", minstone); fprintf(stderr, " maxstone= %d\n", maxstone); fprintf(stderr, " surface = %ld\n", surface); fprintf(stderr, " K mini = %ld\n", kmini); fprintf(stderr, " K maxi = %ld\n", kmaxi); #endif mini = 0; idxmini = 0; for (foo=0; foo<256; foo++) { mini += (histR[foo] + histG[foo] + histB[foo]); if (mini > kmini) { fprintf(stderr, "MINI %3d %ld\n", foo, mini); idxmini = foo; break; } } maxi = 0; idxmaxi = 255; for (foo=255; foo>=0; foo--) { maxi += (histR[foo] + histG[foo] + histB[foo]); if (maxi > kmaxi) { fprintf(stderr, "MAXI %3d %ld\n", foo, maxi); idxmaxi = foo; break; } } delta = idxmaxi - idxmini; fprintf(stderr, "idxmini=%d idxmaxi=%d delta=%ld\n", idxmini, idxmaxi, delta); for (foo=0; foomodified = 1; return FUNC_IS_BETA; } /*::------------------------------------------------------------------::*/ /* * et une fonction de plus ecrite a la rache, avec un nom qui * ne veut probablement rien dire :) */ int Image_luminance(Image_Desc *src, Image_Desc *dst, int factor) { int foo; int x, y; #if DEBUG_LEVEL > 1 fprintf(stderr, "%s ( %p %p %d )\n", __func__, src, dst, factor); #endif fprintf(stderr, "luminance factor: %d %f\n", factor, (float)factor / 256.0); if ( (foo=Image_compare_desc(src, dst)) ) { fprintf(stderr, "Image Luminance: images are differents %d\n", foo); return foo; } for (y=0; yheight; y++) { for (x=0; xwidth; x++) { dst->Rpix[y][x] = (src->Rpix[y][x] * factor) / 256; dst->Gpix[y][x] = (src->Gpix[y][x] * factor) / 256; dst->Bpix[y][x] = (src->Bpix[y][x] * factor) / 256; } } dst->modified = 1; return FUNC_IS_BETA; } /* * p'taing, c'est tellement crade qu'il faut: * 1) retrouver d'ou ça vient * 2) la virer illico !... */ /*::------------------------------------------------------------------::*/ /* ** ne fonctionne que sur les images en RGB, pour le moment. 16 jan 2003: il faudrait faire quelque chose pour les images avec un canal Alpha. + + + + + + + + + + + + + + + + + + + + + + + + + + + + le parametre 'yoyo' n'est pas utilise actuellement. */ int Image_egalise_RGB(Image_Desc *src, Image_Desc *dst, int yoyo) { int foo; long *histr, *histg, *histb; int *cumlr, *cumlg, *cumlb; long cr, cg, cb, s; if (yoyo != 0) { fprintf(stderr, "%s: yoyo is %d\n", __func__, yoyo); } if ( (foo=Image_compare_desc(src, dst)) ) { fprintf(stderr, "Image Egalise RGB: images are differents %d\n", foo); return foo; } /* yup, en 2009, il faudrait pas remplacer tout ces 'alloca' par de * la bonne 'kiss' variable automatique ? */ if((histr=(long *)alloca(256*sizeof(long))) == NULL) return BUFFER_NO_MEM; if((histg=(long *)alloca(256*sizeof(long))) == NULL) return BUFFER_NO_MEM; if((histb=(long *)alloca(256*sizeof(long))) == NULL) return BUFFER_NO_MEM; if((cumlr=(int *)alloca(256*sizeof(int))) == NULL) return BUFFER_NO_MEM; if((cumlg=(int *)alloca(256*sizeof(int))) == NULL) return BUFFER_NO_MEM; if((cumlb=(int *)alloca(256*sizeof(int))) == NULL) return BUFFER_NO_MEM; Image_histo_RGB(src, histr, histg, histb); cr = cg = cb = 0L; s = (src->width * src->height); #if DEBUG_LEVEL fprintf(stderr, "Image Egalise 0: surface = %ld\n", s); #endif for (foo=0; foo<256; foo++) { cr += histr[foo]; cumlr[foo] = (int)((cr*255)/s); cg += histg[foo]; cumlg[foo] = (int)((cg*255)/s); cb += histb[foo]; cumlb[foo] = (int)((cb*255)/s); } #if DEBUG_LEVEL > 1 fprintf(stderr, "* histo RGB: cumuls: %d %d %d surface: %ld\n", cumlr[255], cumlg[255], cumlb[255], s); for (foo=0; foo<256; foo++) { fprintf(stderr, "%3d | %7ld %7ld %7ld | %7d %7d %7d\n", foo, histr[foo], histg[foo], histb[foo], cumlr[foo], cumlg[foo], cumlb[foo]); } #endif Image_LUT_RGB(src, dst, cumlr, cumlg, cumlb); dst->modified = 1; return 0; } /*::------------------------------------------------------------------::*/ /* cette fonction doit absolument etre re-ecrite pour optimiser l'occupation de la memoire. et il faudrait aussi explique ce qu'elle fait :) le parametre 'yoyo' n'est pas utilise actuellement. */ int Image_egalise_mono_0(Image_Desc *src, Image_Desc *dst, int yoyo) { int foo; long c, cc, s3; long *histr, *histg, *histb; int cumul[256]; if ( (foo=Image_compare_desc(src, dst)) ) { fprintf(stderr, "Image_Egalise_Mono_0: images are differents %d\n", foo); return foo; } if (yoyo != 0) fprintf(stderr, "%s : yoyo must be 0\n", __func__); if((histr=(long *)alloca(256*sizeof(long))) == NULL) return BUFFER_NO_MEM; if((histg=(long *)alloca(256*sizeof(long))) == NULL) return BUFFER_NO_MEM; if((histb=(long *)alloca(256*sizeof(long))) == NULL) return BUFFER_NO_MEM; Image_histo_RGB(src, histr, histg, histb); /* * diviseur en fonction de la surface */ s3 = (3 * src->width * src->height); cc = 0L; for (foo=0; foo<256; foo++) { c = histr[foo] + histg[foo] + histb[foo]; cc += c; cumul[foo] = (int)((cc*255) / s3); } Image_LUT_mono(src, dst, cumul); dst->modified = 1; return 0; } /*::------------------------------------------------------------------::*/ /* complement d'une image complete (c.a.d tous les canaux contenus dans cette image) */ int Image_negate(Image_Desc *image, Image_Desc *resultat) { int x, y; if (image->type == 3) { for (y=0; yheight; y++) { for (x=0; xwidth; x++) { resultat->Rpix[y][x] = image->Rpix[y][x] ^ 0xff; resultat->Gpix[y][x] = image->Gpix[y][x] ^ 0xff; resultat->Bpix[y][x] = image->Bpix[y][x] ^ 0xff; } } return 0; } fprintf(stderr, "Image Negate: unknow image type %d, %s\n", image->type, Image_type2str(image->type)); return IMAGE_BAD_TYPE; } /*::------------------------------------------------------------------::*/ int Image_and_pix( Image_Desc *image, uint8_t ar, uint8_t ag, uint8_t ab ) { int x, y; if (image->type == 3) { for (y=0; yheight; y++) { for (x=0; xwidth; x++) { image->Rpix[y][x] &= ar; image->Gpix[y][x] &= ag; image->Bpix[y][x] &= ab; } } return 0; } fprintf(stderr, "Image And Pix: unknow image type %d\n", image->type); return IMAGE_BAD_TYPE; } /*::------------------------------------------------------------------::*/ int Image_or_pix( Image_Desc *image, int ar, int ag, int ab ) { int x, y; if (image->type == 3) { for (y=0; yheight; y++) { for (x=0; xwidth; x++) { image->Rpix[y][x] |= (ar & 0xff); image->Gpix[y][x] |= (ag & 0xff); image->Bpix[y][x] |= (ab & 0xff); } } return 0; } fprintf(stderr, "Image_OrPix: unknow image type %d\n", image->type); return IMAGE_BAD_TYPE; } /*::------------------------------------------------------------------::*/ /* new 11 octobre 2001 */ int Image_clear_component(Image_Desc *img, char component, int value) { int x, y; if (img->type != 3) { fprintf(stderr, "Clear Component: only type 3 img\n"); return IMAGE_BAD_TYPE; } for (y=0; yheight; y++) { for (x=0; xwidth; x++) { switch (component) { case 'r': case 'R': (img->Rpix[y])[x] = value; break; case 'g': case 'G': (img->Gpix[y])[x] = value; break; case 'b': case 'B': (img->Bpix[y])[x] = value; break; } } } img->modified = 1; return 0; } /*::------------------------------------------------------------------::*/ /* * cette func recopie les pixels de la source dont une composante RGB * est superieure aux seuils dans l'image de destination * * 1er Fev 2000: ya quelque chose a faire avec la transparence ? */ int Image_copie_seuil(Image_Desc *s, Image_Desc *d, int sr, int sg, int sb) { int x, y, r, g, b; for (y=0; yheight; y++) { for (x=0; xwidth; x++) { r = Image_R_pixel(s, x, y); g = Image_G_pixel(s, x, y); b = Image_B_pixel(s, x, y); if (r>sr || g>sg || b>sb) Image_plotRGB(d, x, y, r, g, b); } } d->modified = 0; /* 2001-02-08 */ return 0; } /*::------------------------------------------------------------------::*/ /* * pourquoi il n'y a pas de test de debordement ? * ce truc ne marche pas bien si il y a de l'Alpha */ int Image_overlay(Image_Desc *s, Image_Desc *d, int xpos, int ypos) { int x, y, r, g, b; int xd, yd; #if DEBUG_LEVEL fprintf(stderr, "%s ( %p on %p at %d,%d )\n", __func__, s, d, xpos, ypos); #endif for (y=0; yheight; y++) { yd = y+ypos; for (x=0; xwidth; x++) { xd = x+xpos; if ( (xd>=0) && (xdwidth-1) && (yd>=0) && (ydheight-1) ) { r = (s->Rpix[y])[x]; g = (s->Gpix[y])[x]; b = (s->Bpix[y])[x]; Image_plotRGB(d, xd, yd, r, g, b); } } } d->modified = 1; /* 2001-02-08 */ return 0; } /*::------------------------------------------------------------------::*/ int Image_overlay_mix(Image_Desc *s, Image_Desc *d, int xpos, int ypos, int k) { int x, y, sr, sg, sb; int xd, yd; #if DEBUG_LEVEL < 10 fprintf(stderr, "%s ( %p on %p at %d,%d )\n", __func__, s, d, xpos, ypos); fprintf(stderr, " coef = %d\n", k); #endif for (y=0; yheight; y++) { yd = y+ypos; for (x=0; xwidth; x++) { xd = x+xpos; if ( (xd>=0) && (xdwidth-1) && (yd>=0) && (ydheight-1) ) { sr = (s->Rpix[y])[x]; sg = (s->Gpix[y])[x]; sb = (s->Bpix[y])[x]; Image_plotRGB(d, xd, yd, sr, sg, sb); } } } d->modified = 1; /* 2001-02-08 */ return 0; } /*::------------------------------------------------------------------::*/ /* ce truc sert a quoi ? */ static uint16_t rotate_left(uint16_t byte) { byte = byte << 1; if (byte & 0x100) byte |= 1; else byte &= 0xfe; return (byte & 0xff); } static uint16_t rotate_right(uint16_t byte) { uint16_t lowbit = byte & 1; byte = byte >> 1; if (lowbit) byte |= 0x80; else byte &= 0x7f; return (byte & 0xff); } int Image_operator(Image_Desc *in, char op, int val, Image_Desc *out) { int x, y; int retval; if ( (in->type != 3) || (out->type != 3) ) { fprintf(stderr, "Image operator: bad type of image\n"); return IMAGE_BAD_TYPE; } retval = 0; for (y=0; yheight; y++) { for (x=0; xwidth; x++) { switch(op) { case '+': out->Rpix[y][x] = in->Rpix[y][x] + val; out->Gpix[y][x] = in->Gpix[y][x] + val; out->Bpix[y][x] = in->Bpix[y][x] + val; break; case '/': out->Rpix[y][x] = in->Rpix[y][x] / val; out->Gpix[y][x] = in->Gpix[y][x] / val; out->Bpix[y][x] = in->Bpix[y][x] / val; break; case '&': case 'A': out->Rpix[y][x] = in->Rpix[y][x] & val; out->Gpix[y][x] = in->Gpix[y][x] & val; out->Bpix[y][x] = in->Bpix[y][x] & val; break; case '|': case 'O': out->Rpix[y][x] = in->Rpix[y][x] | val; out->Gpix[y][x] = in->Gpix[y][x] | val; out->Bpix[y][x] = in->Bpix[y][x] | val; break; case '^': out->Rpix[y][x] = in->Rpix[y][x] ^ val; out->Gpix[y][x] = in->Gpix[y][x] ^ val; out->Bpix[y][x] = in->Bpix[y][x] ^ val; break; case '*': out->Rpix[y][x] = in->Rpix[y][x] * val; out->Gpix[y][x] = in->Gpix[y][x] * val; out->Bpix[y][x] = in->Bpix[y][x] * val; break; case '<': out->Rpix[y][x] = rotate_left(in->Rpix[y][x]); out->Gpix[y][x] = rotate_left(in->Gpix[y][x]); out->Bpix[y][x] = rotate_left(in->Bpix[y][x]); break; case '>': out->Rpix[y][x] = rotate_right(in->Rpix[y][x]); out->Gpix[y][x] = rotate_right(in->Gpix[y][x]); out->Bpix[y][x] = rotate_right(in->Bpix[y][x]); break; default: out->Rpix[y][x] = in->Rpix[y][x]; out->Gpix[y][x] = in->Gpix[y][x]; out->Bpix[y][x] = in->Bpix[y][x]; retval = 1; break; } } } out->modified = 1; /* 2001-09-28 */ return retval; } /*::------------------------------------------------------------------::*/ int Image_seuil_RGB(Image_Desc *s, Image_Desc *d, int r, int g, int b) { int foo, x, y; if ( (s->type != 3) || (d->type != 3) ) { fprintf(stderr, "Image Seuil RGB: an image is not of type 3\n"); return IMAGE_BAD_TYPE; } if ( (foo=Image_compare_desc(s, d)) != 0 ) { fprintf(stderr, "Image Seuil RGB: images are differents %d\n", foo); return foo; } for (y=0; yheight; y++) { for (x=0; xwidth; x++) { if(s->Rpix[y][x] > r) d->Rpix[y][x] = 255; else d->Rpix[y][x] = 0; if(s->Gpix[y][x] > g) d->Gpix[y][x] = 255; else d->Gpix[y][x] = 0; if(s->Bpix[y][x] > b) d->Bpix[y][x] = 255; else d->Bpix[y][x] = 0; } } d->modified = 1; /* 2001-02-08 */ return OLL_KORRECT; } /*::------------------------------------------------------------------::*/ /* XXX a tester et a documenter XXX */ int Image_AutoSeuilRGB(Image_Desc *s, Image_Desc *d) { int foo, sr, sg, sb; long *histr, *histg, *histb; long surf2, cr, cg, cb; if((histr=(long *)alloca(256*sizeof(long))) == NULL) return BUFFER_NO_MEM; if((histg=(long *)alloca(256*sizeof(long))) == NULL) return BUFFER_NO_MEM; if((histb=(long *)alloca(256*sizeof(long))) == NULL) return BUFFER_NO_MEM; foo = Image_histo_RGB(s, histr, histg, histb); #if DEBUG_LEVEL fprintf(stderr, "in %s histo_RGB -> %d\n", __func__, foo); #endif sr = sg = sb = 0; cr = cg = cb = 0L; surf2 = (s->width*s->height)/2; #if DEBUG_LEVEL fprintf(stderr, "Auto Seuil RGB sur %p - surf2 = %ld\n", s, surf2); #endif for (foo=0; foo<256; foo++) { cr += histr[foo]; if (cr < surf2) sr = foo; cg += histg[foo]; if (cg < surf2) sg = foo; cb += histb[foo]; if (cb < surf2) sb = foo; } #if DEBUG_LEVEL fprintf(stderr, "Auto Seuil RGB sur %p - seuils calcules: %d %d %d\n", s, sr, sg, sb); #endif foo = Image_seuil_RGB(s, d, sr, sg, sb); /* FIXME : this function need a test framework */ return foo; } /*::------------------------------------------------------------------::*/ /*::------------------------------------------------------------------::*/