home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / haeberli / libcan / canop.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  14.9 KB  |  753 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.  *    canop -
  19.  *        Apply global operations to canvases.
  20.  *
  21.  *                Paul Haeberli - 1991
  22.  *
  23.  *    exports
  24.  *
  25.     void bwonly(mode);
  26.     void canvasop(c,opfunc,arg1,arg2,arg3)
  27.  
  28.     void saturateop(pptr,n,sat,dum1,dum2)
  29.     void copyred(pptr,n,dum1,dum2,dum3)
  30.     void imgexpop(pptr,n,min,max,dum1)
  31.     void gammaop(pptr,n,gam,dum1,dum2)
  32.     void cscaleop(pptr,n,rscale,gscale,bscale)
  33.     void invertop(pptr,n)
  34.     void addnoiseop(pptr,n,mag)
  35.     void quantop(pptr,n,nsteps)
  36.     void duotoneop(pptr,n,rval,gval,bval)
  37.  
  38.     canvas *makestamp(c,maxxsize,maxysize,filter)
  39.     void randcopy(orig,dest)
  40.     void canvastile(tile,dest)
  41.     void convolve3(src,dest,mat)
  42.  *
  43.  */
  44. #include "stdio.h"
  45. #include "canvas.h"
  46. #include "math.h"
  47. #include "izoom.h"
  48. #include "lum.h"
  49. #include "lut.h"
  50.  
  51. #define STAMPSIZE    100
  52.  
  53. static int dobwonly;
  54.  
  55. void bwonly(mode)
  56. int mode;
  57. {
  58.     dobwonly = mode;
  59. }
  60.  
  61. float frand();
  62. static applymaptab();
  63.  
  64. static float clamp(v)
  65. float v;
  66. {
  67.     if(v<0.0)
  68.     return 0.0;
  69.     if(v>1.0)
  70.     return 1.0;
  71.     return v;
  72. }
  73.  
  74. void canvasop(c,opfunc,arg1,arg2,arg3)
  75. canvas *c;
  76. int (*opfunc)();
  77. float arg1, arg2, arg3;
  78. {
  79.     long *dptr;
  80.     
  81.     saverect(c,&c->area);
  82.     opfunc(c->data,c->xsize*c->ysize,arg1,arg2,arg3);
  83.     touchcanvas(c);
  84.     flushcanvas(c);
  85. }
  86.  
  87. #define DOTWOPIX(p0,p1)                        \
  88.     ul = ((((pptr[(p1)].r<<16) + pptr[(p0)].r)*RINTLUM)+    \
  89.      (((pptr[(p1)].g<<16) + pptr[(p0)].g)*GINTLUM)+     \
  90.      (((pptr[(p1)].b<<16) + pptr[(p0)].b)*BINTLUM))>>8;    \
  91.     pptr[(p0)].r = pptr[(p0)].g = pptr[(p0)].b = ul;        \
  92.     pptr[(p1)].r = pptr[(p1)].g = pptr[(p1)].b = (ul>>16); 
  93.  
  94.  
  95. void saturateop(pptr,n,sat,dum1,dum2)
  96. pixel *pptr;
  97. int n;
  98. float sat, dum1, dum2;
  99. {
  100.     unsigned long ur, ug, ub, ul, l;
  101.     int bw, r, g, b;
  102.     unsigned long *p, pix0, pix1;
  103.     int isat;
  104.  
  105.     if(dobwonly)
  106.     sat = 0;
  107.     isat = 255*sat;
  108.     if(isat == 0) {
  109.     while(n>=8) {
  110.         DOTWOPIX(0,1);
  111.         DOTWOPIX(2,3);
  112.         DOTWOPIX(4,5);
  113.         DOTWOPIX(6,7);
  114.         pptr+=8;
  115.         n-=8;
  116.     }
  117.     while(n--) {
  118.         pptr->r = pptr->g = pptr->b = ILUM(pptr->r,pptr->g,pptr->b);
  119.         pptr++;
  120.     }
  121.     return;
  122.     }
  123.     if(sat>=0.0 && sat<=1.0) {
  124.     while(n--) {
  125.         r = pptr->r;
  126.         g = pptr->g;
  127.         b = pptr->b;
  128.         bw = (256-isat)*ILUM(r,g,b);
  129.         pptr->r = (bw+isat*r)>>8;
  130.         pptr->g = (bw+isat*g)>>8;
  131.         pptr->b = (bw+isat*b)>>8;
  132.         pptr++;
  133.     }
  134.     return;
  135.     }
  136.     while(n--) {
  137.     r = pptr->r;
  138.     g = pptr->g;
  139.     b = pptr->b;
  140.     bw = (256-isat)*ILUM(r,g,b);
  141.     r = (bw+isat*r)>>8;
  142.     g = (bw+isat*g)>>8;
  143.     b = (bw+isat*b)>>8;
  144.  
  145.     if(r&0xffffff00) {
  146.         if(r<0) r = 0; else r = 255;
  147.     }
  148.     pptr->r = r;
  149.     if(g&0xffffff00) {
  150.         if(g<0) g = 0; else g = 255;
  151.     }
  152.     pptr->g = g;
  153.     if(b&0xffffff00) {
  154.         if(b<0) b = 0; else b = 255;
  155.     }
  156.     pptr->b = b;
  157.     pptr++;
  158.     }
  159. }
  160.  
  161. void copyred(pptr,n,dum1,dum2,dum3)
  162. pixel *pptr;
  163. int n;
  164. float dum1, dum2, dum3;
  165. {
  166.     while(n--) {
  167.     pptr->g = pptr->r;
  168.     pptr->b = pptr->r;
  169.     pptr++;
  170.     }
  171. }
  172.  
  173. void imgexpop(pptr,n,min,max,dum1)
  174. pixel *pptr;
  175. int n;
  176. float min, max, dum1;
  177. {
  178.     int i;
  179.     unsigned char tab[256];
  180.     float val, delta;
  181.  
  182.     delta = max-min;
  183.     if(delta<0.0001)
  184.     delta = 0.0001;
  185.     for(i=0; i<256; i++) {
  186.     val = clamp(((i/255.0)-min)/delta);
  187.     tab[i] = ffloor(255.0*val+0.49);
  188.     }
  189.     applymaptab(pptr,n,tab);
  190. }
  191.  
  192. #define DOMAP(p)            \
  193.     pptr[(p)].r = tab[pptr[(p)].r];    \
  194.     pptr[(p)].g = tab[pptr[(p)].g];    \
  195.     pptr[(p)].b = tab[pptr[(p)].b];
  196.  
  197. #define DOBWMAP(p)            \
  198.     pptr[(p)].r = tab[pptr[(p)].r];    
  199.  
  200. static applymaptab(pptr,n,tab)
  201. pixel *pptr;
  202. int n;
  203. unsigned char tab[256];
  204. {
  205.     if(dobwonly) {
  206.     while(n>=8) {
  207.         DOBWMAP(0);
  208.         DOBWMAP(1);
  209.         DOBWMAP(2);
  210.         DOBWMAP(3);
  211.         DOBWMAP(4);
  212.         DOBWMAP(5);
  213.         DOBWMAP(6);
  214.         DOBWMAP(7);
  215.         n-=8;
  216.         pptr+=8;
  217.     }
  218.     while(n--) {
  219.         DOBWMAP(0);
  220.         pptr++;
  221.     }
  222.     } else {
  223.     while(n>=8) {
  224.         DOMAP(0);
  225.         DOMAP(1);
  226.         DOMAP(2);
  227.         DOMAP(3);
  228.         DOMAP(4);
  229.         DOMAP(5);
  230.         DOMAP(6);
  231.         DOMAP(7);
  232.         n-=8;
  233.         pptr+=8;
  234.     }
  235.     while(n--) {
  236.         DOMAP(0);
  237.         pptr++;
  238.     }
  239.     }
  240. }
  241.  
  242. void gammaop(pptr,n,gam,dum1,dum2)
  243. pixel *pptr;
  244. int n;
  245. float gam, dum1, dum2;
  246. {
  247.     int i;
  248.     unsigned char tab[256];
  249.  
  250.     for(i=0; i<256; i++) 
  251.     tab[i] = ffloor(255.0*pow(i/255.0,gam)+0.49);
  252.     applymaptab(pptr,n,tab);
  253. }
  254.  
  255. #define DOMAP3(p)                \
  256.     pptr[(p)].r = tab1[pptr[(p)].r];    \
  257.     pptr[(p)].g = tab2[pptr[(p)].g];    \
  258.     pptr[(p)].b = tab3[pptr[(p)].b];    \
  259.  
  260. #define DOBWMAP3(p)                \
  261.     pptr[(p)].r = tab1[pptr[(p)].r];    
  262.  
  263. static applymaptab3(pptr,n,tab1,tab2,tab3)
  264. pixel *pptr;
  265. int n;
  266. unsigned char tab1[256], tab2[256], tab3[256];
  267. {
  268.     if(dobwonly) {
  269.     while(n>=8) {
  270.         DOBWMAP3(0);
  271.         DOBWMAP3(1);
  272.         DOBWMAP3(2);
  273.         DOBWMAP3(3);
  274.         DOBWMAP3(4);
  275.         DOBWMAP3(5);
  276.         DOBWMAP3(6);
  277.         DOBWMAP3(7);
  278.         n-=8;
  279.         pptr+=8;
  280.     }
  281.     while(n--) {
  282.         DOBWMAP3(0);
  283.         pptr++;
  284.     }
  285.     } else {
  286.     while(n>=8) {
  287.         DOMAP3(0);
  288.         DOMAP3(1);
  289.         DOMAP3(2);
  290.         DOMAP3(3);
  291.         DOMAP3(4);
  292.         DOMAP3(5);
  293.         DOMAP3(6);
  294.         DOMAP3(7);
  295.         n-=8;
  296.         pptr+=8;
  297.     }
  298.     while(n--) {
  299.         DOMAP3(0);
  300.         pptr++;
  301.     }
  302.     }
  303. }
  304.  
  305. void cscaleop(pptr,n,rscale,gscale,bscale)
  306. pixel *pptr;
  307. int n;
  308. float rscale, gscale, bscale;
  309. {
  310.     int i;
  311.     float val;
  312.     unsigned char rtab[256];
  313.     unsigned char gtab[256];
  314.     unsigned char btab[256];
  315.  
  316.     if(dobwonly) {
  317.     rscale = LUM(rscale,gscale,bscale);
  318.     for(i=0; i<256; i++) {
  319.         val = i/255.0;
  320.         rtab[i] = ffloor(255.0*clamp(rscale*val)+0.49);
  321.     }
  322.     applymaptab(pptr,n,rtab);
  323.     } else {
  324.     for(i=0; i<256; i++) {
  325.         val = i/255.0;
  326.         rtab[i] = ffloor(255.0*clamp(rscale*val)+0.49);
  327.         gtab[i] = ffloor(255.0*clamp(gscale*val)+0.49);
  328.         btab[i] = ffloor(255.0*clamp(bscale*val)+0.49);
  329.     }
  330.     applymaptab3(pptr,n,rtab,gtab,btab);
  331.     }
  332. }
  333.  
  334. void invertop(pptr,n)
  335. pixel *pptr;
  336. int n;
  337. {
  338.     int i;
  339.     unsigned char tab[256];
  340.  
  341.     for(i=0; i<256; i++) 
  342.     tab[i] = 255-i;
  343.     applymaptab(pptr,n,tab);
  344. }
  345.  
  346. #define NRTABS        (100)
  347. static long *randvals;
  348. static unsigned char **rtabs;
  349. static float curmag = -1.0;
  350.  
  351. void addnoiseop(pptr,n,mag)
  352. pixel *pptr;
  353. int n;
  354. float mag;
  355. {
  356.     int i, v, maxdel, idel;
  357.     unsigned char *cptr;
  358.     int curtab;
  359.     long *rptr;
  360.        
  361.     if(mag<=0.0)
  362.     return;
  363.     if(mag>1.0)
  364.     mag = 1.0;
  365.     if(!randvals) {
  366.     randvals = (long *)mymalloc(NRTABS*256*sizeof(long));
  367.     rtabs = (unsigned char **)mymalloc(NRTABS*sizeof(char *));
  368.     for(i=0; i<NRTABS; i++)
  369.         rtabs[i] = (unsigned char *)mymalloc(256*sizeof(char));
  370.     rptr = randvals;
  371.     for(i=0; i<(256*NRTABS); i++)
  372.         *rptr++ = random();
  373.     }
  374.     if(mag != curmag) {
  375.     maxdel = 127*mag;
  376.     rptr = randvals;
  377.     for(i=0; i<NRTABS; i++) {
  378.         cptr = rtabs[i];
  379.         for(v=0; v<256; v++) {
  380. #ifdef OLDWAY
  381.         idel = maxdel;
  382.         if(v<idel)
  383.             idel = v;
  384.         if((255-v)<idel)
  385.             idel = 255-v;
  386. #else
  387.         if(v<128)
  388.             idel = v*mag;
  389.         else
  390.             idel = (255-v)*mag;
  391. #endif
  392.         idel++;
  393.         if(*rptr & 0x80000)
  394.             *cptr++ = v+((*rptr++)%idel);
  395.         else
  396.             *cptr++ = v-((*rptr++)%idel);
  397.         }
  398.     }
  399.     curmag = mag;
  400.     }
  401.     if(mag == 0.0)
  402.     return;
  403.     if(dobwonly) {
  404.     while(n--) {
  405.         curtab = random()%(NRTABS-3);
  406.         pptr->r = rtabs[curtab][pptr->r];
  407.         pptr++;
  408.     }
  409.     } else {
  410.     while(n--) {
  411.         curtab = random()%(NRTABS-3);
  412.         pptr->r = rtabs[curtab++][pptr->r];
  413.         pptr->g = rtabs[curtab++][pptr->g];
  414.         pptr->b = rtabs[curtab++][pptr->b];
  415.         pptr++;
  416.     }
  417.     }
  418. }
  419.  
  420. void quantop(pptr,n,nsteps)
  421. pixel *pptr;
  422. int n;
  423. float nsteps;
  424. {
  425.     int i, isteps, ival;
  426.     unsigned char qtab[256];
  427.  
  428.     isteps = nsteps+0.50;
  429.     if(isteps<2)
  430.     isteps = 2;
  431.     else if(isteps>256)
  432.     isteps = 256;
  433.  
  434.     for(i=0; i<256; i++) {
  435.     ival = isteps*i/256;
  436.     qtab[i] =  (255*ival)/(isteps-1);
  437.     }
  438.     applymaptab(pptr,n,qtab);
  439. }
  440.  
  441. /* duotone stuff follows */
  442.  
  443. #define DTTONE        (0.50)
  444. #define DTPOWVAL    (2.0)
  445. float hypfunc();
  446.  
  447. void duotoneop(pptr,n,r,g,b)
  448. pixel *pptr;
  449. int n;
  450. float r, g, b;
  451. {
  452.     unsigned char rtab[256];
  453.     unsigned char gtab[256];
  454.     unsigned char btab[256];
  455.     int i, lum;
  456.     int glum, wlum;
  457.     float l;
  458.  
  459.     l = LUM(r,g,b)/DTTONE;
  460.     r = r/l;
  461.     g = g/l;
  462.     b = b/l;
  463.     dtmkcurve(r,rtab);
  464.     dtmkcurve(g,gtab);
  465.     dtmkcurve(b,btab);
  466.     for(i=0; i<256; i++) {
  467.     glum = ILUM(rtab[i],gtab[i],btab[i]);
  468.     wlum = i;
  469.     if(glum>0) {
  470.         rtab[i] = (rtab[i]*wlum+(glum>>1))/glum;
  471.         gtab[i] = (gtab[i]*wlum+(glum>>1))/glum;
  472.         btab[i] = (btab[i]*wlum+(glum>>1))/glum;
  473.         if(rtab[i]>255) rtab[i] = 255;
  474.         if(gtab[i]>255) gtab[i] = 255;
  475.         if(btab[i]>255) btab[i] = 255;
  476.     }
  477.     }
  478.     applymaptab3(pptr,n,rtab,gtab,btab);
  479. }
  480.  
  481. dtmkcurve(f,tab)
  482. float f;
  483. unsigned char tab[256];
  484. {
  485.     int i;
  486.     float h, hypval;
  487.  
  488.     if(f<0.05)
  489.     f = 0.05;
  490.     if(f>0.95)
  491.     f = 0.95;
  492.     hypval = 1.0;
  493.     h = hypfunc(hypval,DTPOWVAL,DTTONE);
  494.     if(h>f) {
  495.     while(1) {
  496.         h = hypfunc(hypval,DTPOWVAL,DTTONE);
  497.         if(h<f)
  498.         break;
  499.         hypval += 0.005;
  500.     }
  501.     } else {
  502.     while(1) {
  503.         h = hypfunc(hypval,DTPOWVAL,DTTONE);
  504.         if(h>f)
  505.         break;
  506.         hypval -= 0.005;
  507.     }
  508.     }
  509.     for(i=0; i<256; i++) 
  510.     tab[i] = 255.0*hypfunc(hypval,DTPOWVAL,i/(float)255)+0.499;
  511. }
  512.  
  513. canvas *makestamp(c,maxxsize,maxysize,filter)
  514. canvas *c;
  515. int maxxsize, maxysize, filter;
  516. {
  517.     canvas *stamp;
  518.     int nx, ny;
  519.  
  520.     if((float)c->xsize/c->ysize > (float)maxxsize/maxysize) {
  521.     nx = maxxsize;
  522.     ny = round((float)nx*c->ysize/c->xsize);
  523.     } else {
  524.     ny = maxysize;
  525.     nx = round((float)ny*c->xsize/c->ysize);
  526.     }
  527.     stamp = newcanvas(nx,ny);
  528.     copycanvas(c,&c->area,stamp,&stamp->area,filter);
  529.     return stamp;
  530. }
  531.  
  532. void randcopy(orig,dest)
  533. canvas *orig, *dest;
  534. {
  535.     int nx, ny, dx, dy, i;
  536.     canvas *stamp, *clone;
  537.     rct drct;
  538.  
  539.     stamp = makestamp(orig,STAMPSIZE,STAMPSIZE,IMPULSE);
  540.     dx = dest->xsize-stamp->xsize;
  541.     dy = dest->ysize-stamp->ysize;
  542.     for(i=0; i<50; i++) {
  543.     drct = stamp->area;
  544.     rctoffset(&drct,random()%dx,random()%dy);
  545.     clone = clonecanvas(stamp);
  546.     canvasop(clone,cscaleop,0.5+0.5*frand(),0.5+0.5*frand(),0.5*frand());
  547.     copycanvas(clone,&clone->area,dest,&drct,IMPULSE);
  548.     freecanvas(clone);
  549.     flushcanvas(dest);
  550.     }
  551.     freecanvas(stamp);
  552. }
  553.  
  554. void canvastile(tile,dest)
  555. canvas *tile, *dest;
  556. {
  557.     int x, y, nx, ny;
  558.     rct drct;
  559.  
  560.     nx = 1+((dest->xsize-1)/tile->xsize);
  561.     ny = 1+((dest->ysize-1)/tile->ysize);
  562.     for(y=0; y<ny; y++) {
  563.     for(x=0; x<nx; x++) {
  564.         drct = tile->area;
  565.         rctoffset(&drct,x*tile->xsize,y*tile->ysize);
  566.         copycanvas(tile,&tile->area,dest,&drct,IMPULSE);
  567.     }
  568.     flushcanvas(dest);
  569.     }
  570. }
  571.  
  572. /*
  573.  *    3x3 convolution follows
  574.  *
  575.  *
  576.  */
  577. #define DIVVAL    (1024)
  578. #define NORM(x)    ((DIVVAL*(x))/tot)
  579.  
  580. static calcconv(d,s,xsize,ysize,x1,y1,v00,v01,v02,v10,v11,v12,v20,v21,v22)
  581. pixel *d, *s;
  582. int xsize, ysize, x1, y1;
  583. short v00, v01, v02, v10, v11, v12, v20, v21, v22;
  584. {
  585.     pixel *sp;
  586.     int r, g, b;
  587.     int x0, x2;
  588.     int y0, y2;
  589.  
  590.     x0 = x1-1;
  591.     if(x0<0) x0 = 0;
  592.     x2 = x1+1;
  593.     if(x2==xsize) x2 = xsize-1;
  594.  
  595.     y0 = y1-1;
  596.     if(y0<0) y0 = 0;
  597.     y2 = y1+1;
  598.     if(y2==ysize) y2 = ysize-1;
  599.  
  600.     sp = s+(xsize*y0);
  601.     r  = v00*sp[x0].r+v01*sp[x1].r+v02*sp[x2].r;
  602.     g  = v00*sp[x0].g+v01*sp[x1].g+v02*sp[x2].g;
  603.     b  = v00*sp[x0].b+v01*sp[x1].b+v02*sp[x2].b;
  604.     sp = s+(xsize*y1);
  605.     r += v10*sp[x0].r+v11*sp[x1].r+v12*sp[x2].r;
  606.     g += v10*sp[x0].g+v11*sp[x1].g+v12*sp[x2].g;
  607.     b += v10*sp[x0].b+v11*sp[x1].b+v12*sp[x2].b;
  608.     sp = s+(xsize*y2);
  609.     r = (r+v20*sp[x0].r+v21*sp[x1].r+v22*sp[x2].r)/DIVVAL;
  610.     g = (g+v20*sp[x0].g+v21*sp[x1].g+v22*sp[x2].g)/DIVVAL;
  611.     b = (b+v20*sp[x0].b+v21*sp[x1].b+v22*sp[x2].b)/DIVVAL;
  612.  
  613.     d = d+(xsize*y1+x1);
  614.     if(r&0xffffff00) {
  615.     if(r<0) d->r = 0; else d->r = 255;
  616.     } else
  617.     d->r = r;
  618.  
  619.     if(g&0xffffff00) {
  620.     if(g<0) d->g = 0; else d->g = 255;
  621.     } else
  622.     d->g = g;
  623.  
  624.     if(b&0xffffff00) {
  625.     if(b<0) d->b = 0; else d->b = 255;
  626.     } else
  627.     d->b = b;
  628. }
  629.  
  630. void convolve3(sc,dc,mat)
  631. canvas *sc, *dc;
  632. int mat[3][3];
  633. {
  634.     int xsize, ysize;
  635.     int r, g, b;
  636.     short v00, v01, v02;
  637.     short v10, v11, v12;
  638.     short v20, v21, v22;
  639.     pixel *sp, *dp;
  640.     pixel *s, *d;
  641.     int tot, x, y, nx, ny;
  642.     int bcheck, min, max;
  643.  
  644.     xsize = sc->xsize;
  645.     ysize = sc->ysize;
  646.     if(dc->xsize != xsize || dc->ysize != ysize) {
  647.     fprintf(stderr,"convove3: source and dest canvases must be same size\n");
  648.     return;
  649.     }
  650.     s = (pixel *)sc->data;
  651.     d = (pixel *)dc->data;
  652.     nx = xsize-2;
  653.     ny = ysize-2;
  654.     tot = 0;
  655.     bcheck = 0;
  656.     max = -100000;
  657.     min = 100000;
  658.     for(y=0; y<3; y++) {
  659.     for(x=0; x<3; x++) {
  660.         tot += mat[y][x];
  661.         if(mat[y][x]<0)
  662.         bcheck++;
  663.         if(mat[y][x]<min)
  664.         min = mat[y][x];
  665.         if(mat[y][x]>max)
  666.         max = mat[y][x];
  667.     }
  668.     }
  669.     if(tot == 0)
  670.     tot = 1;
  671.     v00 = NORM(mat[0][0]); v01 = NORM(mat[0][1]); v02 = NORM(mat[0][2]);
  672.     v10 = NORM(mat[1][0]); v11 = NORM(mat[1][1]); v12 = NORM(mat[1][2]);
  673.     v20 = NORM(mat[2][0]); v21 = NORM(mat[2][1]); v22 = NORM(mat[2][2]);
  674.  
  675. /* do the edges by reflecting values */
  676.     for(y=0; y<ysize; y++) {
  677.     if(y==0 || y == ysize-1) {
  678.         for(x=0; x<xsize; x++)
  679.         calcconv(d,s,xsize,ysize,x,y,v00,v01,v02,v10,v11,v12,v20,v21,v22);
  680.     } else {
  681.         calcconv(d,s,xsize,ysize,0,y,v00,v01,v02,v10,v11,v12,v20,v21,v22);
  682.         if(xsize>1) 
  683.         calcconv(d,s,xsize,ysize,xsize-1,y,v00,v01,v02,v10,v11,v12,v20,v21,v22);
  684.     }
  685.     }
  686.  
  687. /* check for constant kernel */
  688.     if(max == min) {
  689.     for(y=0; y<ny; y++) {
  690.         dp = d+(y+1)*xsize+1;
  691.         sp = s+(y+0)*xsize+0;
  692.         for(x=0; x<nx; x++) {
  693.         r  = sp[0].r+sp[1].r+sp[2].r;
  694.         g  = sp[0].g+sp[1].g+sp[2].g;
  695.         b  = sp[0].b+sp[1].b+sp[2].b;
  696.         sp+=xsize;
  697.         r += sp[0].r+sp[1].r+sp[2].r;
  698.         g += sp[0].g+sp[1].g+sp[2].g;
  699.         b += sp[0].b+sp[1].b+sp[2].b;
  700.         sp+=xsize;
  701.         dp->r = (r+sp[0].r+sp[1].r+sp[2].r)/9;
  702.         dp->g = (g+sp[0].g+sp[1].g+sp[2].g)/9;
  703.         dp->b = (b+sp[0].b+sp[1].b+sp[2].b)/9;
  704.         sp = sp-(2*xsize-1);
  705.         dp++;
  706.         }
  707.     }
  708. /* do general kernel */
  709.     } else {
  710.     for(y=0; y<ny; y++) {
  711.         dp = d+(y+1)*xsize+1;
  712.         sp = s+(y+0)*xsize+0;
  713.         for(x=0; x<nx; x++) {
  714.         r  = v00*sp[0].r+v01*sp[1].r+v02*sp[2].r;
  715.         g  = v00*sp[0].g+v01*sp[1].g+v02*sp[2].g;
  716.         b  = v00*sp[0].b+v01*sp[1].b+v02*sp[2].b;
  717.         sp+=xsize;
  718.         r += v10*sp[0].r+v11*sp[1].r+v12*sp[2].r;
  719.         g += v10*sp[0].g+v11*sp[1].g+v12*sp[2].g;
  720.         b += v10*sp[0].b+v11*sp[1].b+v12*sp[2].b;
  721.         sp+=xsize;
  722.         r = (r+v20*sp[0].r+v21*sp[1].r+v22*sp[2].r)/DIVVAL;
  723.         g = (g+v20*sp[0].g+v21*sp[1].g+v22*sp[2].g)/DIVVAL;
  724.         b = (b+v20*sp[0].b+v21*sp[1].b+v22*sp[2].b)/DIVVAL;
  725.  
  726.         if(bcheck) {
  727.             if(r&0xffffff00) {
  728.             if(r<0) dp->r = 0; else dp->r = 255;
  729.             } else
  730.             dp->r = r;
  731.  
  732.             if(g&0xffffff00) {
  733.             if(g<0) dp->g = 0; else dp->g = 255;
  734.             } else
  735.             dp->g = g;
  736.  
  737.             if(b&0xffffff00) {
  738.             if(b<0) dp->b = 0; else dp->b = 255;
  739.             } else
  740.             dp->b = b;
  741.         } else {
  742.             dp->r = r;
  743.             dp->g = g;
  744.             dp->b = b;
  745.         }
  746.  
  747.         sp = sp-(2*xsize-1);
  748.         dp++;
  749.         }
  750.     }
  751.     }
  752. }
  753.