Listing 1

/**********************************************************/
/* CONVOLVE.C - Turbo C 2.0 implementation of image       */
/*                           convolution                  */
/* ----------   by Wesley G. Faler.  All code is "as is". */
/* There is NO copyright.  Use this code as you will, and */
/* if you make money at it, good for you.                 */
/**********************************************************/

#include<stdlib.h>
#include<stdio.h>
#include<graphics.h>
#include<alloc.h>
#include<ctype.h>

int load_cut(char *fname);
int load_convolution_matrix(char *fname);
int convolve_image(void);
int swap_pictures(void);

int minx,maxx,miny,maxy;
int LOADPAGE=0;
int ENHANCEPAGE=1;
int *cmat, *pmat, *vmat;
int cmx,cmy,cmnum;

struct palettetype palette,newpal;
int driver,mode;

int cleancut=-1;

int init_graphics(void)
{
 driver=DETECT; mode=0;
 detectgraph(&driver,&mode);
 if(driver==VGA) mode=VGAMED;
 initgraph(&driver,&mode,"");
 getpalette(&palette);
 getpalette(&newpal);
}

int cleanup_image(void)
{
 int i,j,num,x,y,k;

 if(cleancut<0) return;
 setactivepage(LOADPAGE);
 setvisualpage(ENHANCEPAGE);
 for(x=minx;x<maxx;x++) {
  for(y=miny;y<maxy;y++) {
   if(getpixel(x,y)!=0) num=-1;
    else num=0;
   for(j=-1;j<2;j++) {
    for(i=-1;i<2;i++) {
     if(getpixel(x+i,y+j)!=0) num++;
    }
   }
   if(num>cleancut) {
    k=getpixel(x,y);
    setactivepage(ENHANCEPAGE);
    putpixel(x,y,k);
    setactivepage(LOADPAGE);
   }
  }
 }
 k=ENHANCEPAGE; ENHANCEPAGE=LOADPAGE; LOADPAGE=k;
}

void show_test_image(void)
{
 int i;
 
 minx-cmx; miny=cmy;
 maxx=100+minx; maxy=100+miny;
 setcolor(1);
 moveto(minx,miny);
 randomize();
 for(i=0;i<20;i++)
  lineto(random(100)+minx,random(100)+miny);
 for(i=0;i<10;i++)
  fillellipse(random(50)+25+minx,random(50)+25+miny,
            random(25),random(25));
}

main( )
{
 char fname[50];
 int flag=0;

 load_convolution_matrix("matrix.dat");
 printf(".CUT file (1) or test image (0)?");
 scanf("%d",&flag);
 flag= flag? 1:0;
 if(flag) {
  fflush(stdin);
  printf("filename to process:");
  gets(fname);
 }
 
 printf("Delete pixels with x or fewer neighbors. x=");
 scanf("%d",&cleancut);
 if(cleancut>8) cleancut=8;

 init_graphics();
 setactivepage(1); cleardevice();
 setactivepage(0); cleardevice();

 setactivepage(LOADPAGE); setvisualpage(LOADPAGE);
 if(flag) load_cut(fname);
  else show_test_image();
 cleanup_image();

 setvisualpage(ENHANCEPAGE);
 convolve_image();

 swap_pictures();
 restorecrtmode();
}

int toggle_colors(char c)
{
 c=tolower(c);
 c=c-'a';
 if(c<0 || c>=palette.size) return 0;
 newpal.colors[c]= palette.colors[c]-newpal.colors[c];
 setpalette(c,newpal.colors[c]);
 return 1;
}

int swap_pictures(void)
{
 int mode=0;
 char a;

 setvisualpage(LOADPAGE);
 for (;;) {
  a=getch();
  if(a==27) return;
  if(toggle colors(a)) continue;
  if(mode==0) setvisualpage(ENHANCEPAGE);
  if(mode==1) setvisualpage(LOADPAGE);
  mode=1-mode;
 }
}

int convolve_image(void)
{
 int i,j,k,nval;
 int *vx, *vy, *c;
 int colmax,offset,end,midy;
char **lines=NULL;
char *temp=NULL;

offset =-minx+(mcx/2);
end=cmy-1; midy=cmy/2;
lines=(char **)malloc(cmy*sizeof(char *));
for(i=0;i<cmy;i++)
  lines[i]-(char *)malloc(sizeof(char)*(maxx-minx+cmx+1));
setactivepage(LOADPAGE);
for(j=-cmy/2;j<cmy/2;j++) {
 for(i=minx-cmx/2;i<(maxx+cmx/2+1);i++) {
  lines[j+midy][i+offset]-getpixel(i,j+miny);
 }
}
  colmax=getmaxcolor();
  for(j = miny;j<maxy;j++) {
   setactivepage(LOADPAGE);
   for(i=j+cmy/2,k=minx-cmx/2,nval=maxx+cmx/2;k<nval;k++)
    lines[end][k+offset] = getpixel(k,i);
   for(i=minx;i<maxx;i++) {
    /* Load & multiply neighbors into matrix */
    setactivepage(LOADPAGE);
    vx=vmat; vy=vmat+1; c=cmat; nval=0;
    for(k=0;k<cmnum;k++) {
     if(*c) nval+= lines[(*vy)+midy][i+(*vx)+offset]*(*c);
     /* if(*c) nval+= getpixel(i+(*vx),j+(*vy)) * (*c); */
     c++;
     vx+=2; vy+=2;
    }
    /*  Cut off values too high or too low */
    if(nval<0) nval=0;
    if(nval>colmax) nval=colmax;
    /*  Place new pixel value */
    setactivepage(ENHANCEPAGE);
    putpixel(i,j,nval);
   }
   if(kbhit()) { getch(); break; }
   /* rotate line pointers */
   temp=lines[0];
   for(i=1;i<cmy;i++) lines[i-1]=lines[i];
   lines[end]=temp;
  }
  for(i=0;i<cmy;i++) {
   if(lines[i]!=NULL) free(lines[i]);
  }
  if(lines!=NULL) {
   free(lines);
  }
  return;
 }
 int build_offset_vectors(void)
 {
  int *t;
  int il,im,jl,jm,i,j;
  il=-cmx/2; im=cmx+il;
  jl=-cmy/2; jm=cmy+jl;
  t=vmat;
  for(j = jl;j<jm;j++) {
   for(i=il;i<im;i++) {
    *t++=i; *t++=j;
   }
  }
 }
 int load_convolution_matrix(char *fname)
 {
  /* Layout of matrix file:
     #x #y
     x0y0 x1y0 ... xny1
     .... .... ... ....
     x0ym x1ym ... xnym
  */
  FILE *mf;
 int *t;
 int i,j,im,jm;
 if( (mf=fopen(fname,"rt"))==NULL) {
  printf("Cannot load matrix file.\n");
  abort();
 }
 fscanf(mf,"%d%d",&im,&jm);
 if( (im&1)==0 || (jm&1)==0) {
  printf("Convolution matrix MUST have a center point.\n");
  abort();
 }
 if( (cmat=(int *)calloc(im*jm,sizeof(int)))==NULL ) {
  printf("Unable to calloc convolution matrix.\n");
  abort();
 }
 cmx=im; cmy=jm; cmnum=im*jm;
 t=cmat;
 for(j=0;j<jm;j++) {
  for(i=0;i<im;i++) {
   if( fscanf(mf,"%d",t++)!=1 ) {
    printf("Unable to read matrix.\n");
    abort();
   }
  }
 }
 fclose(mf);
 build_offset_vectors();
}

int load_cut(char *fname)
{
 static unsigned char st[3000];
 char *sp=st,*spend;
 int stp=0;
 int width,height;
 FILE *fp;
 int x,y,xl,yl;
 int i,n,len,d,j;
 
 fp=fopen(fname,"rb");
 width=getw(fp); height=getw(fp);
 xl =cmx; yl=cmy;
 minx=xl; miny=yl;
 maxx=xl+width; maxy=yl+height;
 if(maxy>(getmaxy()-cmy)) {
  maxy=getmaxy()-cmy;
  height=maxy-yl;
 }
 getw(fp);
 y=yl-1;
 for(sp=st,n=0;n<height;n++) {
  stp=getw(fp);
  for(sp=st,spend=st+stp;sp<spend;) *sp++=getc(fp);
  sp=st; spend=sp+stp; x=xl; y++;
  while(sp<spend) {
   if(*((unsigned char *)sp)>0x80) {
    len=(*sp++) & 0x7f;
    if(!(*sp)) { x+=len; continue; }
    setcolor(*sp++);
    moveto(x,y);
    linerel(len,0);
    x+=len;
    continue;
   } else {
    len=*sp++;
    for(j-0;j<len;j++) putpixel(x++,y,*sp++);
    continue;
   }
  }
 }
  fclose(fp);
 }