This is smush.c in view mode; [Download] [Up]
/* * smush.c - Blur an image. A level 1 smush is just a convolution with * a gaussian mask (or given mask). Higher levels will be more blurry. * * Author: Rod Bogart * Computer Science Dept. * University of Utah * Date: Wed Oct 15 1986 * Copyright (c) 1986, University of Utah * */ #ifndef lint static char rcs_ident[] = "$Header: /usr/users/spencer/src/urt/tools/RCS/smush.c,v 3.0 90/08/03 15:24:01 spencer Exp $"; #endif #include <stdio.h> #include "rle.h" #ifdef USE_STDLIB_H #include <stdlib.h> #else #ifndef VOID_STAR extern char *malloc(); #else extern void *malloc(); #endif extern void free(); #endif /* USE_STDLIB_H */ char *progname; void main(argc, argv) int argc; char *argv[]; { char * infname = NULL, * outfname = NULL, * maskfname = NULL; FILE * outfile = stdout; int oflag = 0, mflag = 0, no_norm = 0; int xlinewidth, xlen, ylen, x, y; int i, j, k, chan, nchan, level, levels = 1; int maskskip, origmasksize; int maxmaskskip, maxmasksize, maxmaskbelow; int masksize, maskbelow, maskabove; /*number of maskels below and above */ /* the center maskel. */ float *maskmult; float *mask_mult_table; rle_hdr out_hdr; float total, *mask, *gauss_mask(), *read_mask(); int newvalue; rle_pixel *rastptr, *rasterbase, *centerpxl, *calcpxl; rle_pixel *outrastptr, *outrasterbase, *outpxl, *tempbase; rle_pixel *bot_edge_pxl, *bot_data_pxl, *bot_extrap_pxl; rle_pixel *top_edge_pxl, *top_data_pxl, *top_extrap_pxl; rle_pixel *left_edge_pxl, *left_data_pxl, *left_extrap_pxl; rle_pixel *right_edge_pxl, *right_data_pxl, *right_extrap_pxl; rle_pixel **scanout; rle_pixel **rows; int rle_cnt, rle_err; progname = cmd_name( argv ); if ( scanargs( argc, argv, "% m%-maskfile!s n%- o%-outfile!s level%d infile%s", &mflag, &maskfname, &no_norm, &oflag, &outfname, &levels, &infname ) == 0 ) exit( 1 ); if (mflag) { mask = read_mask(&origmasksize, maskfname, no_norm); } else { origmasksize = 5; mask = gauss_mask(origmasksize); } rle_dflt_hdr.rle_file = rle_open_f(progname, infname, "r"); for ( rle_cnt = 0; (rle_err = rle_get_setup( &rle_dflt_hdr )) == RLE_SUCCESS; rle_cnt++ ) { if ( rle_dflt_hdr.alpha ) RLE_SET_BIT( rle_dflt_hdr, RLE_ALPHA ); out_hdr = rle_dflt_hdr; if ( rle_cnt == 0 ) outfile = rle_open_f( progname, outfname, "w" ); out_hdr.rle_file = outfile; rle_addhist( argv, &rle_dflt_hdr, &out_hdr ); /* initialize mask_mult_table */ mask_mult_table = (float *) malloc(sizeof(float) * origmasksize * origmasksize * 256); for (i=0; i < origmasksize; i++) { maskmult = &(mask_mult_table[(i*origmasksize) << 8]); for (j=0; j < origmasksize; j++) { for (k=0;k < 256; k++) maskmult[ k ] = (float) k * mask[i*origmasksize+j]; maskmult += 256; } } if (levels < 1) { fprintf(stderr, "Level must be greater than 0.\n"); exit(-1); } /* initial size of array has a border large enough for the biggest mask */ maxmaskskip = 1 << (levels - 1); maxmasksize = (origmasksize - 1) * maxmaskskip + 1; maxmaskbelow = (maxmasksize-1) / 2; rle_dflt_hdr.xmax -= rle_dflt_hdr.xmin; rle_dflt_hdr.xmin = 0; xlen = rle_dflt_hdr.xmax - rle_dflt_hdr.xmin + 1; ylen = rle_dflt_hdr.ymax - rle_dflt_hdr.ymin + 1; xlinewidth = xlen + maxmasksize - 1; /* assumes that alpha is 1 or 0 */ nchan = rle_dflt_hdr.ncolors + rle_dflt_hdr.alpha; /* Note: * When you read in a row of pixels with rle_getrow, it places blank * pixels between 0 and xmin of your buffer. However, when you * use rle_putrow to write them out, the buffer must be pointing at * where the data actually starts (i.e., at [xmin] of the getrow * buffer. */ /* WARNING: Heavy-duty pointer munging ahead */ rows = (rle_pixel **) malloc( nchan * sizeof( rle_pixel * ) ); if (! rows) fprintf(stderr, "%s: malloc failed\n", progname); rasterbase = (unsigned char *)malloc( xlinewidth * (ylen + maxmasksize - 1) * nchan ); outrasterbase = (unsigned char *)malloc( xlinewidth * (ylen + maxmasksize - 1) * nchan ); if ((!rasterbase) || (!outrasterbase)) { fprintf(stderr, "%s: No memory for raster\n", progname); exit(-1); } rastptr = &(rasterbase[maxmaskbelow * xlinewidth * nchan + maxmaskbelow]); /**************************************************** * Read in all of the pixels ****************************************************/ for (i = rle_dflt_hdr.ymin; i <= rle_dflt_hdr.ymax; i++) { for (chan=0; chan < nchan; chan++) { rows[chan] = rastptr; /* Increment pointer by xlinewidth */ rastptr = &(rastptr[xlinewidth]); } /* assumes 1 or 0 for alpha */ rle_getrow( &rle_dflt_hdr, &rows[rle_dflt_hdr.alpha] ); } for(level = 1; level <= levels; level++) { /* actual mask is always size by size of data with extra zeros */ maskskip = 1 << (level - 1); masksize = (origmasksize - 1) * maskskip + 1; maskbelow = (masksize-1) / 2; maskabove = masksize / 2; /**************************************************** * Extrapolate boundary pixels ****************************************************/ if ((maskbelow > 0) && (maskabove > 0)) { rastptr = &(rasterbase[maxmaskbelow + maxmaskbelow * xlinewidth * nchan]); for (chan = 0; chan < nchan; chan++) { bot_edge_pxl = &(rastptr[chan * xlinewidth]); top_edge_pxl = &(rastptr[(ylen-1) * nchan * xlinewidth + chan * xlinewidth]); for(x=0; x < xlen; x++) { for (i=1; i <= maskbelow; i++) { bot_data_pxl = bot_edge_pxl + i * xlinewidth * nchan; bot_extrap_pxl = bot_edge_pxl - i * xlinewidth * nchan; newvalue = 2 * (*bot_edge_pxl) - (*bot_data_pxl); *bot_extrap_pxl = (newvalue < 0) ? 0 : ((newvalue > 255) ? 255 : newvalue); } for (i=1; i <= maskabove; i++) { top_data_pxl = top_edge_pxl - i * xlinewidth * nchan; top_extrap_pxl = top_edge_pxl + i * xlinewidth * nchan; newvalue = 2 * (*top_edge_pxl) - (*top_data_pxl); *top_extrap_pxl = (newvalue < 0) ? 0 : ((newvalue > 255) ? 255 : newvalue); } bot_edge_pxl++; top_edge_pxl++; } } left_edge_pxl = &(rastptr[(-maskbelow) * nchan * xlinewidth]); right_edge_pxl = &(rastptr[(-maskbelow) * nchan * xlinewidth + xlinewidth - masksize]); for (chan = 0; chan < nchan; chan++) { for(y=0; y < ylen + masksize - 1; y++) { for (i=1; i <= maskbelow; i++) { left_data_pxl = left_edge_pxl + i; left_extrap_pxl = left_edge_pxl - i; newvalue = 2 * (*left_edge_pxl) - (*left_data_pxl); *left_extrap_pxl = (newvalue < 0) ? 0 : ((newvalue > 255) ? 255 : newvalue); } for (i=1; i <= maskabove; i++) { right_data_pxl = right_edge_pxl - i; right_extrap_pxl = right_edge_pxl + i; newvalue = 2 * (*right_edge_pxl) - (*right_data_pxl); *right_extrap_pxl = (newvalue < 0) ? 0 : ((newvalue > 255) ? 255 : newvalue); } left_edge_pxl += xlinewidth; right_edge_pxl += xlinewidth; } } } for (y = 0; y < ylen; y++) { rastptr = &(rasterbase[maxmaskbelow + (y+maxmaskbelow) * xlinewidth * nchan]); outrastptr = &(outrasterbase[maxmaskbelow + (y+maxmaskbelow) * xlinewidth * nchan]); for (chan = 0; chan < nchan; chan++) { centerpxl = &(rastptr[chan * xlinewidth]); outpxl = &(outrastptr[chan * xlinewidth]); for(x=0; x < xlen; x++) { total = 0.0; for (i=0; i < origmasksize; i++) { calcpxl = centerpxl + (i * maskskip - maskbelow) * xlinewidth * nchan - maskbelow; maskmult = &(mask_mult_table[(i*origmasksize) << 8]); for (j=0; j < origmasksize; j++) { /* look up multiply in maskmult table */ total += maskmult[ calcpxl[j*maskskip] ]; maskmult += 256; } } /* bound result to 0 to 255 */ *outpxl = (total < 0.0) ? 0 : ((total > 255.0) ? 255 : (unsigned char) total ); centerpxl++; outpxl++; } } } /* swap inbase and out base pointers for next pass */ tempbase = rasterbase; rasterbase = outrasterbase; outrasterbase = tempbase; } /**************************************************** * Set up output scanline ****************************************************/ if (rle_row_alloc( &out_hdr, &scanout )) fprintf(stderr, "%s: Ran out of malloc space\n", progname); if (out_hdr.alpha) scanout--; /* Use zero based (vs. -1 based) addressing */ for ( chan=0; chan < nchan; chan++) { rows[chan] = scanout[chan]; } rle_put_setup( &out_hdr ); for (y = 0; y < ylen; y++) { rastptr = &(rasterbase[maxmaskbelow + (y+maxmaskbelow) * xlinewidth * nchan]); for (chan = 0; chan < nchan; chan++) { outpxl = &(rastptr[chan * xlinewidth]); for(x=0; x < xlen; x++) { scanout[chan][x] = *outpxl; outpxl++; } } rle_putrow( &rows[out_hdr.alpha], xlen, &out_hdr ); } rle_puteof( &out_hdr ); free( mask_mult_table ); free( rows ); free( rasterbase ); free( outrasterbase ); if ( out_hdr.alpha ) scanout++; /* Reverse above action. */ rle_row_free( &out_hdr, scanout ); } /* Check for an error. EOF or EMPTY is ok if at least one image * has been read. Otherwise, print an error message. */ if ( rle_cnt == 0 || (rle_err != RLE_EOF && rle_err != RLE_EMPTY) ) rle_get_error( rle_err, cmd_name( argv ), infname ); exit( 0 ); } float * gauss_mask(siz) int siz; { int i,j; float w[5]; float *mptr; w[0] = 0.05; w[1] = 0.25; w[2] = 0.4; w[3] = 0.25; w[4] = 0.05; mptr = (float *) malloc( sizeof(float) * siz * siz ); if (siz != 5) { fprintf(stderr,"mask size not 5\n"); exit(-1); } for(i=0; i< 5; i++) { for(j=0;j<5;j++) { mptr[j+i*siz] = w[j]*w[i]; } } return mptr; } float * read_mask(size, fname, no_norm) int * size; char * fname; int no_norm; { FILE * maskfile; int i,j,masksize; float *mptr, total; maskfile = rle_open_f( progname, fname, "r" ); fscanf(maskfile, "%d", &masksize); mptr = (float *) malloc( sizeof(float) * masksize * masksize); total = 0.0; for (i=0; i< masksize; i++) for (j=0; j< masksize; j++) { fscanf(maskfile, "%f", &(mptr[j+i*masksize])); total += mptr[j+i*masksize]; } if (!no_norm) { if (total <= 0.0) { fprintf(stderr,"%s: Input mask total not valid\n", progname); exit(1); } /* normalize the mask */ for (i=0; i< masksize; i++) for (j=0; j< masksize; j++) { mptr[j+i*masksize] /= total; } } *size = masksize; if ( maskfile != stdin ) fclose( maskfile ); return mptr; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.