📄 filter_rcg.c
字号:
/* * Filtered Image Rescaling * * by Dale Schumacher * *//* Additional changes by Ray Gardener, Daylon Graphics Ltd. December 4, 1999 Summary: - Horizontal filter contributions are calculated on the fly, as each column is mapped from src to dst image. This lets us omit having to allocate a temporary full horizontal stretch of the src image. - If none of the src pixels within a sampling region differ, then the output pixel is forced to equal (any of) the source pixel. This ensures that filters do not corrupt areas of constant color. - Filter weight contribution results, after summing, are rounded to the nearest pixel color value instead of being casted to Pixel (usually an int or char). Otherwise, artifacting occurs. - All memory allocations checked for failure; zoom() returns error code. new_image() returns NULL if unable to allocate pixel storage, even if Image struct can be allocated. Some assertions added. - load_image(), save_image() take filenames, not file handles. - TGA bitmap format available. If you want to add a filetype, extend the gImageHandlers array, and factor in your load_image_xxx() and save_image_xxx() functions. Search for string 'add your' to find appropriate code locations. - The 'input' and 'output' command-line arguments do not have to specify .bm files; any supported filetype is okay. - Added implementation of getopt() if compiling under Windows.*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <malloc.h>#include <math.h>#include "GraphicsGems.h"static char _Program[] = "fzoom";static char _Version[] = "0.30";static char _Copyright[] = "Public Domain 1991 by Dale Schumacher. Mods by Ray Gardener";#ifndef EXIT_SUCCESS#define EXIT_SUCCESS (0)#define EXIT_FAILURE (1)#endif/* M_PI was not in gems header ?? */#ifndef M_PI #define M_PI 3.14159265359#endif#ifdef WIN32/* getopt() - Parses command line (argv) looking for switch chars Returns option flag char if option found. Returns EOF if end of arglist or non-flag arg reached. Returns 0 if option arg doesn't match any switch. rcg: No idea if this fully implements getopt()'s API; just provided so main() would compile. */int optind;char *optarg;intgetopt(argc, argv, pszSwitches)int argc;char* argv[];char* pszSwitches;{ static int n = 1; char* pszToken; char* arg = "- "; char* szSwitches; if(n >= argc || argv[n][0] != '-') { optind = n; n = 1; return EOF; } szSwitches = _strdup(pszSwitches); if(szSwitches == NULL) return EOF; /* Compare argv[n] with acceptable switches */ pszToken = strtok(szSwitches, ":"); if(pszToken == NULL) { free(szSwitches); return EOF; } while(pszToken) { if(strlen(argv[n]) > 1 && argv[n][0] == '-') { arg[1] = pszToken[0]; if(memcmp(arg, argv[n], 2) == 0) { optind = n++; optarg = argv[n++]; free(szSwitches); return arg[1]; } } pszToken = strtok(NULL, ":"); } n++; free(szSwitches); return 0;}#endif // WIN32typedef unsigned char Pixel;/* Note: if you define Pixel to something bigger than char, you may need to add more support in bitmap file I/O functions.*/typedef struct{ int xsize; /* horizontal size of the image in Pixels */ int ysize; /* vertical size of the image in Pixels */ Pixel * data; /* pointer to first scanline of image */ int span; /* byte offset between two scanlines */} Image;#define WHITE_PIXEL (255)#define BLACK_PIXEL (0)/* * generic image access and i/o support routines */static char *next_token(f)FILE *f;{ static char delim[] = " \t\r\n"; static char *t = NULL; static char lnbuf[256]; char *p; while(t == NULL) { /* nothing in the buffer */ if(fgets(lnbuf, sizeof(lnbuf), f)) { /* read a line */ if(p = strchr(lnbuf, '#')) { /* clip any comment */ *p = '\0'; } t = strtok(lnbuf, delim); /* get first token */ } else { return(NULL); } } p = t; t = strtok((char *)NULL, delim); /* get next token */ return(p);}Pixelget_pixel(image, x, y)Image *image;int x, y;{ static Image *im = NULL; static int yy = -1; static Pixel *p = NULL; if((x < 0) || (x >= image->xsize) || (y < 0) || (y >= image->ysize)) { return(0); } if((im != image) || (yy != y)) { im = image; yy = y; p = image->data + (y * image->span); } return(p[x]);}voidget_row(row, image, y)Pixel *row;Image *image;int y;{ if((y < 0) || (y >= image->ysize)) { return; } memcpy(row, image->data + (y * image->span), (sizeof(Pixel) * image->xsize));}voidget_column(column, image, x)Pixel *column;Image *image;int x;{ int i, d; Pixel *p; if((x < 0) || (x >= image->xsize)) { return; } d = image->span; for(i = image->ysize, p = image->data + x; i-- > 0; p += d) { *column++ = *p; }}Pixelput_pixel(image, x, y, data)Image *image;int x, y;Pixel data;{ static Image *im = NULL; static int yy = -1; static Pixel *p = NULL; if((x < 0) || (x >= image->xsize) || (y < 0) || (y >= image->ysize)) { return(0); } if((im != image) || (yy != y)) { im = image; yy = y; p = image->data + (y * image->span); } return(p[x] = data);}Image *new_image(xsize, ysize) /* create a blank image */int xsize, ysize;{ Image *image; ASSERT(xsize > 0 && ysize > 0); if(image = (Image *)malloc(sizeof(Image))) { if(image->data = (Pixel *)calloc(ysize, xsize)) { image->xsize = xsize; image->ysize = ysize; image->span = xsize; } else { free(image); image = NULL; } } return image;}voidfree_image(image)Image *image;{ ASSERT(image && image->data); free(image->data); free(image);}/* fileextension() Returns type of file based on its name. Returns the empty string if filename has no extension */char*fileextension(f)char* f;{ /* Get a filename's extension string. */ int i; for(i = strlen(f) - 1; i > 0; i--) { if(f[i] == '.') return f + i + 1; } /* No extension. Return the end of the string, which effectively returns a null string. */ return f + strlen(f);}/* add your filetype loaders and savers here *//* -- PXM bitmap support------------------------------------------------ */Image *load_image_bm(f) /* read image from bm file */FILE *f;{ char *p; int width, height; Image *image; if(((p = next_token(f)) && (strcmp(p, "Bm") == 0)) && ((p = next_token(f)) && ((width = atoi(p)) > 0)) && ((p = next_token(f)) && ((height = atoi(p)) > 0)) && ((p = next_token(f)) && (strcmp(p, "8") == 0)) && (image = new_image(width, height)) && (fread(image->data, (size_t)width, (size_t)height, f) == (size_t)height)) { return(image); /* load successful */ } else { return(NULL); /* load failed */ }}intsave_image_bm(f, image) /* write image to bm file */FILE *f;Image *image;{ fprintf(f, "Bm # PXM 8-bit greyscale image\x0A"); fprintf(f, "%d %d 8 # width height depth\x0A", image->xsize, image->ysize); if(fwrite(image->data, (size_t)image->xsize, (size_t)image->ysize, f) == (size_t)image->ysize) { return(0); /* save successful */ } else { return(-1); /* save failed */ }}/* -- TGA bitmap support------------------------------------------------ */typedef struct{ unsigned char lsb, msb;} DoubleByte;#define INT_TO_DB(n, db) { (db).lsb = (unsigned char)((n) & 0xFF);\ (db).msb = (unsigned char)((n) >> 8); }#define DB_TO_INT(db) (((int)((db).msb) << 8) + (db).lsb)typedef struct{ unsigned char IDfieldLen; unsigned char colorMapType; unsigned char imageType; DoubleByte ColorMapOrigin; DoubleByte ColorMapLen; unsigned char ColorMapEntrySize; /* no. of bits */ DoubleByte Xorigin; DoubleByte Yorigin; DoubleByte Width; DoubleByte Height; unsigned char bpp; unsigned char descriptor;} TGAheader;intsave_image_tga(f, image) /* save image to TGA file */FILE* f;Image* image;{ int x, y; int n, j; TGAheader header; boolean bOK = TRUE; /* assume success */ /* Grayscale images only. */ ASSERT(sizeof(Pixel) == 1); /* Write header */ memset(&header, 0, sizeof(header)); header.colorMapType = 1; header.imageType = 1; INT_TO_DB(256, header.ColorMapLen); header.ColorMapEntrySize = 24; INT_TO_DB(image->xsize, header.Width); INT_TO_DB(image->ysize, header.Height); header.bpp = 8; header.descriptor = 0x20; /* top down */ bOK = (fwrite(&header, sizeof(header), 1, f) == 1); /* Write palette. */ for(n = 0; n < 256 && bOK; n++) { for(j = 0; j < 3 && bOK; j++) bOK = fputc(n, f) != EOF; } /* Write pixel index values. */ for(y = 0; y < image->ysize && bOK; y++) { for(x = 0; x < image->xsize && bOK; x++) bOK = (EOF != fputc(get_pixel(image, x, y), f)); } return bOK ? 0 : -1;} /* save_image_tga */Image *load_image_tga(f) /* read image from TGA file */FILE *f;{ Image* image = NULL; boolean bTopDown; boolean bOK = FALSE; TGAheader header; int width, height, c, x, y, yy; /* Grayscale images only. */ ASSERT(sizeof(Pixel) == 1); if(fread(&header, sizeof(header), 1, f) == 1 && header.bpp == 8) { bTopDown = (header.descriptor & 0x20); width = DB_TO_INT(header.Width); height = DB_TO_INT(header.Height); image = new_image(width, height); if(image != NULL) { /* Skip palette */ bOK = 0 == fseek(f, DB_TO_INT(header.ColorMapLen) * header.ColorMapEntrySize/8, SEEK_CUR); /* Read pixels */ for(y = 0; y < height && bOK; y++) { yy = bTopDown ? y : (height-1) - y; for(x = 0; x < width && bOK; x++) { bOK = ((c = fgetc(f)) != EOF); if(bOK) put_pixel(image, x, yy, (Pixel)c); } } } } if(!bOK && image != NULL) { free_image(image); image = NULL; } return image;}/* -- End TGA bitmap support ------------------------------------------- *//* ImageHandler stuff. An ImageHandler stores an image file's extension, and pointers to functions that read and write the image format.*/typedef struct{ char* filetype; Image* (*reader)(); int (*writer)();} ImageHandler;ImageHandler gImageHandlers[] ={ { "bm", load_image_bm, save_image_bm }, { "tga", load_image_tga, save_image_tga } /* add your image handlers here */};/* find_imagehandler() Given a filename, return an image handler for it. Return NULL if no handler available.*/ImageHandler*find_imagehandler(f)char* f;{ int i; for(i = 0; i < sizeof(gImageHandlers) / sizeof(gImageHandlers[0]); i++) { if(stricmp(gImageHandlers[i].filetype, fileextension(f)) == 0) return &gImageHandlers[i]; } return NULL;}/* load_image() Given a filename, hands off to appropriate image loader. Returns pointer to loaded Image, NULL if it can't.*/Image *load_image(f) /* read image from file */char *f;{ Image *image; FILE* fp; ImageHandler* handler; ASSERT(f); fp = fopen(f, "rb"); if(fp == NULL) return NULL; if(handler = find_imagehandler(f)) image = handler->reader(fp); fclose(fp); return image;}/* save_image() Given a filename and an Image, hands off to appropriate image saver. Returns -1 on error, 0 on success.*/intsave_image(f, image)char *f;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -