- Main Page
- Data Structures
- Files

- File List

# E:/DevIL/src-ILU/src/ilu_filter_rcg.c

    00001 //-----------------------------------------------------------------------------
    00002 //
    00003 // ImageLib Utility Sources
    00004 // Copyright (C) 2000-2002 by Denton Woods
    00005 // Last modified: 10/12/2001 <--Y2K Compliant! =]
    00006 //
    00007 // Filename: src-ILU/src/ilu_filter_rcg.c
    00008 //
    00009 // Description: Scales an image.  Based on the Graphic Gems III source.
    00010 //
    00011 //-----------------------------------------------------------------------------
    00012
    00013
    00014 /*
    00015  *              Filtered Image Rescaling
    00016  *
    00017  *                by Dale Schumacher
    00018  *
    00019  */
    00020
    00021 /*
    00022         Additional changes by Ray Gardener, Daylon Graphics Ltd.
    00023         December 4, 1999
    00024
    00025         Summary:
    00026
    00027                 - Horizontal filter contributions are calculated on the fly,
    00028                   as each column is mapped from src to dst image. This lets
    00029                   us omit having to allocate a temporary full horizontal stretch
    00030                   of the src image.
    00031
    00032                 - If none of the src pixels within a sampling region differ,
    00033                   then the output pixel is forced to equal (any of) the source pixel.
    00034                   This ensures that filters do not corrupt areas of constant color.
    00035
    00036                 - Filter weight contribution results, after summing, are
    00037                   rounded to the nearest pixel color value instead of
    00038                   being casted to ILubyte (usually an int or char). Otherwise,
    00039                   artifacting occurs.
    00040
    00041                 - All memory allocations checked for failure; zoom() returns
    00042                   error code. new_image() returns NULL if unable to allocate
    00043                   pixel storage, even if Image struct can be allocated.
    00044                   Some assertions added.
    00045
    00046                 - load_image(), save_image() take filenames, not file handles.
    00047
    00048                 - TGA bitmap format available. If you want to add a filetype,
    00049                   extend the gImageHandlers array, and factor in your load_image_xxx()
    00050                   and save_image_xxx() functions. Search for string 'add your'
    00051                   to find appropriate code locations.
    00052
    00053                 - The 'input' and 'output' command-line arguments do not have
    00054                   to specify .bm files; any supported filetype is okay.
    00055
    00056                 - Added implementation of getopt() if compiling under Windows.
    00057 */
    00058
    00059 #include <stdio.h>
    00060 #include <stdlib.h>
    00061 #include <string.h>
    00062 //#include <malloc.h>
    00063 #include <math.h>
    00064
    00065 #include "ilu_internal.h"
    00066 #include "ilu_filter.h"
    00067 #include "ilu_states.h"
    00068
    00069 #define filter_support          (1.0)
    00070 double filter( double t) {
    00071         /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
    00072         if(t < 0.0) t = -t;
    00073         if(t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0);
    00074         return(0.0);
    00075 }
    00076
    00077 #define box_support             (0.5)
    00078
    00079 double box_filter( double t) {
    00080         if((t > -0.5) && (t <= 0.5)) return(1.0);
    00081         return(0.0);
    00082 }
    00083
    00084 #define triangle_support        (1.0)
    00085 double triangle_filter( double t ) {
    00086         if(t < 0.0) t = -t;
    00087         if(t < 1.0) return(1.0 - t);
    00088         return(0.0);
    00089 }
    00090
    00091 #define bell_support            (1.5)
    00092
    00093 double bell_filter( double t ) {
    00094         if(t < 0) t = -t;
    00095         if(t < .5) return(.75 - (t * t));
    00096         if(t < 1.5) {
    00097                 t = (t - 1.5);
    00098                 return(.5 * (t * t));
    00099         }
    00100         return(0.0);
    00101 }
    00102
    00103 #define B_spline_support        (2.0)
    00104
    00105 #define FRAC_2_3 0.6666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667
    00106 #define FRAC_1_6 0.1666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667
    00107
    00108 double B_spline_filter( double t ) { /* box (*) box (*) box (*) box */
    00109         double tt;
    00110
    00111         if(t < 0) t = -t;
    00112         if(t < 1) {
    00113                 tt = t * t;
    00114                 return((.5 * tt * t) - tt + (2.0 / 3.0));
    00115         } else if(t < 2) {
    00116                 t = 2 - t;
    00117                 return((1.0 / 6.0) * (t * t * t));
    00118         }
    00119         return(0.0);
    00120 }
    00121
    00122 double sinc( double x) {
    00123         x *= IL_PI;
    00124         if(x != 0) return(sin(x) / x);
    00125         return(1.0);
    00126 }
    00127
    00128 #define Lanczos3_support        (3.0)
    00129 double Lanczos3_filter( double t ) {
    00130         if(t < 0) t = -t;
    00131         if(t < 3.0) return(sinc(t) * sinc(t/3.0));
    00132         return(0.0);
    00133 }
    00134
    00135 #define Mitchell_support        (2.0)
    00136
    00137 #define B       (1.0 / 3.0)
    00138 #define C       (1.0 / 3.0)
    00139
    00140 double Mitchell_filter( double t ) {
    00141         double tt;
    00142
    00143         tt = t * t;
    00144         if(t < 0) t = -t;
    00145         if(t < 1.0) {
    00146                 t = (((12.0 - 9.0 * B - 6.0 * C) * (t * tt))
    00147                    + ((-18.0 + 12.0 * B + 6.0 * C) * tt)
    00148                    + (6.0 - 2 * B));
    00149                 return(t / 6.0);
    00150         } else if(t < 2.0) {
    00151                 t = (((-1.0 * B - 6.0 * C) * (t * tt))
    00152                    + ((6.0 * B + 30.0 * C) * tt)
    00153                    + ((-12.0 * B - 48.0 * C) * t)
    00154                    + (8.0 * B + 24 * C));
    00155                 return(t / 6.0);
    00156         }
    00157         return(0.0);
    00158 }
    00159
    00160
    00161 int roundcloser(double d) {
    00162         int n = (int) d;
    00163         double diff = d - (double)n;
    00164         if(diff < 0)
    00165                 diff = -diff;
    00166         if(diff >= 0.5)
    00167         {
    00168                 if(d < 0)
    00169                         n--;
    00170                 else
    00171                         n++;
    00172         }
    00173         return n;
    00174 }
    00175
    00176 int wrap_filter_sample(int i, int size) {
    00177         int j;
    00178         j = i % (size * 2);
    00179         if (j < 0)
    00180                 j += (size * 2);
    00181         if (j < size)
    00182                 return j;
    00183         return 2 * size - j - 1;
    00184 }
    00185
    00186 /*char  _Program[] = "fzoom";
    00187 char    _Version[] = "0.30";
    00188 char    _Copyright[] = "Public Domain 1991 by Dale Schumacher. Mods by Ray Gardener";*/
    00189
    00190
    00191 /* Note: if you define ILubyte to something bigger than char,
    00192                 you may need to add more support in bitmap file I/O functions.
    00193 */
    00194
    00195 #define WHITE_PIXEL     (255)
    00196 #define BLACK_PIXEL     (0)
    00197
    00198 #define CLAMP(v,l,h)    ((v)<(l) ? (l) : (v) > (h) ? (h) : v)
    00199
    00200 static ILuint c;  // Current colour plane offset
    00201
    00202 typedef struct {
    00203         int     pixel;
    00204         double  weight;
    00205 } CONTRIB;
    00206
    00207 typedef struct {
    00208         int     n;              /* number of contributors */
    00209         CONTRIB *p;             /* pointer to list of contributions */
    00210 } CLIST;
    00211
    00212 CLIST   *contrib;               /* array of contribution lists */
    00213
    00214 /*
    00215  *      generic image access and i/o support routines
    00216  */
    00217
    00218 /*
    00219         calc_x_contrib()
    00220
    00221         Calculates the filter weights for a single target column.
    00222         contribX->p must be freed afterwards.
    00223
    00224         Returns -1 if error, 0 otherwise.
    00225 */
    00226 int calc_x_contrib( CLIST *contribX, double xscale, double fwidth, int dstwidth, int srcwidth, double (*filterf)(double), int i) {
    00227         double width;
    00228         double fscale;
    00229         double center, left, right;
    00230         double weight;
    00231         int j, k, n;
    00232
    00233         if(xscale < 1.0)
    00234         {
    00235                 /* Shrinking image */
    00236                 width = fwidth / xscale;
    00237                 fscale = 1.0 / xscale;
    00238
    00239                 contribX->n = 0;
    00240                 contribX->p = (CONTRIB *)icalloc((int) (width * 2 + 1),
    00241                                 sizeof(CONTRIB));
    00242                 if (contribX->p == NULL) {
    00243                         return -1;
    00244                 }
    00245
    00246                 center = (double) i / xscale;
    00247                 left = ceil(center - width);
    00248                 right = floor(center + width);
    00249                 for(j = (int)left; j <= right; ++j)
    00250                 {
    00251                         weight = center - (double) j;
    00252                         weight = (*filterf)(weight / fscale) / fscale;
    00253                         n = wrap_filter_sample(j, srcwidth);
    00254
    00255                         k = contribX->n++;
    00256                         contribX->p[k].pixel = n;
    00257                         contribX->p[k].weight = weight;
    00258                 }
    00259
    00260         }
    00261         else
    00262         {
    00263                 /* Expanding image */
    00264                 contribX->n = 0;
    00265                 contribX->p = (CONTRIB*)icalloc((int) (fwidth * 2 + 1),
    00266                                 sizeof(CONTRIB));
    00267                 if (contribX->p == NULL) {
    00268                         return -1;
    00269                 }
    00270                 center = (double) i / xscale;
    00271                 left = ceil(center - fwidth);
    00272                 right = floor(center + fwidth);
    00273
    00274                 for(j = (int)left; j <= right; ++j)
    00275                 {
    00276                         weight = center - (double) j;
    00277                         weight = (*filterf)(weight);
    00278                         n = wrap_filter_sample(j, srcwidth);
    00279                         k = contribX->n++;
    00280                         contribX->p[k].pixel = n;
    00281                         contribX->p[k].weight = weight;
    00282                 }
    00283         }
    00284         return 0;
    00285 } /* calc_x_contrib */
    00286
    00287
    00288 /*
    00289         zoom()
    00290
    00291         Resizes bitmaps while resampling them.
    00292         Returns -1 if error, 0 if success.
    00293 */
    00294 int zoom( ILimage *dst, ILimage *src, double (*filterf)(double), double fwidth) {
    00295         ILubyte* tmp;
    00296         double xscale, yscale;          /* zoom scale factors */
    00297         int xx;
    00298         int i, j, k;                    /* loop variables */
    00299         int n;                          /* pixel number */
    00300         double center, left, right;     /* filter calculation variables */
    00301         double width, fscale, weight;   /* filter calculation variables */
    00302         ILubyte pel, pel2;
    00303         int bPelDelta;
    00304         CLIST   *contribY;              /* array of contribution lists */
    00305         CLIST   contribX;
    00306         int             nRet = -1;
    00307
    00308         /* create intermediate column to hold horizontal dst column zoom */
    00309         tmp = (ILubyte*)ialloc(src->Height * sizeof(ILubyte));
    00310         if (tmp == NULL) {
    00311                 return 0;
    00312         }
    00313
    00314         xscale = (double) dst->Width / (double) src->Width;
    00315
    00316         /* Build y weights */
    00317         /* pre-calculate filter contributions for a column */
    00318         contribY = (CLIST*)icalloc(dst->Height, sizeof(CLIST));
    00319         if (contribY == NULL) {
    00320                 ifree(tmp);
    00321                 return -1;
    00322         }
    00323
    00324         yscale = (double) dst->Height / (double) src->Height;
    00325
    00326         if(yscale < 1.0)
    00327         {
    00328                 width = fwidth / yscale;
    00329                 fscale = 1.0 / yscale;
    00330                 for(i = 0; i < (ILint)dst->Height; ++i)
    00331                 {
    00332                         contribY[i].n = 0;
    00333                         contribY[i].p = (CONTRIB*)icalloc((int) (width * 2 + 1),
    00334                                         sizeof(CONTRIB));
    00335                         if(contribY[i].p == NULL) {
    00336                                 ifree(tmp);
    00337                                 ifree(contribY);
    00338                                 return -1;
    00339                         }
    00340                         center = (double) i / yscale;
    00341                         left = ceil(center - width);
    00342                         right = floor(center + width);
    00343                         for(j = (int)left; j <= right; ++j) {
    00344                                 weight = center - (double) j;
    00345                                 weight = (*filterf)(weight / fscale) / fscale;
    00346                                 n = wrap_filter_sample(j, src->Height);
    00347                                 k = contribY[i].n++;
    00348                                 contribY[i].p[k].pixel = n;
    00349                                 contribY[i].p[k].weight = weight;
    00350                         }
    00351                 }
    00352         } else {
    00353                 for(i = 0; i < (ILint)dst->Height; ++i) {
    00354                         contribY[i].n = 0;
    00355                         contribY[i].p = (CONTRIB*)icalloc((int) (fwidth * 2 + 1),
    00356                                         sizeof(CONTRIB));
    00357                         if (contribY[i].p == NULL) {
    00358                                 ifree(tmp);
    00359                                 ifree(contribY);
    00360                                 return -1;
    00361                         }
    00362                         center = (double) i / yscale;
    00363                         left = ceil(center - fwidth);
    00364                         right = floor(center + fwidth);
    00365                         for(j = (int)left; j <= right; ++j) {
    00366                                 weight = center - (double) j;
    00367                                 weight = (*filterf)(weight);
    00368                                 n = wrap_filter_sample(j, src->Height);
    00369                                 k = contribY[i].n++;
    00370                                 contribY[i].p[k].pixel = n;
    00371                                 contribY[i].p[k].weight = weight;
    00372                         }
    00373                 }
    00374         }
    00375
    00376
    00377         for(xx = 0; xx < (ILint)dst->Width; xx++)
    00378         {
    00379                 if(0 != calc_x_contrib(&contribX, xscale, fwidth,
    00380                                                                 dst->Width, src->Width, filterf, xx))
    00381                 {
    00382                         goto __zoom_cleanup;
    00383                 }
    00384                 /* Apply horz filter to make dst column in tmp. */
    00385                 for(k = 0; k < (ILint)src->Height; ++k)
    00386                 {
    00387                         weight = 0.0;
    00388                         bPelDelta = IL_FALSE;
    00389                         // Denton:  Put get_pixel source here
    00390                         //pel = get_pixel(src, contribX.p[0].pixel, k);
    00391                         pel = src->Data[k * src->Bps + contribX.p[0].pixel * src->Bpp + c];
    00392                         for(j = 0; j < contribX.n; ++j)
    00393                         {
    00394                                 // Denton:  Put get_pixel source here
    00395                                 //pel2 = get_pixel(src, contribX.p[j].pixel, k);
    00396                                 pel2 = src->Data[k * src->Bps + contribX.p[j].pixel * src->Bpp + c];
    00397                                 if(pel2 != pel)
    00398                                         bPelDelta = IL_TRUE;
    00399                                 weight += pel2 * contribX.p[j].weight;
    00400                         }
    00401                         weight = bPelDelta ? roundcloser(weight) : pel;
    00402
    00403                         tmp[k] = (ILubyte)CLAMP(weight, BLACK_PIXEL, WHITE_PIXEL);
    00404                 } /* next row in temp column */
    00405
    00406                 ifree(contribX.p);
    00407
    00408                 /* The temp column has been built. Now stretch it
    00409                  vertically into dst column. */
    00410                 for(i = 0; i < (ILint)dst->Height; ++i)
    00411                 {
    00412                         weight = 0.0;
    00413                         bPelDelta = IL_FALSE;
    00414                         pel = tmp[contribY[i].p[0].pixel];
    00415
    00416                         for(j = 0; j < contribY[i].n; ++j)
    00417                         {
    00418                                 pel2 = tmp[contribY[i].p[j].pixel];
    00419                                 if(pel2 != pel)
    00420                                         bPelDelta = IL_TRUE;
    00421                                 weight += pel2 * contribY[i].p[j].weight;
    00422                         }
    00423                         weight = bPelDelta ? roundcloser(weight) : pel;
    00424                         // Denton:  Put set_pixel source here
    00425                         //put_pixel(dst, xx, i, (ILubyte)CLAMP(weight, BLACK_PIXEL, WHITE_PIXEL));
    00426                         dst->Data[i * dst->Bps + xx * dst->Bpp + c] =
    00427                                 (ILubyte)CLAMP(weight, BLACK_PIXEL, WHITE_PIXEL);
    00428                 } /* next dst row */
    00429         } /* next dst column */
    00430         nRet = 0; /* success */
    00431
    00432 __zoom_cleanup:
    00433         ifree(tmp);
    00434
    00435         // Free the memory allocated for vertical filter weights
    00436         for (i = 0; i < (ILint)dst->Height; ++i)
    00437                 ifree(contribY[i].p);
    00438         ifree(contribY);
    00439
    00440         return nRet;
    00441 } /* zoom */
    00442
    00443
    00444 ILuint iluScaleAdvanced(ILuint Width, ILuint Height, ILenum Filter)
    00445 {
    00446         double (*f)(double) = filter;
    00447         double s = filter_support;
    00448         ILimage *Dest;
    00449
    00450         iluCurImage = ilGetCurImage();
    00451         if (iluCurImage == NULL) {
    00452                 ilSetError(ILU_ILLEGAL_OPERATION);
    00453                 return IL_FALSE;
    00454         }
    00455
    00456         // Not supported yet.
    00457         if (iluCurImage->Type != IL_UNSIGNED_BYTE ||
    00458                 iluCurImage->Format == IL_COLOUR_INDEX ||
    00459                 iluCurImage->Depth > 1) {
    00460                         ilSetError(ILU_ILLEGAL_OPERATION);
    00461                         return IL_FALSE;
    00462         }
    00463
    00464         switch (Filter)
    00465         {
    00466                 case ILU_SCALE_BOX: f=box_filter; s=box_support; break;
    00467                 case ILU_SCALE_TRIANGLE: f=triangle_filter; s=triangle_support; break;
    00468                 case ILU_SCALE_BELL: f=bell_filter; s=bell_support; break;
    00469                 case ILU_SCALE_BSPLINE: f=B_spline_filter; s=B_spline_support; break;
    00470                 case ILU_SCALE_LANCZOS3: f=Lanczos3_filter; s=Lanczos3_support; break;
    00471                 case ILU_SCALE_MITCHELL: f=Mitchell_filter; s=Mitchell_support; break;
    00472                 //case 'h': f=filter; s=filter_support; break;
    00473         }
    00474
    00475         Dest = ilNewImage(Width, Height, 1, iluCurImage->Bpp, 1);
    00476         Dest->Origin = iluCurImage->Origin;
    00477         Dest->Duration = iluCurImage->Duration;
    00478         for (c = 0; c < (ILuint)iluCurImage->Bpp; c++) {
    00479                 if (zoom(Dest, iluCurImage, f, s) != 0) {
    00480                         return IL_FALSE;
    00481                 }
    00482         }
    00483
    00484         ilTexImage(Width, Height, 1, iluCurImage->Bpp, iluCurImage->Format, iluCurImage->Type, Dest->Data);
    00485         iluCurImage->Origin = Dest->Origin;
    00486         iluCurImage->Duration = Dest->Duration;
    00487         ilCloseImage(Dest);
    00488
    00489         return IL_TRUE;
    00490 }
    00491