/* * This software is copyrighted as noted below. It may be freely copied, * modified, and redistributed, provided that the copyright notice is * preserved on all copies. * * There is no warranty or other guarantee of fitness for this software, * it is provided solely "as is". Bug reports or fixes may be sent * to the author, who may or may not act on them as he desires. * * You may not include this software in a program or other software product * without supplying the source, or without informing the end-user that the * source is available for no extra charge. * * If you modify this software, you should include a notice giving the * name of the person performing the modification, the date of modification, * and the reason for such modification. */ /* * slowzoom.c - perform a better zoom ( but slower ). * * Author: Raul Rivero * Mathematics Dept. * University of Oviedo * Date: Mon 5 Jul 1993 * Copyright (c) 1993, Raul Rivero * */ /* * This code is strongly based on the "Filtered Image Rescaling", by Dale * Schumacher [Graphics Gems III, 8-16]. The filter used is "the bell". * * The core is the same but some parts have been re-estructure. This * code doesn't try to be clear, it tries to be efficient. * * Thanks, Dale!. * * Dale Schumacher * Minnesota * ( dal@syntel.mn.org ) * */ #include #include #define bell_support (1.5) typedef struct { int pixel; double weight; }CONTRIB; typedef struct { int n; CONTRIB *p; }CLIST; /* * Functions prototype. */ double bell_filter( #ifdef USE_PROTOTYPES double #endif ); CLIST * calculate_filter( #ifdef USE_PROTOTYPES register, register, double #endif ); byte * slow_zoom( #ifdef USE_PROTOTYPES register byte *, int, int, int, int, CLIST *, CLIST * #endif ); extern int LUGverbose; slow_adjust_bitmap( inbitmap, outbitmap, newx, newy ) bitmap_hdr *inbitmap, *outbitmap; int newx, newy; { int i; CLIST *xcontrib, *ycontrib; if ( inbitmap->magic != LUGUSED ) error( 19 ); /* Correct values ? */ if ( newx < 1 || newy < 1 ) error( 22 ); /* If the same proportions ... */ if ( newx == inbitmap->xsize && newy == inbitmap->ysize ) { copy_bitmap( inbitmap, outbitmap ); return 0; } /* * Ok, we need a resampling. But we accept only true * color or gray scaled images. */ if ( inbitmap->depth < 24 && !isagrayscaled(inbitmap) ) error( 23 ); /* Fill the new header */ outbitmap->magic = LUGUSED; outbitmap->xsize = newx; outbitmap->ysize = newy; outbitmap->depth = inbitmap->depth; outbitmap->colors = inbitmap->colors; /* If it's a mapped image, copy the cmap */ if ( outbitmap->depth < 24 ) outbitmap->cmap = (byte *) create_bw_pallete(); /* * All preprocess do it. Let's go !. */ /* Get the horizontal mask */ VPRINTF( stderr, "Calculating masks: horizontal" ); VFLUSH( stderr ); xcontrib = calculate_filter( inbitmap->xsize, newx, bell_support ); /* Get the vertical mask */ VPRINTF( stderr, ", vertical" ); VFLUSH( stderr ); ycontrib = calculate_filter( inbitmap->ysize, newy, bell_support ); VPRINTF( stderr, ". Done.\n"); /* Zooms each component ( and applies the filter ) */ VPRINTF( stderr, "Zoooming R" ); VFLUSH( stderr ); outbitmap->r = slow_zoom( inbitmap->r, inbitmap->xsize, inbitmap->ysize, newx, newy, xcontrib, ycontrib ); if ( outbitmap->depth > 8 ) { VPRINTF( stderr, "Zoooming G" ); VFLUSH( stderr ); outbitmap->g = slow_zoom( inbitmap->g, inbitmap->xsize, inbitmap->ysize, newx, newy, xcontrib, ycontrib ); VPRINTF( stderr, "Zoooming B" ); VFLUSH( stderr ); outbitmap->b = slow_zoom( inbitmap->b, inbitmap->xsize, inbitmap->ysize, newx, newy, xcontrib, ycontrib ); } /* Free the masks */ for ( i = 0; i < newx; i++ ) Free( xcontrib[i].p ); for ( i = 0; i < newy; i++ ) Free( ycontrib[i].p ); Free(xcontrib); Free(ycontrib); } double bell_filter(t) /* box (*) box (*) box */ double t; { if ( t < 0 ) t = -t; if ( t < .5 ) return( .75 - (t * t) ); if ( t < 1.5 ) { t -= 1.5; return( .5 * (t * t) ); } return( 0. ); } CLIST * calculate_filter( oldsize, newsize, filter_width ) register oldsize, newsize; double filter_width; { register int i, j, n, k; double scale, fscale; double weight; double left, center, right; double aux; CLIST *contrib; int oldsize2 = oldsize << 1; int contributor_size; /* Get the zoom scaled values */ scale = (double) newsize / (double) oldsize; fscale = 1.0 / scale; /* Pre-calculate filter contributions for a row */ contrib = (CLIST *) Malloc( newsize * sizeof(CLIST) ); if( scale < 1.0 ) { /* * We are minification the current axis. */ /* Scale the filter */ filter_width *= fscale; /* Get the memory size for each contributor */ contributor_size = (int) (filter_width * 2 + 2) * sizeof(CONTRIB); /* Pre-calculate ... */ for( i = 0; i < newsize; i++ ) { contrib[i].p = (CONTRIB *) Malloc( contributor_size ); /* Build the borders ... */ center = (double) i * fscale; aux = center - filter_width; left = CEILING( aux ); aux = center + filter_width; right = FLOOR( aux ); /* ... and build the filter. */ for( j = left; j <= right; j++ ) { /* Get the current weight */ weight = center - (double) j; weight = bell_filter(weight * scale) * scale; if( j < 0 ) { n = -j; }else if( j >= oldsize ) { n = oldsize2 - j - 1; }else { n = j; } k = contrib[i].n++; /*** fprintf( stdout, "%3d-%3d %3d-%3d\n", newsize, i, (int) (filter_width * 2 + 1), k ); ***/ contrib[i].p[k].pixel = n; contrib[i].p[k].weight = weight; } } }else { /* * We are magnification the current axis. */ /* Get the memory size for each contributor */ contributor_size = (int) (filter_width * 2 + 2) * sizeof(CONTRIB); /* Pre-calculate ... */ for( i = 0; i < newsize; i++ ) { contrib[i].p = (CONTRIB *) Malloc( contributor_size ); /* Build the borders ... */ center = (double) i * fscale; aux = center - filter_width; left = CEILING( aux ); aux = center + filter_width; right = FLOOR( aux ); /* ... and build the filter. */ for( j = left; j <= right; j++ ) { weight = center - (double) j; weight = bell_filter( weight ); if( j < 0 ) { n = -j; }else if( j >= oldsize ) { n = oldsize2 - j - 1; }else { n = j; } k = contrib[i].n++; contrib[i].p[k].pixel = n; contrib[i].p[k].weight = weight; } } } return contrib; } byte * slow_zoom( base, oldx, oldy, newx, newy, xcontrib, ycontrib ) register byte *base; int oldx, oldy, newx, newy; CLIST *xcontrib, *ycontrib; { int i, j, k; register byte *tmpixel, *outpixel; byte *tmp; byte *out; double weight; /* * First, we resample horizontally so we need a * temporary buffer to store it. */ tmpixel = tmp = (byte *) Malloc( newx * oldy ); /* * Apply the [hozizontal] filter to zoom horizontally. */ VPRINTF( stderr, ", horizontally" ); VFLUSH( stderr ); for( i = 0; i < oldy; i++ ) { for( j = 0; j < newx; j++) { weight = 0.0; for( k = 0; k < xcontrib[j].n; k++) { weight += base[xcontrib[j].p[k].pixel] * xcontrib[j].p[k].weight; } *tmpixel++ = CORRECT( weight ); } base += oldx; } /* Get memory fo our output zoomed image */ out = (byte *) Malloc( newx * newy ); /* * Apply the [vertical] filter to zoom vertically. */ VPRINTF( stderr, ", vertically" ); VFLUSH( stderr ); tmpixel = tmp; for( i = 0; i < newx; i++, tmpixel++ ) { outpixel = out + i; for( j = 0; j < newy; j++ ) { weight = 0.0; for( k = 0; k < ycontrib[j].n; k++ ) { weight += *(tmpixel + newx*ycontrib[j].p[k].pixel) * ycontrib[j].p[k].weight; } *outpixel = CORRECT( weight ); outpixel += newx; } } VPRINTF( stderr, ", done\n" ); /* Free the auxiliar buffer */ Free( tmp ); return out; }