/* * GIMP CVS: "|Id: sharpen.c,v 1.23.2.1 2001/01/12 13:15:10 neo Exp |" * * Sharpen filters for The GIMP -- an image manipulation program * * Copyright 1997-1998 Michael Sweet (mike@easysw.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA * * Contents: * * sharpen() - Sharpen an image using a median filter. * rgb_filter() - Sharpen RGB pixels. * * Revision History: * * See GIMP ChangeLog */ #include #include #include "sharpen.h" #define new(ctype, ccount) calloc(ccount, sizeof(ctype)) static void compute_luts (int sharpen_percent, int *pos_lut, int *neg_lut ) { int i; /* Looping var */ int fact; /* 1 - sharpness */ fact = 100 - sharpen_percent; if (fact < 1) fact = 1; for (i = 0; i < 256; i ++) { pos_lut[i] = (800 * i) / fact; neg_lut[i] = (4 + pos_lut[i] - (i << 3)) >> 3; }; } /** 'rgb_filter()' - Sharpen RGB pixels. **/ static void rgb_filter (int width, /* I - Width of line in pixels */ int *pos_lut, int *neg_lut, unsigned char *src, /* I - Source line */ unsigned char *dst, /* O - Destination line */ long int *neg0, /* I - Top negative coefficient line */ long int *neg1, /* I - Middle negative coefficient line */ long int *neg2) /* I - Bottom negative coefficient line */ { long int pixel; /* New pixel value */ *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; width -= 2; while (width > 0) { pixel = (pos_lut[*src++] - neg0[-3] - neg0[0] - neg0[3] - neg1[-3] - neg1[3] - neg2[-3] - neg2[0] - neg2[3]); pixel = (pixel + 4) >> 3; if (pixel < 0) *dst++ = 0; else if (pixel < 255) *dst++ = pixel; else *dst++ = 255; pixel = (pos_lut[*src++] - neg0[-2] - neg0[1] - neg0[4] - neg1[-2] - neg1[4] - neg2[-2] - neg2[1] - neg2[4]); pixel = (pixel + 4) >> 3; if (pixel < 0) *dst++ = 0; else if (pixel < 255) *dst++ = pixel; else *dst++ = 255; pixel = (pos_lut[*src++] - neg0[-1] - neg0[2] - neg0[5] - neg1[-1] - neg1[5] - neg2[-1] - neg2[2] - neg2[5]); pixel = (pixel + 4) >> 3; if (pixel < 0) *dst++ = 0; else if (pixel < 255) *dst++ = pixel; else *dst++ = 255; neg0 += 3; neg1 += 3; neg2 += 3; width --; }; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; } /** 'sharpen()' - Sharpen an image using a convolution filter. **/ void sharpen(int width, int height, unsigned char *src_region, unsigned char *dest_region, int sharpen_percent ) { unsigned char *src_rows[4], /* Source pixel rows */ *src_ptr, /* Current source pixel */ *dst_row; /* Destination pixel row */ long int *neg_rows[4], /* Negative coefficient rows */ *neg_ptr; /* Current negative coefficient */ int i, /* Looping vars */ y, /* Current location in image */ row, /* Current row in src_rows */ count, /* Current number of filled src_rows */ pitch; /* Byte width of the image */ int img_bpp=3; /* Bytes-per-pixel in image */ int neg_lut[256]; /* Negative coefficient LUT */ int pos_lut[256]; /* Positive coefficient LUT */ compute_luts (sharpen_percent,pos_lut,neg_lut); pitch = width * img_bpp; for (row = 0; row < 4; row ++) { src_rows[row] = new (unsigned char, pitch); neg_rows[row] = new (long int, pitch); } dst_row = new (unsigned char, pitch); /** Pre-load the first row for the filter... **/ memcpy(src_rows[0], src_region, pitch); for (i = pitch, src_ptr = src_rows[0], neg_ptr = neg_rows[0]; i > 0; i --, src_ptr ++, neg_ptr ++) *neg_ptr = neg_lut[*src_ptr]; row = 1; count = 1; /** Sharpen... **/ for (y = 0; y < height; y ++) { /** Load the next pixel row... **/ if ((y + 1) < height) { /** Check to see if our src_rows[] array is overflowing yet... **/ if (count >= 3) count --; /** Grab the next row... **/ memcpy(src_rows[row], (src_region + pitch*(y+1)), pitch); for (i = pitch, src_ptr = src_rows[row], neg_ptr = neg_rows[row]; i > 0; i --, src_ptr ++, neg_ptr ++) *neg_ptr = neg_lut[*src_ptr]; count ++; row = (row + 1) & 3; } else { /** No more pixels at the bottom... Drop the oldest samples... **/ count --; } /** Now sharpen pixels and save the results... **/ if (count == 3) { rgb_filter(width, pos_lut, neg_lut, src_rows[(row + 2) & 3], dst_row, neg_rows[(row + 1) & 3] + img_bpp, neg_rows[(row + 2) & 3] + img_bpp, neg_rows[(row + 3) & 3] + img_bpp); /** Set the row... **/ memcpy((dest_region + pitch*y), dst_row, pitch); } else if (count == 2) { if (y == 0) /* first row */ memcpy((dest_region), src_rows[0], pitch); else /* last row */ memcpy((dest_region + pitch*(y)), src_rows[(height-1)&3], pitch); } } /* for */ /** OK, we're done. Free all memory used... **/ for (row = 0; row < 4; row ++) { free (src_rows[row]); free (neg_rows[row]); } free (dst_row); }