libtthimage/Lib/operat.c
2022-06-26 12:22:12 +02:00

689 lines
17 KiB
C

/*
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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef NEED_ALLOCA_H
#include <alloca.h>
#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; foo<idxmini; foo++) lut[foo] = 0;
level = 0;
for (foo=idxmini; foo<=idxmaxi; foo++)
{
val = (level*255) / delta;
lut[foo] = val;
level++;
}
for (foo=idxmaxi; foo<256; foo++) lut[foo] = 255;
/**
for (foo=0; foo<256; foo++)
fprintf(stderr, "%d\t%d\n", foo, lut[foo]);
**/
foo = Image_LUT_mono(src, dst, lut);
dst->modified = 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
if ( (foo=Image_compare_desc(src, dst)) ) {
fprintf(stderr, "Image Luminance: images are differents %d\n", foo);
return foo;
}
for (y=0; y<src->height; y++)
{
for (x=0; x<src->width; 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;
}
/*::------------------------------------------------------------------::*/
/*
cette fonction ne marche que si les deux images
sont allouees et de meme dimensions.
*/
int
Image_copy(Image_Desc *src, Image_Desc *dst)
{
int foo;
if ( (foo=Image_compare_desc(src, dst)) )
{
fprintf(stderr, "Image_Copy: images are differents %d\n", foo);
return foo;
}
for (foo=0; foo<src->height; foo++)
{
memcpy(dst->Rpix[foo], src->Rpix[foo], src->width);
memcpy(dst->Gpix[foo], src->Gpix[foo], src->width);
memcpy(dst->Bpix[foo], src->Bpix[foo], src->width);
if (dst->Apix!=NULL && src->Apix!=NULL)
memcpy(dst->Apix[foo], src->Apix[foo], src->width);
}
dst->modified = 1;
/*
>> 18 Juin 2002
>> ============
>> bon, maintenant se pose un grand problème philosophique.
>> on vient juste de copier les octets qui incarnent les pixels
>> rgb et peut-être alpha. Mais ce n'est que la partie évident
>> d'une image: ses pixels.
*/
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; y<image->height; y++)
{
for (x=0; x<image->width; 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; y<image->height; y++)
{
for (x=0; x<image->width; 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; y<image->height; y++)
{
for (x=0; x<image->width; 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; y<img->height; y++)
{
for (x=0; x<img->width; 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; y<s->height; y++)
{
for (x=0; x<s->width; 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; y<s->height; y++)
{
yd = y+ypos;
for (x=0; x<s->width; x++)
{
xd = x+xpos;
if ( (xd>=0) && (xd<d->width-1) && (yd>=0) && (yd<d->height-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; y<s->height; y++)
{
yd = y+ypos;
for (x=0; x<s->width; x++)
{
xd = x+xpos;
if ( (xd>=0) && (xd<d->width-1) && (yd>=0) && (yd<d->height-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; y<in->height; y++)
{
for (x=0; x<in->width; 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; y<s->height; y++)
{
for (x=0; x<s->width; 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;
}
/*::------------------------------------------------------------------::*/
/*::------------------------------------------------------------------::*/