pike.git / src / modules / Image / layers.c

version» Context lines:

pike.git/src/modules/Image/layers.c:1:   /*   **! module Image   **! note - **! $Id: layers.c,v 1.7 1999/04/23 01:20:38 mirar Exp $ + **! $Id: layers.c,v 1.8 1999/04/23 15:50:04 mirar Exp $   **! class Layer   */      #include "global.h"   #include <config.h>      #include <math.h> /* floor */    - RCSID("$Id: layers.c,v 1.7 1999/04/23 01:20:38 mirar Exp $"); + RCSID("$Id: layers.c,v 1.8 1999/04/23 15:50:04 mirar Exp $");      #include "config.h"      #include "stralloc.h"   #include "pike_macros.h"   #include "object.h"   #include "constants.h"   #include "interpret.h"   #include "svalue.h"   #include "array.h"
pike.git/src/modules/Image/layers.c:93:      LMFUNC(lm_normal);   LMFUNC(lm_add);   LMFUNC(lm_subtract);   LMFUNC(lm_multiply);   LMFUNC(lm_divide);   LMFUNC(lm_modulo);   LMFUNC(lm_invsubtract);   LMFUNC(lm_invdivide);   LMFUNC(lm_invmodulo); + LMFUNC(lm_difference); + LMFUNC(lm_min); + LMFUNC(lm_max); + LMFUNC(lm_bitwise_and); + LMFUNC(lm_bitwise_or); + LMFUNC(lm_bitwise_xor);      LMFUNC(lm_dissolve);      LMFUNC(lm_replace);   LMFUNC(lm_red);   LMFUNC(lm_green);   LMFUNC(lm_blue);      LMFUNC(lm_replace_hsv);   LMFUNC(lm_hue);   LMFUNC(lm_saturation);   LMFUNC(lm_value);   LMFUNC(lm_color);      LMFUNC(lm_behind); - LMFUNC(lm_screen); - LMFUNC(lm_overlay); +    LMFUNC(lm_difference);   LMFUNC(lm_darken);   LMFUNC(lm_lighten);   LMFUNC(lm_hue);   LMFUNC(lm_saturation);   LMFUNC(lm_color);   LMFUNC(lm_value);   LMFUNC(lm_erase);      struct layer_mode_desc
pike.git/src/modules/Image/layers.c:136:   {    {"normal", lm_normal, 1, NULL },    {"add", lm_add, 1, NULL },    {"subtract", lm_subtract, 1, NULL },    {"multiply", lm_multiply, 1, NULL },    {"divide", lm_divide, 1, NULL },    {"modulo", lm_modulo, 1, NULL },    {"invsubtract", lm_invsubtract, 1, NULL },    {"invdivide", lm_invdivide, 1, NULL },    {"invmodulo", lm_invmodulo, 1, NULL }, +  {"difference", lm_difference, 1, NULL }, +  {"max", lm_max, 1, NULL }, +  {"min", lm_min, 1, NULL }, +  {"bitwize_and", lm_bitwise_and, 1, NULL }, +  {"bitwize_or", lm_bitwise_or, 1, NULL }, +  {"bitwize_xor", lm_bitwise_xor, 1, NULL },    -  {"dissolve", lm_dissolve, 1, NULL }, -  +     {"replace", lm_replace, 1, NULL },    {"red", lm_red, 1, NULL },    {"green", lm_green, 1, NULL },    {"blue", lm_blue, 1, NULL },       {"replace_hsv", lm_replace_hsv, 1, NULL },    {"hue", lm_hue, 1, NULL },    {"saturation", lm_saturation, 1, NULL },    {"value", lm_value, 1, NULL },    {"color", lm_color, 1, NULL }, /* h+s */    - /* {"behind", lm_behind, 1, NULL }, */ +  {"darken", lm_darken, 1, NULL }, +  {"lighten", lm_lighten, 1, NULL }, +  +  {"dissolve", lm_dissolve, 1, NULL }, +  {"behind", lm_behind, 1, NULL }, +  {"erase", lm_erase, 1, NULL }, +    /* {"screen", lm_screen, 1, NULL }, */   /* {"overlay", lm_overlay, 1, NULL }, */ - /* {"difference", lm_difference, 1, NULL }, */ - /* {"darken", lm_darken, 1, NULL }, */ - /* {"lighten", lm_lighten, 1, NULL }, */ - /* {"erase", lm_erase, 1, NULL }, */ - /* {"replace", lm_replace, 1, NULL }, */ +    } ;      #define LAYER_MODES ((int)NELEM(layer_mode))      /*      Px=pixel, Ax=alpha [0-1], Rx,Gx,Bx, Hx,Sx,Vx = kanaler   Xs=källbild   Xl=aktuellt lager   Xd=målbild      normal Pd=(Pl*Al+Ps*(1-Al)*As)/(Al+(1-Al)*As)    Ad=(Al+(1-Al)*As)    - add Pd=Pl*Al+Ps*As -  Ad=(Al+(1-Al)*As) + operand layers: +  (Ad=(Al+(1-Al)*As))    - subtract Pd=Ps-Pl*Al -  Ad=(Al+(1-Al)*As) -  + add Pd=Pl+Ps + subtract Pd=Ps-Pl   multiply Pd=Ps*Pl -  Ad=(Al+(1-Al)*As) -  +    divide Pd=Ps/Pl -  Ad=(Al+(1-Al)*As) -  +    invmodulo Pd=Ps%Pl (measured in color values) -  Ad=(Al+(1-Al)*As) -  +    invsubtract Pd=Pl*Al-Ps -  Ad=(Al+(1-Al)*As) -  +    invdivide Pd=Pl/Ps -  Ad=(Al+(1-Al)*As) -  +    invmodulo Pd=Pl%Ps (measured in color values) -  Ad=(Al+(1-Al)*As) + difference Pd=abs(Ps-Pl) + min Pd=min(Ps,Pl) + max Pd=max(Ps,Pl) + bitwise_and Pd=Ps&Pl + bitwise_or Pd=Ps|Pl + bitwise_xor Pd=Ps^Pl    -  +  + replace channel layers: +  (Ad=As) + replace Pd=(Pl*Al+Ps*(1-Al)*As)/(Al+(1-Al)*As) + red Pd=Ps,Rd=(Rl*Al+Rs*(1-Al)*As)/(Al+(1-Al)*As) + green Pd=Ps,Gd=(Gl*Al+Gs*(1-Al)*As)/(Al+(1-Al)*As) + blue Pd=Ps,Bd=(Bl*Al+Bs*(1-Al)*As)/(Al+(1-Al)*As) +  + replace_hsv same as replace, but r,g,b alpha is operating on h,s,v + hue Pd=Ps,Hd=(Hl*Al+Hs*(1-Al)*As)/(Al+(1-Al)*As) + saturation Pd=Ps,Sd=(Sl*Al+Ss*(1-Al)*As)/(Al+(1-Al)*As) + value Pd=Ps,Vd=(Vl*Al+Vs*(1-Al)*As)/(Al+(1-Al)*As) + color Vd=Vs,HSd=(HSl*Al+HSs*(1-Al)*As)/(Al+(1-Al)*As) +  + darken Pd=Ps,Vd=min(Vs,Vl) + lighten Pd=Ps,Vd=max(Vs,Vl) +  +  + special layers: +    dissolve i=round(random(Al)) typ    Pd=Al*i+As*(1-i)    Ad=i+As    - behind + erase Pd=Ps +  Ad=As*(1-Al) +  + behind Pd=(Ps*As+Pl*(1-As)*Al)/(As+(1-As)*Al) +  Ad=(As+(1-As)*Al) +  note: alpha value connects to layer below, +  tuning how "much" behind the image is placed +    screen   overlay - difference - darken - lighten - hue - saturation - color - value - erase - replace +       */            /*** layer helpers ****************************************/      #define COMBINE_METHOD_INT   #define CCUT_METHOD_INT   
pike.git/src/modules/Image/layers.c:274:   #endif /* COMBINE_METHOD_FLOAT */      #endif      #define COMBINE(P,A) CCUT(((int)(P))*(A))   #define COMBINE_A(P,A) ((COLORTYPE)((P)*(A)))   #define COMBINE_V(P,V,A) CCUT((V)*(P)*(A))      #define F2C(Z) ((COLORTYPE)(COLORMAX*(Z)))    - #define ALPHA_ADD(S,L,D,SA,LA,DA,C) \ -  if (!LA->C) d->C=S->C,DA->C=SA->C; \ -  else if (!SA->C) D->C=l->C,DA->C=LA->C; \ -  else if (LA->C==COLORMAX) D->C=l->C,DA->C=LA->C; \ -  else \ -  D->C=COMBINE_ALPHA(S->C,l->C,SA->C,LA->C), \ -  DA->C=COMBINE_ALPHA_SUM(SA->C,LA->C); + #define ALPHA_ADD(S,L,D,SA,LA,DA,C) \ +  if (!(LA)->C) (D)->C=(S)->C,(DA)->C=(SA)->C; \ +  else if (!(SA)->C) (D)->C=(L)->C,(DA)->C=(LA)->C; \ +  else if ((LA)->C==COLORMAX) (D)->C=(L)->C,(DA)->C=(LA)->C; \ +  else \ +  (D)->C=COMBINE_ALPHA((S)->C,(L)->C,(SA)->C,(LA)->C), \ +  (DA)->C=COMBINE_ALPHA_SUM((SA)->C,(LA)->C);    - #define ALPHA_ADD_V_NOLA(L,S,D,SA,DA,V,C) \ -  do { \ -  if (!SA->C) D->C=l->C,DA->C=0; \ -  else \ -  { \ -  if (SA->C==COLORMAX) \ -  D->C=COMBINE_ALPHA_V(S->C,l->C,COLORMAX,255,V); \ -  else D->C=COMBINE_ALPHA_V(S->C,l->C,SA->C,255,V); \ -  DA->C=COMBINE_ALPHA_SUM_V(SA->C,255,V); \ -  } \ + #define ALPHA_ADD_V_NOLA(L,S,D,SA,DA,V,C) \ +  do { \ +  if (!(SA)->C) (D)->C=(L)->C,(DA)->C=0; \ +  else \ +  { \ +  if ((SA)->C==COLORMAX) \ +  (D)->C=COMBINE_ALPHA_V((S)->C,(L)->C,COLORMAX,255,V); \ +  else \ +  (D)->C=COMBINE_ALPHA_V((S)->C,(L)->C,(SA)->C,255,V); \ +  (DA)->C=COMBINE_ALPHA_SUM_V((SA)->C,255,V); \ +  } \    } while(0)    - #define ALPHA_ADD_V(L,S,D,LA,SA,DA,V,C) \ -  do { \ -  if (!LA->C) \ -  { \ -  D->C=COMBINE_ALPHA_V(S->C,l->C,SA->C,0,V); \ -  DA->C=COMBINE_ALPHA_SUM_V(0,SA->C,V); \ -  } \ -  else if (!SA->C) \ -  { \ -  D->C=COMBINE_ALPHA_V(S->C,l->C,0,LA->C,V); \ -  DA->C=COMBINE_ALPHA_SUM_V(LA->C,0,V); \ -  } \ -  else \ -  { \ -  D->C=COMBINE_ALPHA_V(S->C,l->C,SA->C,LA->C,V); \ -  DA->C=COMBINE_ALPHA_SUM_V(LA->C,SA->C,V); \ -  } \ + #define ALPHA_ADD_V(L,S,D,LA,SA,DA,V,C) \ +  do { \ +  if (!(LA)->C) \ +  { \ +  (D)->C=COMBINE_ALPHA_V((S)->C,(L)->C,(SA)->C,0,V); \ +  (DA)->C=COMBINE_ALPHA_SUM_V(0,(SA)->C,V); \ +  } \ +  else if (!(SA)->C) \ +  { \ +  (D)->C=COMBINE_ALPHA_V((S)->C,(L)->C,0,(LA)->C,V); \ +  (DA)->C=COMBINE_ALPHA_SUM_V((LA)->C,0,V); \ +  } \ +  else \ +  { \ +  (D)->C=COMBINE_ALPHA_V((S)->C,(L)->C,(SA)->C,(LA)->C,V); \ +  (DA)->C=COMBINE_ALPHA_SUM_V((LA)->C,(SA)->C,V); \ +  } \    } while (0)         static INLINE void smear_color(rgb_group *d,rgb_group s,int len)   {    while (len--)    *(d++)=s;   }      #define MAX3(X,Y,Z) MAXIMUM(MAXIMUM(X,Y),Z)
pike.git/src/modules/Image/layers.c:805:    _image_make_rgb_color(THIS->fill_alpha.r,    THIS->fill_alpha.g,    THIS->fill_alpha.b);   }      /*   **! method object set_offset(int x,int y)   **! method int xoffset()   **! method int yoffset()   **! Set/query layer offset. + **! + **! method int xsize() + **! method int ysize() + **! Query layer offset. This is the same as layer + **! image/alpha image size.   */      static void image_layer_set_offset(INT32 args)   {    get_all_args("Image.Layer->set_offset",args,"%i%i",    &(THIS->xoffs),&(THIS->yoffs));    pop_n_elems(args);    ref_push_object(THISOBJ);   }   
pike.git/src/modules/Image/layers.c:827:    pop_n_elems(args);    push_int(THIS->xoffs);   }      static void image_layer_yoffset(INT32 args)   {    pop_n_elems(args);    push_int(THIS->yoffs);   }    + static void image_layer_xsize(INT32 args) + { +  pop_n_elems(args); +  push_int(THIS->xsize); + } +  + static void image_layer_ysize(INT32 args) + { +  pop_n_elems(args); +  push_int(THIS->ysize); + } +    /*   **! method object set_tiled(int yes)   **! method int tiled()   **! Set/query <i>tiled</i> flag. If set, the   **! image and alpha channel will be tiled rather   **! then framed by the <ref>fill</ref> values.   */      static void image_layer_set_tiled(INT32 args)   {
pike.git/src/modules/Image/layers.c:1168:   #undef L_OPER      #define LM_FUNC lm_invmodulo   #define L_TRUNC(X) ((COLORTYPE)(X))   #define L_OPER(A,B) ((B)%(A))   #include "layer_oper.h"   #undef LM_FUNC   #undef L_TRUNC   #undef L_OPER    + #define LM_FUNC lm_difference + #define L_TRUNC(X) ((COLORTYPE)(X)) + #define L_OPER(A,B) abs((A)-(B)) + #include "layer_oper.h" + #undef LM_FUNC + #undef L_TRUNC + #undef L_OPER +  + #define LM_FUNC lm_max + #define L_TRUNC(X) ((COLORTYPE)(X)) + #define L_OPER(A,B) MAXIMUM((A),(B)) + #include "layer_oper.h" + #undef LM_FUNC + #undef L_TRUNC + #undef L_OPER +  + #define LM_FUNC lm_min + #define L_TRUNC(X) ((COLORTYPE)(X)) + #define L_OPER(A,B) MINIMUM((A),(B)) + #include "layer_oper.h" + #undef LM_FUNC + #undef L_TRUNC + #undef L_OPER +  + #define LM_FUNC lm_bitwise_and + #define L_TRUNC(X) ((COLORTYPE)(X)) + #define L_OPER(A,B) ((A)&(B)) + #include "layer_oper.h" + #undef LM_FUNC + #undef L_TRUNC + #undef L_OPER +  + #define LM_FUNC lm_bitwise_or + #define L_TRUNC(X) ((COLORTYPE)(X)) + #define L_OPER(A,B) ((A)|(B)) + #include "layer_oper.h" + #undef LM_FUNC + #undef L_TRUNC + #undef L_OPER +  + #define LM_FUNC lm_bitwise_xor + #define L_TRUNC(X) ((COLORTYPE)(X)) + #define L_OPER(A,B) ((A)^(B)) + #include "layer_oper.h" + #undef LM_FUNC + #undef L_TRUNC + #undef L_OPER +    /* channels from template */      /* replace rgb by alpha channel */      #define LM_FUNC lm_replace   #define L_CHANNEL_DO(S,L,D,A) \    ((D).r=COMBINE_ALPHA((S).r,(L).r,COLORMAX,(A).r), \    (D).g=COMBINE_ALPHA((S).g,(L).g,COLORMAX,(A).g), \    (D).b=COMBINE_ALPHA((S).b,(L).b,COLORMAX,(A).b))   #define L_CHANNEL_DO_V(S,L,D,A,V) \
pike.git/src/modules/Image/layers.c:1291:   #define L_CHANNEL_DO_V(S,L,D,A,V) \    do { \    double lh,ls,lv; \    double sh,ss,sv; \    double dh,ds,dv; \    rgb_to_hsv((S),&sh,&ss,&sv); \    rgb_to_hsv((L),&lh,&ls,&lv); \    dv=lv*(V)*C2F((A).b)+sv*(1-(V)*C2F((A).b)); \    hsv_to_rgb(sh,ss,dv,&(D)); \    } while (0) -  +    #include "layer_channel.h"   #undef L_CHANNEL_DO_V   #undef LM_FUNC      /* h, s */      #define LM_FUNC lm_color   #define L_CHANNEL_DO_V(S,L,D,A,V) \    do { \    double lh,ls,lv; \    double sh,ss,sv; \    double dh,ds,dv; \    rgb_to_hsv((S),&sh,&ss,&sv); \    rgb_to_hsv((L),&lh,&ls,&lv); \    dh=lh*(V)*C2F((A).r)+sh*(1-(V)*C2F((A).r)); \    ds=ls*(V)*C2F((A).g)+ss*(1-(V)*C2F((A).g)); \    hsv_to_rgb(dh,ds,sv,&(D)); \    } while (0) -  + #include "layer_channel.h" + #undef L_CHANNEL_DO_V + #undef LM_FUNC    -  + /* lighten: max v */ +  + #define LM_FUNC lm_lighten + #define L_CHANNEL_DO_V(S,L,D,A,V) \ +  do { \ +  double lh,ls,lv; \ +  double sh,ss,sv; \ +  double dh,ds,dv; \ +  rgb_to_hsv((S),&sh,&ss,&sv); \ +  rgb_to_hsv((L),&lh,&ls,&lv); \ +  hsv_to_rgb(sh,ss,MAXIMUM(sv,lv),&(D)); \ +  } while (0)   #include "layer_channel.h"   #undef L_CHANNEL_DO_V   #undef LM_FUNC    -  + /* darken: min v */ +  + #define LM_FUNC lm_darken + #define L_CHANNEL_DO_V(S,L,D,A,V) \ +  do { \ +  double lh,ls,lv; \ +  double sh,ss,sv; \ +  double dh,ds,dv; \ +  rgb_to_hsv((S),&sh,&ss,&sv); \ +  rgb_to_hsv((L),&lh,&ls,&lv); \ +  hsv_to_rgb(sh,ss,MINIMUM(sv,lv),&(D)); \ +  } while (0) + #include "layer_channel.h" + #undef L_CHANNEL_DO_V + #undef LM_FUNC +  +    #undef L_CHANNEL_DO      /* special modes */      static void lm_dissolve(rgb_group *s,rgb_group *l,rgb_group *d,    rgb_group *sa,rgb_group *la,rgb_group *da,    int len,double alpha)   {    if (alpha==0.0)    {
pike.git/src/modules/Image/layers.c:1374:    if ((my_rand()&65535) < ((la->r*87 + la->g*127 + la->b*41)>>8)*v)    *d=*l,*da=white;    else    *d=*s,*da=*sa;    l++; s++; la++; sa++; da++; d++;    }    }    }   }    + static void lm_behind(rgb_group *s,rgb_group *l,rgb_group *d, +  rgb_group *sa,rgb_group *la,rgb_group *da, +  int len,double alpha) + { +  /* la may be NULL, no other */ +  +  if (alpha==0.0) /* optimized */ +  { +  MEMCPY(d,s,sizeof(rgb_group)*len); +  MEMCPY(da,sa,sizeof(rgb_group)*len); +  return; +  } +  else if (alpha==1.0) +  while (len--) +  { +  if (sa->r==COLORMAX && sa->g==COLORMAX && sa->b==COLORMAX) +  { +  *d=*s; +  *da=*sa; +  } +  else if (sa->r==0 && sa->g==0 && sa->b==0) +  { +  *d=*l; +  if (la) *da=*la; else *da=white; +  } +  else if (la) +  { +  ALPHA_ADD(l,s,d,la,sa,da,r); +  ALPHA_ADD(l,s,d,la,sa,da,g); +  ALPHA_ADD(l,s,d,la,sa,da,b); +  } +  else +  { +  ALPHA_ADD(l,s,d,(&white),sa,da,r); +  ALPHA_ADD(l,s,d,(&white),sa,da,g); +  ALPHA_ADD(l,s,d,(&white),sa,da,b); +  } +  l++; s++; sa++; d++; da++; +  if (la) la++; +  } +  else +  while (len--) +  { +  if (sa->r==COLORMAX && sa->g==COLORMAX && sa->b==COLORMAX) +  { +  *d=*s; +  *da=*sa; +  } +  else if (sa->r==0 && sa->g==0 && sa->b==0) +  { +  *d=*l; +  if (la) *da=*la; else *da=white; +  } +  else if (la) +  { +  ALPHA_ADD_V(l,s,d,la,sa,da,alpha,r); +  ALPHA_ADD_V(l,s,d,la,sa,da,alpha,g); +  ALPHA_ADD_V(l,s,d,la,sa,da,alpha,b); +  } +  else +  { +  ALPHA_ADD_V(l,s,d,(&white),sa,da,alpha,r); +  ALPHA_ADD_V(l,s,d,(&white),sa,da,alpha,g); +  ALPHA_ADD_V(l,s,d,(&white),sa,da,alpha,b); +  } +  l++; s++; sa++; d++; da++; +  if (la) la++; +  } + } +  + static void lm_erase(rgb_group *s,rgb_group *l,rgb_group *d, +  rgb_group *sa,rgb_group *la,rgb_group *da, +  int len,double alpha) + { +  /* la may be NULL, no other */ +  +  MEMCPY(d,s,sizeof(rgb_group)*len); +  +  if (alpha==1.0) +  if (!la) /* full opaque */ +  smear_color(da,black,len); +  else +  while (len--) +  { +  da->r=CCUT(sa->r*(int)(COLORMAX-la->r)); +  da->g=CCUT(sa->g*(int)(COLORMAX-la->g)); +  da->b=CCUT(sa->b*(int)(COLORMAX-la->b)); +  +  la++; sa++; da++; +  } +  else +  if (!la) /* full opaque */ +  { +  rgb_group a; +  a.r=a.g=a.b=COLORMAX-(COLORTYPE)(alpha*COLORMAX); +  smear_color(da,a,len); +  } +  else +  while (len--) +  { +  da->r=CCUT(sa->r*(int)(COLORMAX-alpha*la->r)); +  da->g=CCUT(sa->g*(int)(COLORMAX-alpha*la->g)); +  da->b=CCUT(sa->b*(int)(COLORMAX-alpha*la->b)); +  +  la++; sa++; da++; +  } + } +  +    /*** the add-layer function ***************************/      static void INLINE img_lay_first_line(struct layer *l,    int xoffs,int xsize,    int y, /* in _this_ layer */    rgb_group *d,rgb_group *da)   {    if (!l->tiled)    {    rgb_group *s,*sa;
pike.git/src/modules/Image/layers.c:1863:       /* query */       ADD_FUNCTION("image",image_layer_image,tFunc(,tObj),0);    ADD_FUNCTION("alpha",image_layer_alpha,tFunc(,tObj),0);    ADD_FUNCTION("mode",image_layer_mode,tFunc(,tStr),0);       ADD_FUNCTION("available_modes",image_layer_available_modes,    tFunc(,tArr(tStr)),0);    +  ADD_FUNCTION("xsize",image_layer_xsize,tFunc(,tInt),0); +  ADD_FUNCTION("ysize",image_layer_ysize,tFunc(,tInt),0); +     ADD_FUNCTION("xoffset",image_layer_xoffset,tFunc(,tInt),0);    ADD_FUNCTION("yoffset",image_layer_yoffset,tFunc(,tInt),0);       ADD_FUNCTION("alpha_value",image_layer_alpha_value,tFunc(,tFloat),0);    ADD_FUNCTION("fill",image_layer_fill,tFunc(,tObj),0);    ADD_FUNCTION("fill_alpha",image_layer_fill_alpha,tFunc(,tObj),0);       ADD_FUNCTION("tiled",image_layer_tiled,tFunc(,tInt01),0);       image_layer_program=end_program();