]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/resample.c
(no commit message)
[imagemagick] / MagickCore / resample.c
index 5a5b43f52e05d43f8d6450285f9baaa9561ade25..fdeab03414205055fbdecc3e09b13206fe797753 100644 (file)
@@ -18,7 +18,7 @@
 %                                August 2007                                  %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
 #include "MagickCore/resample.h"
 #include "MagickCore/resize.h"
 #include "MagickCore/resize-private.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/token.h"
 #include "MagickCore/transform.h"
 #include "MagickCore/signature-private.h"
 #include "MagickCore/utility.h"
 #include "MagickCore/utility-private.h"
+#include "MagickCore/option.h"
 /*
   EWA Resampling Options
 */
@@ -178,7 +181,7 @@ struct _ResampleFilter
 %
 %  Usage Example...
 %      resample_filter=AcquireResampleFilter(image,exception);
-%      SetResampleFilter(resample_filter, GaussianFilter, 1.0);
+%      SetResampleFilter(resample_filter, GaussianFilter);
 %      for (y=0; y < (ssize_t) image->rows; y++) {
 %        for (x=0; x < (ssize_t) image->columns; x++) {
 %          u= ....;   v= ....;
@@ -222,7 +225,7 @@ MagickExport ResampleFilter *AcquireResampleFilter(const Image *image,
 
   resample_filter->exception=exception;
   resample_filter->image=ReferenceImage((Image *) image);
-  resample_filter->view=AcquireCacheView(resample_filter->image);
+  resample_filter->view=AcquireVirtualCacheView(resample_filter->image,exception);
 
   resample_filter->debug=IsEventLogging();
   resample_filter->signature=MagickSignature;
@@ -231,12 +234,10 @@ MagickExport ResampleFilter *AcquireResampleFilter(const Image *image,
   resample_filter->average_defined = MagickFalse;
 
   /* initialise the resampling filter settings */
-  SetResampleFilter(resample_filter, image->filter, image->blur);
-  (void) SetResampleFilterInterpolateMethod(resample_filter,
-    image->interpolate);
+  SetResampleFilter(resample_filter, image->filter);
+  (void) SetResampleFilterInterpolateMethod(resample_filter,image->interpolate);
   (void) SetResampleFilterVirtualPixelMethod(resample_filter,
     GetImageVirtualPixelMethod(image));
-
   return(resample_filter);
 }
 \f
@@ -302,7 +303,8 @@ MagickExport ResampleFilter *DestroyResampleFilter(
 %  The format of the ResamplePixelColor method is:
 %
 %     MagickBooleanType ResamplePixelColor(ResampleFilter *resample_filter,
-%       const double u0,const double v0,PixelInfo *pixel)
+%       const double u0,const double v0,PixelInfo *pixel,
+%       ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -313,10 +315,12 @@ MagickExport ResampleFilter *DestroyResampleFilter(
 %
 %    o pixel: the resampled pixel is returned here.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 MagickExport MagickBooleanType ResamplePixelColor(
   ResampleFilter *resample_filter,const double u0,const double v0,
-  PixelInfo *pixel)
+  PixelInfo *pixel,ExceptionInfo *exception)
 {
   MagickBooleanType
     status;
@@ -468,14 +472,14 @@ MagickExport MagickBooleanType ResamplePixelColor(
           resample_filter->average_defined=MagickTrue;
 
           /* Try to get an averaged pixel color of whole image */
-          average_image=ResizeImage(resample_filter->image,1,1,BoxFilter,1.0,
+          average_image=ResizeImage(resample_filter->image,1,1,BoxFilter,
             resample_filter->exception);
           if (average_image == (Image *) NULL)
             {
               *pixel=resample_filter->average_pixel; /* FAILED */
               break;
             }
-          average_view=AcquireCacheView(average_image);
+          average_view=AcquireVirtualCacheView(average_image,exception);
           pixels=GetCacheViewVirtualPixels(average_view,0,0,1,1,
             resample_filter->exception);
           if (pixels == (const Quantum *) NULL) {
@@ -491,17 +495,19 @@ MagickExport MagickBooleanType ResamplePixelColor(
 
           if ( resample_filter->virtual_pixel == CheckerTileVirtualPixelMethod )
             {
-              /* CheckerTile is avergae of image average half background */
-              /* FUTURE: replace with a 50% blend of both pixels */
+              /* CheckerTile is a alpha blend of the image's average pixel
+                 color and the current background color */
 
-              weight = QuantumScale*((MagickRealType)
+              /* image's average pixel color */
+              weight = QuantumScale*((double)
                 resample_filter->average_pixel.alpha);
               resample_filter->average_pixel.red *= weight;
               resample_filter->average_pixel.green *= weight;
               resample_filter->average_pixel.blue *= weight;
               divisor_c = weight;
 
-              weight = QuantumScale*((MagickRealType)
+              /* background color */
+              weight = QuantumScale*((double)
                 resample_filter->image->background_color.alpha);
               resample_filter->average_pixel.red +=
                       weight*resample_filter->image->background_color.red;
@@ -513,10 +519,11 @@ MagickExport MagickBooleanType ResamplePixelColor(
                       resample_filter->image->background_color.alpha;
               divisor_c += weight;
 
+              /* alpha blend */
               resample_filter->average_pixel.red /= divisor_c;
               resample_filter->average_pixel.green /= divisor_c;
               resample_filter->average_pixel.blue /= divisor_c;
-              resample_filter->average_pixel.alpha /= 2;
+              resample_filter->average_pixel.alpha /= 2; /* 50% blend */
 
             }
         }
@@ -535,7 +542,7 @@ MagickExport MagickBooleanType ResamplePixelColor(
   pixel->red = pixel->green = pixel->blue = 0.0;
   if (pixel->colorspace == CMYKColorspace)
     pixel->black = 0.0;
-  if (pixel->matte != MagickFalse)
+  if (pixel->alpha_trait == BlendPixelTrait)
     pixel->alpha = 0.0;
 
   /*
@@ -600,8 +607,8 @@ MagickExport MagickBooleanType ResamplePixelColor(
         pixel->alpha  += weight*GetPixelAlpha(resample_filter->image,pixels);
         divisor_m += weight;
 
-        if (pixel->matte != MagickFalse)
-          weight *= QuantumScale*((MagickRealType) GetPixelAlpha(resample_filter->image,pixels));
+        if (pixel->alpha_trait == BlendPixelTrait)
+          weight *= QuantumScale*((double) GetPixelAlpha(resample_filter->image,pixels));
         pixel->red   += weight*GetPixelRed(resample_filter->image,pixels);
         pixel->green += weight*GetPixelGreen(resample_filter->image,pixels);
         pixel->blue  += weight*GetPixelBlue(resample_filter->image,pixels);
@@ -638,8 +645,9 @@ MagickExport MagickBooleanType ResamplePixelColor(
   /*
     Result sanity check -- this should NOT happen
   */
-  if ( hit == 0 ) {
-    /* not enough pixels in resampling, resort to direct interpolation */
+  if ( hit == 0 || divisor_m <= MagickEpsilon || divisor_c <= MagickEpsilon ) {
+    /* not enough pixels, or bad weighting in resampling,
+       resort to direct interpolation */
 #if DEBUG_NO_PIXEL_HIT
     pixel->alpha = pixel->red = pixel->green = pixel->blue = 0;
     pixel->red = QuantumRange; /* show pixels for which EWA fails */
@@ -655,13 +663,13 @@ MagickExport MagickBooleanType ResamplePixelColor(
     Finialize results of resampling
   */
   divisor_m = 1.0/divisor_m;
-  pixel->alpha = (MagickRealType) ClampToQuantum(divisor_m*pixel->alpha);
+  pixel->alpha = (double) ClampToQuantum(divisor_m*pixel->alpha);
   divisor_c = 1.0/divisor_c;
-  pixel->red   = (MagickRealType) ClampToQuantum(divisor_c*pixel->red);
-  pixel->green = (MagickRealType) ClampToQuantum(divisor_c*pixel->green);
-  pixel->blue  = (MagickRealType) ClampToQuantum(divisor_c*pixel->blue);
+  pixel->red   = (double) ClampToQuantum(divisor_c*pixel->red);
+  pixel->green = (double) ClampToQuantum(divisor_c*pixel->green);
+  pixel->blue  = (double) ClampToQuantum(divisor_c*pixel->blue);
   if (pixel->colorspace == CMYKColorspace)
-    pixel->black = (MagickRealType) ClampToQuantum(divisor_c*pixel->black);
+    pixel->black = (double) ClampToQuantum(divisor_c*pixel->black);
   return(MagickTrue);
 }
 \f
@@ -695,16 +703,10 @@ MagickExport MagickBooleanType ResamplePixelColor(
 %
 % Reference: http://en.wikipedia.org/wiki/Ellipse#Canonical_form
 */
-static inline void ClampUpAxes(const double dux,
-                              const double dvx,
-                              const double duy,
-                              const double dvy,
-                              double *major_mag,
-                              double *minor_mag,
-                              double *major_unit_x,
-                              double *major_unit_y,
-                              double *minor_unit_x,
-                              double *minor_unit_y)
+static inline void ClampUpAxes(const double dux,const double dvx,
+  const double duy,const double dvy,double *major_mag,double *minor_mag,
+  double *major_unit_x,double *major_unit_y,double *minor_unit_x,
+  double *minor_unit_y)
 {
   /*
    * ClampUpAxes takes an input 2x2 matrix
@@ -1149,7 +1151,8 @@ MagickExport void ScaleResampleFilter(ResampleFilter *resample_filter,
   }
 
   /* Scale ellipse to match the filters support
-     (that is, multiply F by the square of the support).
+     (that is, multiply F by the square of the support)
+     Simplier to just multiply it by the support twice!
   */
   F *= resample_filter->support;
   F *= resample_filter->support;
@@ -1208,14 +1211,10 @@ MagickExport void ScaleResampleFilter(ResampleFilter *resample_filter,
 %  specific filter.  Note that the filter is used as a radial filter not as a
 %  two pass othogonally aligned resampling filter.
 %
-%  The default Filter, is Gaussian, which is the standard filter used by the
-%  original paper on the Elliptical Weighted Everage Algorithm. However other
-%  filters can also be used.
-%
 %  The format of the SetResampleFilter method is:
 %
 %    void SetResampleFilter(ResampleFilter *resample_filter,
-%      const FilterTypes filter,const double blur)
+%      const FilterTypes filter)
 %
 %  A description of each parameter follows:
 %
@@ -1223,11 +1222,9 @@ MagickExport void ScaleResampleFilter(ResampleFilter *resample_filter,
 %
 %    o filter: the resize filter for elliptical weighting LUT
 %
-%    o blur: filter blur factor (radial scaling) for elliptical weighting LUT
-%
 */
 MagickExport void SetResampleFilter(ResampleFilter *resample_filter,
-  const FilterTypes filter,const double blur)
+  const FilterTypes filter)
 {
   ResizeFilter
      *resize_filter;
@@ -1238,25 +1235,25 @@ MagickExport void SetResampleFilter(ResampleFilter *resample_filter,
   resample_filter->do_interpolate = MagickFalse;
   resample_filter->filter = filter;
 
-  if ( filter == PointFilter )
-    {
-      resample_filter->do_interpolate = MagickTrue;
-      return;  /* EWA turned off - nothing more to do */
-    }
-
-  /* Set a default cylindrical filter of a 'low blur' Jinc windowed Jinc */
+  /* Default cylindrical filter is a Cubic Keys filter */
   if ( filter == UndefinedFilter )
     resample_filter->filter = RobidouxFilter;
 
+  if ( resample_filter->filter == PointFilter ) {
+    resample_filter->do_interpolate = MagickTrue;
+    return;  /* EWA turned off - nothing more to do */
+  }
+
   resize_filter = AcquireResizeFilter(resample_filter->image,
-       resample_filter->filter,blur,MagickTrue,resample_filter->exception);
-  if (resize_filter == (ResizeFilter *) NULL)
-    {
-      (void) ThrowMagickException(resample_filter->exception,GetMagickModule(),
-           ModuleError, "UnableToSetFilteringValue",
-           "Fall back to default EWA gaussian filter");
-      resample_filter->filter = PointFilter;
-    }
+    resample_filter->filter,MagickTrue,resample_filter->exception);
+  if (resize_filter == (ResizeFilter *) NULL) {
+    (void) ThrowMagickException(resample_filter->exception,GetMagickModule(),
+         ModuleError, "UnableToSetFilteringValue",
+         "Fall back to Interpolated 'Point' filter");
+    resample_filter->filter = PointFilter;
+    resample_filter->do_interpolate = MagickTrue;
+    return;  /* EWA turned off - nothing more to do */
+  }
 
   /* Get the practical working support for the filter,
    * after any API call blur factors have been accoded for.
@@ -1273,6 +1270,7 @@ MagickExport void SetResampleFilter(ResampleFilter *resample_filter,
        Q;
     double
        r_scale;
+
     /* Scale radius so the filter LUT covers the full support range */
     r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH);
     for(Q=0; Q<WLUT_WIDTH; Q++)
@@ -1296,10 +1294,10 @@ MagickExport void SetResampleFilter(ResampleFilter *resample_filter,
   ScaleResampleFilter(resample_filter, 1.0, 0.0, 0.0, 1.0);
 
 #if 0
-  /* This is old code kept as a reference only.  It is very wrong,
-     and I don't understand exactly what it was attempting to do.
-  */
   /*
+    This is old code kept as a reference only. Basically it generates
+    a Gaussian bell curve, with sigma = 0.5 if the support is 2.0
+
     Create Normal Gaussian 2D Filter Weighted Lookup Table.
     A normal EWA guassual lookup would use   exp(Q*ALPHA)
     where  Q = distance squared from 0.0 (center) to 1.0 (edge)
@@ -1307,48 +1305,56 @@ MagickExport void SetResampleFilter(ResampleFilter *resample_filter,
     The table is of length 1024, and equates to support radius of 2.0
     thus needs to be scaled by  ALPHA*4/1024 and any blur factor squared
 
-    The above came from some reference code provided by Fred Weinhaus
-    and seems to have been a guess that was appropriate for its use
-    in a 3d perspective landscape mapping program.
+    The it comes from reference code provided by Fred Weinhaus.
   */
   r_scale = -2.77258872223978123767/(WLUT_WIDTH*blur*blur);
   for(Q=0; Q<WLUT_WIDTH; Q++)
     resample_filter->filter_lut[Q] = exp((double)Q*r_scale);
   resample_filter->support = WLUT_WIDTH;
-  break;
 #endif
 
 #if FILTER_LUT
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp single
 #endif
-  { register int
-       Q;
-    double
-       r_scale;
-
-    /* Scale radius so the filter LUT covers the full support range */
-    r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH);
-    if (IsMagickTrue(GetImageArtifact(resample_filter->image,"resample:verbose")) )
+  {
+    if (IfStringTrue(GetImageArtifact(resample_filter->image,
+             "resample:verbose")) )
       {
+        register int
+          Q;
+        double
+          r_scale;
+
         /* Debug output of the filter weighting LUT
-          Gnuplot the LUT with hoizontal adjusted to 'r' using...
-            plot [0:2][-.2:1] "lut.dat" using (sqrt($0/1024)*2):1 with lines
-          The filter values is normalized for comparision
+          Gnuplot the LUT data, the x scale index has been adjusted
+            plot [0:2][-.2:1] "lut.dat" with lines
+          The filter values should be normalized for comparision
         */
         printf("#\n");
-        printf("# Resampling Filter LUT (%d values)\n", WLUT_WIDTH);
+        printf("# Resampling Filter LUT (%d values) for '%s' filter\n",
+                   WLUT_WIDTH, CommandOptionToMnemonic(MagickFilterOptions,
+                   resample_filter->filter) );
         printf("#\n");
         printf("# Note: values in table are using a squared radius lookup.\n");
-        printf("# And the whole table represents the filters support.\n");
-        printf("\n"); /* generates a 'break' in gnuplot if multiple outputs */
+        printf("# As such its distribution is not uniform.\n");
+        printf("#\n");
+        printf("# The X value is the support distance for the Y weight\n");
+        printf("# so you can use gnuplot to plot this cylindrical filter\n");
+        printf("#    plot [0:2][-.2:1] \"lut.dat\" with lines\n");
+        printf("#\n");
+
+        /* Scale radius so the filter LUT covers the full support range */
+        r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH);
         for(Q=0; Q<WLUT_WIDTH; Q++)
           printf("%8.*g %.*g\n",
-               GetMagickPrecision(),sqrt((double)Q)*r_scale,
-               GetMagickPrecision(),resample_filter->filter_lut[Q] );
+              GetMagickPrecision(),sqrt((double)Q)*r_scale,
+              GetMagickPrecision(),resample_filter->filter_lut[Q] );
+        printf("\n\n"); /* generate a 'break' in gnuplot if multiple outputs */
       }
-    /* output the above once only for each image, and each setting */
+    /* Output the above once only for each image, and each setting
     (void) DeleteImageArtifact(resample_filter->image,"resample:verbose");
+    */
   }
 #endif /* FILTER_LUT */
   return;