📄 filter_rcg.c
字号:
Image* image;{ FILE* fp; ImageHandler* handler; int nRet = -1; /* assume failure */ ASSERT(f && image); fp = fopen(f, "wb"); if(fp != NULL) { if(handler = find_imagehandler(f)) nRet = handler->writer(fp, image); fclose(fp); } return nRet;}/* * filter function definitions */#define filter_support (1.0)doublefilter(t)double t;{ /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */ if(t < 0.0) t = -t; if(t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0); return(0.0);}#define box_support (0.5)doublebox_filter(t)double t;{ if((t > -0.5) && (t <= 0.5)) return(1.0); return(0.0);}#define triangle_support (1.0)doubletriangle_filter(t)double t;{ if(t < 0.0) t = -t; if(t < 1.0) return(1.0 - t); return(0.0);}#define bell_support (1.5)doublebell_filter(t) /* box (*) box (*) box */double t;{ if(t < 0) t = -t; if(t < .5) return(.75 - (t * t)); if(t < 1.5) { t = (t - 1.5); return(.5 * (t * t)); } return(0.0);}#define B_spline_support (2.0)doubleB_spline_filter(t) /* box (*) box (*) box (*) box */double t;{ double tt; if(t < 0) t = -t; if(t < 1) { tt = t * t; return((.5 * tt * t) - tt + (2.0 / 3.0)); } else if(t < 2) { t = 2 - t; return((1.0 / 6.0) * (t * t * t)); } return(0.0);}doublesinc(x)double x;{ x *= M_PI; if(x != 0) return(sin(x) / x); return(1.0);}#define Lanczos3_support (3.0)doubleLanczos3_filter(t)double t;{ if(t < 0) t = -t; if(t < 3.0) return(sinc(t) * sinc(t/3.0)); return(0.0);}#define Mitchell_support (2.0)#define B (1.0 / 3.0)#define C (1.0 / 3.0)doubleMitchell_filter(t)double t;{ double tt; tt = t * t; if(t < 0) t = -t; if(t < 1.0) { t = (((12.0 - 9.0 * B - 6.0 * C) * (t * tt)) + ((-18.0 + 12.0 * B + 6.0 * C) * tt) + (6.0 - 2 * B)); return(t / 6.0); } else if(t < 2.0) { t = (((-1.0 * B - 6.0 * C) * (t * tt)) + ((6.0 * B + 30.0 * C) * tt) + ((-12.0 * B - 48.0 * C) * t) + (8.0 * B + 24 * C)); return(t / 6.0); } return(0.0);}/* * image rescaling routine */typedef struct { int pixel; double weight;} CONTRIB;typedef struct { int n; /* number of contributors */ CONTRIB *p; /* pointer to list of contributions */} CLIST;CLIST *contrib; /* array of contribution lists *//* roundcloser() Round an FP value to its closest int representation. General routine; ideally belongs in general math lib file.*/ int roundcloser(double d){ /* Untested potential one-liner, but smacks of call overhead */ /* return fabs(ceil(d)-d) <= 0.5 ? ceil(d) : floor(d); */ /* Untested potential optimized ceil() usage *//* double cd = ceil(d); int ncd = (int)cd; if(fabs(cd - d) > 0.5) ncd--; return ncd;*/ /* Version that uses no function calls at all. */ int n = (int) d; double diff = d - (double)n; if(diff < 0) diff = -diff; if(diff >= 0.5) { if(d < 0) n--; else n++; } return n;} /* roundcloser *//* calc_x_contrib() Calculates the filter weights for a single target column. contribX->p must be freed afterwards. Returns -1 if error, 0 otherwise.*/int calc_x_contrib(contribX, xscale, fwidth, dstwidth, srcwidth, filterf, i)CLIST* contribX; /* Receiver of contrib info */double xscale; /* Horizontal zooming scale */double fwidth; /* Filter sampling width */int dstwidth; /* Target bitmap width */int srcwidth; /* Source bitmap width */double (*filterf)(double); /* Filter proc */int i; /* Pixel column in source bitmap being processed */{ double width; double fscale; double center, left, right; double weight; int j, k, n; if(xscale < 1.0) { /* Shrinking image */ width = fwidth / xscale; fscale = 1.0 / xscale; contribX->n = 0; contribX->p = (CONTRIB *)calloc((int) (width * 2 + 1), sizeof(CONTRIB)); if(contribX->p == NULL) return -1; center = (double) i / xscale; left = ceil(center - width); right = floor(center + width); for(j = (int)left; j <= right; ++j) { weight = center - (double) j; weight = (*filterf)(weight / fscale) / fscale; if(j < 0) n = -j; else if(j >= srcwidth) n = (srcwidth - j) + srcwidth - 1; else n = j; k = contribX->n++; contribX->p[k].pixel = n; contribX->p[k].weight = weight; } } else { /* Expanding image */ contribX->n = 0; contribX->p = (CONTRIB *)calloc((int) (fwidth * 2 + 1), sizeof(CONTRIB)); if(contribX->p == NULL) return -1; center = (double) i / xscale; left = ceil(center - fwidth); right = floor(center + fwidth); for(j = (int)left; j <= right; ++j) { weight = center - (double) j; weight = (*filterf)(weight); if(j < 0) { n = -j; } else if(j >= srcwidth) { n = (srcwidth - j) + srcwidth - 1; } else { n = j; } k = contribX->n++; contribX->p[k].pixel = n; contribX->p[k].weight = weight; } } return 0;} /* calc_x_contrib *//* zoom() Resizes bitmaps while resampling them. Returns -1 if error, 0 if success.*/intzoom(dst, src, filterf, fwidth)Image* dst;Image* src;double (*filterf)(double);double fwidth;{ Pixel* tmp; double xscale, yscale; /* zoom scale factors */ int xx; int i, j, k; /* loop variables */ int n; /* pixel number */ double center, left, right; /* filter calculation variables */ double width, fscale, weight; /* filter calculation variables */ Pixel pel, pel2; int bPelDelta; CLIST *contribY; /* array of contribution lists */ CLIST contribX; int nRet = -1; /* create intermediate column to hold horizontal dst column zoom */ tmp = (Pixel*)malloc(src->ysize * sizeof(Pixel)); if(tmp == NULL) return 0; xscale = (double) dst->xsize / (double) src->xsize; /* Build y weights */ /* pre-calculate filter contributions for a column */ contribY = (CLIST *)calloc(dst->ysize, sizeof(CLIST)); if(contribY == NULL) { free(tmp); return -1; } yscale = (double) dst->ysize / (double) src->ysize; if(yscale < 1.0) { width = fwidth / yscale; fscale = 1.0 / yscale; for(i = 0; i < dst->ysize; ++i) { contribY[i].n = 0; contribY[i].p = (CONTRIB *)calloc((int) (width * 2 + 1), sizeof(CONTRIB)); if(contribY[i].p == NULL) { free(tmp); free(contribY); return -1; } center = (double) i / yscale; left = ceil(center - width); right = floor(center + width); for(j = (int)left; j <= right; ++j) { weight = center - (double) j; weight = (*filterf)(weight / fscale) / fscale; if(j < 0) { n = -j; } else if(j >= src->ysize) { n = (src->ysize - j) + src->ysize - 1; } else { n = j; } k = contribY[i].n++; contribY[i].p[k].pixel = n; contribY[i].p[k].weight = weight; } } } else { for(i = 0; i < dst->ysize; ++i) { contribY[i].n = 0; contribY[i].p = (CONTRIB *)calloc((int) (fwidth * 2 + 1), sizeof(CONTRIB)); if(contribY[i].p == NULL) { free(tmp); free(contribY); return -1; } center = (double) i / yscale; left = ceil(center - fwidth); right = floor(center + fwidth); for(j = (int)left; j <= right; ++j) { weight = center - (double) j; weight = (*filterf)(weight); if(j < 0) { n = -j; } else if(j >= src->ysize) { n = (src->ysize - j) + src->ysize - 1; } else { n = j; } k = contribY[i].n++; contribY[i].p[k].pixel = n; contribY[i].p[k].weight = weight; } } } for(xx = 0; xx < dst->xsize; xx++) { if(0 != calc_x_contrib(&contribX, xscale, fwidth, dst->xsize, src->xsize, filterf, xx)) { goto __zoom_cleanup; } /* Apply horz filter to make dst column in tmp. */ for(k = 0; k < src->ysize; ++k) { weight = 0.0; bPelDelta = FALSE; pel = get_pixel(src, contribX.p[0].pixel, k); for(j = 0; j < contribX.n; ++j) { pel2 = get_pixel(src, contribX.p[j].pixel, k); if(pel2 != pel) bPelDelta = TRUE; weight += pel2 * contribX.p[j].weight; } weight = bPelDelta ? roundcloser(weight) : pel; tmp[k] = (Pixel)CLAMP(weight, BLACK_PIXEL, WHITE_PIXEL); } /* next row in temp column */ free(contribX.p); /* The temp column has been built. Now stretch it vertically into dst column. */ for(i = 0; i < dst->ysize; ++i) { weight = 0.0; bPelDelta = FALSE; pel = tmp[contribY[i].p[0].pixel]; for(j = 0; j < contribY[i].n; ++j) { pel2 = tmp[contribY[i].p[j].pixel]; if(pel2 != pel) bPelDelta = TRUE; weight += pel2 * contribY[i].p[j].weight; } weight = bPelDelta ? roundcloser(weight) : pel; put_pixel(dst, xx, i, (Pixel)CLAMP(weight, BLACK_PIXEL, WHITE_PIXEL)); } /* next dst row */ } /* next dst column */ nRet = 0; /* success */__zoom_cleanup: free(tmp); /* free the memory allocated for vertical filter weights */ for(i = 0; i < dst->ysize; ++i) free(contribY[i].p); free(contribY); return nRet;} /* zoom *//* * command line interface */voidusage(){ fprintf(stderr, "usage: %s [-options] input output\n", _Program); fprintf(stderr, "\options:\n\ -x xsize output x size\n\ -y ysize output y size\n\ -f filter filter type\n\{b=box, t=triangle, q=bell, B=B-spline, h=hermite, l=Lanczos3, m=Mitchell}\n\ input, output files to read/write. Use BM or TGA extension.\n\"); exit(1);}voidbanner(){ printf("%s v%s -- %s\n", _Program, _Version, _Copyright);}intmain(argc, argv)int argc;char *argv[];{ register int c;#ifndef WIN32 extern int optind; extern char *optarg;#endif int xsize = 0, ysize = 0; double (*f)() = filter; double s = filter_support; char *dstfile, *srcfile; Image *dst, *src; while((c = getopt(argc, argv, "x:y:f:V")) != EOF) { switch(c) { case 'x': xsize = atoi(optarg); break; case 'y': ysize = atoi(optarg); break; case 'f': switch(*optarg) { case 'b': f=box_filter; s=box_support; break; case 't': f=triangle_filter; s=triangle_support; break; case 'q': f=bell_filter; s=bell_support; break; case 'B': f=B_spline_filter; s=B_spline_support; break; case 'h': f=filter; s=filter_support; break; case 'l': f=Lanczos3_filter; s=Lanczos3_support; break; case 'm': f=Mitchell_filter; s=Mitchell_support; break; default: usage(); } break; case 'V': banner(); exit(EXIT_SUCCESS); case '?': usage(); default: usage(); } } if((argc - optind) != 2) usage(); srcfile = argv[optind]; dstfile = argv[optind + 1]; if((src = load_image(srcfile)) == NULL) { fprintf(stderr, "%s: can't load source image '%s'\n", _Program, srcfile); exit(EXIT_FAILURE); } if(xsize <= 0) xsize = src->xsize; if(ysize <= 0) ysize = src->ysize; dst = new_image(xsize, ysize); if(zoom(dst, src, f, s) != 0) { fprintf(stderr, "%s: can't process image '%s'\n", _Program, srcfile); exit(EXIT_FAILURE); } else { if(save_image(dstfile, dst) != 0) { fprintf(stderr, "%s: can't save destination image '%s'\n", _Program, dstfile); exit(EXIT_FAILURE); } } exit(EXIT_SUCCESS); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -