resize.c

Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                 RRRR   EEEEE  SSSSS  IIIII  ZZZZZ  EEEEE                    %
00007 %                 R   R  E      SS       I       ZZ  E                        %
00008 %                 RRRR   EEE     SSS     I     ZZZ   EEE                      %
00009 %                 R R    E         SS    I    ZZ     E                        %
00010 %                 R  R   EEEEE  SSSSS  IIIII  ZZZZZ  EEEEE                    %
00011 %                                                                             %
00012 %                                                                             %
00013 %                      MagickCore Image Resize Methods                        %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                                 July 1992                                   %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 */
00038 
00039 /*
00040   Include declarations.
00041 */
00042 #include "magick/studio.h"
00043 #include "magick/artifact.h"
00044 #include "magick/blob.h"
00045 #include "magick/cache.h"
00046 #include "magick/cache-view.h"
00047 #include "magick/color.h"
00048 #include "magick/color-private.h"
00049 #include "magick/draw.h"
00050 #include "magick/exception.h"
00051 #include "magick/exception-private.h"
00052 #include "magick/gem.h"
00053 #include "magick/image.h"
00054 #include "magick/image-private.h"
00055 #include "magick/list.h"
00056 #include "magick/memory_.h"
00057 #include "magick/pixel-private.h"
00058 #include "magick/property.h"
00059 #include "magick/monitor.h"
00060 #include "magick/monitor-private.h"
00061 #include "magick/pixel.h"
00062 #include "magick/option.h"
00063 #include "magick/resample.h"
00064 #include "magick/resize.h"
00065 #include "magick/resize-private.h"
00066 #include "magick/string_.h"
00067 #include "magick/utility.h"
00068 #include "magick/version.h"
00069 #if defined(MAGICKCORE_LQR_DELEGATE)
00070 #include <lqr.h>
00071 #endif
00072 
00073 /*
00074   Typedef declarations.
00075 */
00076 struct _ResizeFilter
00077 {
00078   MagickRealType
00079     (*filter)(const MagickRealType,const ResizeFilter *),
00080     (*window)(const MagickRealType,const ResizeFilter *),
00081     support,   /* filter region of support - the filter support limit */
00082     window_support,  /* window support, usally equal to support (expert only) */
00083     scale,     /* dimension to scale to fit window support (usally 1.0) */
00084     blur,      /* x-scale (blur-sharpen) */
00085     cubic[8];  /* cubic coefficents for smooth Cubic filters */
00086 
00087   unsigned long
00088     signature;
00089 };
00090 
00091 /*
00092   Forward declaractions.
00093 */
00094 static MagickRealType
00095   I0(MagickRealType x),
00096   BesselOrderOne(MagickRealType);
00097 
00098 /*
00099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00100 %                                                                             %
00101 %                                                                             %
00102 %                                                                             %
00103 +   F i l t e r F u n c t i o n s                                             %
00104 %                                                                             %
00105 %                                                                             %
00106 %                                                                             %
00107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00108 %
00109 %  These are the various filter and windowing functions that are provided,
00110 %
00111 %  They are all internal to this module only.  See AcquireResizeFilterInfo()
00112 %  for details of the access to these functions, via the
00113 %  GetResizeFilterSupport() and GetResizeFilterWeight() API interface.
00114 %
00115 %  The individual filter functions have this format...
00116 %
00117 %     static MagickRealtype *FilterName(const MagickRealType x,
00118 %        const MagickRealType support)
00119 %
00120 %    o x: the distance from the sampling point
00121 %         generally in the range of  0 to support
00122 %         The GetResizeFilterWeight() ensures this a positive value.
00123 %
00124 %    o resize_filter: Current Filter Information
00125 %        This allows function to access support, and posibly other
00126 %        pre-calculated information defineding the functions.
00127 %
00128 */
00129 
00130 static MagickRealType Bessel(const MagickRealType x,
00131   const ResizeFilter *magick_unused(resize_filter))
00132 {
00133   /*
00134     See Pratt "Digital Image Processing" p.97 for Bessel functions
00135 
00136     This function actually a X-scaled Jinc(x) function.
00137       http://mathworld.wolfram.com/JincFunction.html
00138     And on page 11 of...
00139       http://www.ph.ed.ac.uk/%7ewjh/teaching/mo/slides/lens/lens.pdf
00140   */
00141   if (x == 0.0)
00142     return((MagickRealType) (MagickPI/4.0));
00143   return(BesselOrderOne(MagickPI*x)/(2.0*x));
00144 }
00145 
00146 static MagickRealType Blackman(const MagickRealType x,
00147      const ResizeFilter *magick_unused(resize_filter))
00148 {
00149   /*
00150     Blackman: 2rd Order cosine windowing function.
00151   */
00152   return(0.42+0.5*cos(MagickPI*(double) x)+0.08*cos(2.0*MagickPI*(double) x));
00153 }
00154 
00155 static MagickRealType Bohman(const MagickRealType x,
00156      const ResizeFilter *magick_unused(resize_filter))
00157 {
00158   /*
00159     Bohman: 2rd Order cosine windowing function.
00160   */
00161   return((1-x)*cos(MagickPI*(double) x)+sin(MagickPI*(double) x)/MagickPI);
00162 }
00163 
00164 static MagickRealType Box(const MagickRealType magick_unused(x),
00165   const ResizeFilter *magick_unused(resize_filter))
00166 {
00167   /*
00168     Just return 1.0, filter will still be clipped by its support window.
00169   */
00170   return(1.0);
00171 }
00172 
00173 static MagickRealType CubicBC(const MagickRealType x,
00174   const ResizeFilter *resize_filter)
00175 {
00176   /*
00177     Cubic Filters using B,C determined values:
00178 
00179     Mitchell-Netravali  B=1/3 C=1/3   Qualitively ideal Cubic Filter
00180     Catmull-Rom         B= 0  C=1/2   Cublic Interpolation Function
00181     Cubic B-Spline      B= 1  C= 0    Spline Approximation of Gaussian
00182     Hermite             B= 0  C= 0    Quadratic Spline (support = 1)
00183 
00184     See paper by Mitchell and Netravali,
00185       Reconstruction Filters in Computer Graphics
00186       Computer Graphics, Volume 22, Number 4, August 1988
00187         http://www.cs.utexas.edu/users/fussell/courses/cs384g/
00188                  lectures/mitchell/Mitchell.pdf
00189 
00190     Coefficents are determined from B,C values
00191        P0 = (  6 - 2*B       )/6
00192        P1 =         0
00193        P2 = (-18 +12*B + 6*C )/6
00194        P3 = ( 12 - 9*B - 6*C )/6
00195        Q0 = (      8*B +24*C )/6
00196        Q1 = (    -12*B -48*C )/6
00197        Q2 = (      6*B +30*C )/6
00198        Q3 = (    - 1*B - 6*C )/6
00199 
00200     Which is used to define the filter...
00201        P0 + P1*x + P2*x^2 + P3*x^3      0 <= x < 1
00202        Q0 + Q1*x + Q2*x^2 + Q3*x^3      1 <= x <= 2
00203 
00204     Which ensures function is continuous in value and derivative (slope).
00205   */
00206   if (x < 1.0)
00207     return(resize_filter->cubic[0]+x*(resize_filter->cubic[1]+x*
00208       (resize_filter->cubic[2]+x*resize_filter->cubic[3])));
00209   if (x < 2.0)
00210     return(resize_filter->cubic[4] +x*(resize_filter->cubic[5]+x*
00211       (resize_filter->cubic[6] +x*resize_filter->cubic[7])));
00212   return(0.0);
00213 }
00214 
00215 static MagickRealType Gaussian(const MagickRealType x,
00216   const ResizeFilter *magick_unused(resize_filter))
00217 {
00218   return(exp((double) (-2.0*x*x))*sqrt(2.0/MagickPI));
00219 }
00220 
00221 static MagickRealType Hanning(const MagickRealType x,
00222   const ResizeFilter *magick_unused(resize_filter))
00223 {
00224   /*
00225     A Cosine windowing function.
00226   */
00227   return(0.5+0.5*cos(MagickPI*(double) x));
00228 }
00229 
00230 static MagickRealType Hamming(const MagickRealType x,
00231   const ResizeFilter *magick_unused(resize_filter))
00232 {
00233   /*
00234     A offset Cosine windowing function.
00235   */
00236   return(0.54+0.46*cos(MagickPI*(double) x));
00237 }
00238 
00239 static MagickRealType Kaiser(const MagickRealType x,
00240   const ResizeFilter *magick_unused(resize_filter))
00241 {
00242 #define Alpha  6.5
00243 #define I0A  (1.0/I0(Alpha))
00244 
00245   /*
00246     Kaiser Windowing Function (bessel windowing):
00247       Alpha is a free value  from 5 to 8 (currently hardcoded to 6.5)
00248       Future: make alphand the IOA pre-calculation, a 'expert' setting.
00249   */
00250   return(I0A*I0(Alpha*sqrt((double) (1.0-x*x))));
00251 }
00252 
00253 static MagickRealType Lagrange(const MagickRealType x,
00254   const ResizeFilter *resize_filter)
00255 {
00256   long
00257     n,
00258     order;
00259 
00260   MagickRealType
00261     value;
00262 
00263   register long
00264     i;
00265 
00266   /*
00267     Lagrange Piece-Wise polynomial fit of Sinc:
00268       N is the 'order' of the lagrange function and depends on
00269       the overall support window size of the filter. That is for
00270       a support of 2, gives a lagrange-4 or piece-wise cubic functions
00271 
00272       Note that n is the specific piece of the piece-wise function to calculate.
00273 
00274       See Survey: Interpolation Methods, IEEE Transactions on Medical Imaging,
00275       Vol 18, No 11, November 1999, p1049-1075, -- Equation 27 on p1064
00276   */
00277   if (x > resize_filter->support)
00278     return(0.0);
00279   order=(long) (2.0*resize_filter->window_support);  /* number of pieces */
00280   n=(long) ((1.0*order)/2.0+x);  /* which piece does x belong to */
00281   value=1.0f;
00282   for (i=0; i < order; i++)
00283     if (i != n)
00284       value*=(n-i-x)/(n-i);
00285   return(value);
00286 }
00287 
00288 static MagickRealType Quadratic(const MagickRealType x,
00289   const ResizeFilter *magick_unused(resize_filter))
00290 {
00291   /*
00292     2rd order (quadratic) B-Spline approximation of Gaussian.
00293   */
00294   if (x < 0.5)
00295     return(0.75-x*x);
00296   if (x < 1.5)
00297     return(0.5*(x-1.5)*(x-1.5));
00298   return(0.0);
00299 }
00300 
00301 static MagickRealType Sinc(const MagickRealType x,
00302   const ResizeFilter *magick_unused(resize_filter))
00303 {
00304   /*
00305     This function actually a X-scaled Sinc(x) function.
00306   */
00307   if (x == 0.0)
00308     return(1.0);
00309   return(sin(MagickPI*(double) x)/(MagickPI*(double) x));
00310 }
00311 
00312 static MagickRealType Triangle(const MagickRealType x,
00313   const ResizeFilter *magick_unused(resize_filter))
00314 {
00315   /*
00316     1rd order (linear) B-Spline,  bilinear interpolation,
00317     Tent 1D filter, or a Bartlett 2D Cone filter
00318   */
00319   if (x < 1.0)
00320     return(1.0-x);
00321   return(0.0);
00322 }
00323 
00324 static MagickRealType Welsh(const MagickRealType x,
00325   const ResizeFilter *magick_unused(resize_filter))
00326 {
00327   /*
00328     Welsh parabolic windowing filter.
00329   */
00330   if (x <  1.0)
00331     return(1.0-x*x);
00332   return(0.0);
00333 }
00334 
00335 /*
00336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00337 %                                                                             %
00338 %                                                                             %
00339 %                                                                             %
00340 +   A c q u i r e R e s i z e F i l t e r                                     %
00341 %                                                                             %
00342 %                                                                             %
00343 %                                                                             %
00344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00345 %
00346 %  AcquireResizeFilter() allocates the ResizeFilter structure.  Choose from
00347 %  these filters:
00348 %
00349 %  FIR (Finite impulse Response) Filters
00350 %      Box         Triangle   Quadratic
00351 %      Cubic       Hermite    Catrom
00352 %      Mitchell
00353 %
00354 %  IIR (Infinite impulse Response) Filters
00355 %      Gaussian     Sinc        Bessel
00356 %
00357 %  Windowed Sinc/Bessel Method
00358 %      Blackman     Hanning     Hamming
00359 %      Kaiser       Lancos (Sinc)
00360 %
00361 %  FIR filters are used as is, and are limited by that filters support window
00362 %  (unless over-ridden).  'Gaussian' while classed as an IIR filter, is also
00363 %  simply clipped by its support size (1.5).
00364 %
00365 %  Requesting a windowed filter will return either a windowed Sinc, for a one
00366 %  dimentional orthogonal filtering method, such as ResizeImage(), or a
00367 %  windowed Bessel for image operations requiring a two dimentional
00368 %  cylindrical filtering method, such a DistortImage().  Which function is
00369 %  is used set by the "cylindrical" boolean argument.
00370 %
00371 %  Directly requesting 'Sinc' or 'Bessel' will force the use of that filter
00372 %  function, with a default 'Blackman' windowing method.  This not however
00373 %  recommended as it removes the correct filter selection for different
00374 %  filtering image operations.  Selecting a window filtering method is better.
00375 %
00376 %  Lanczos is purely special case of a Sinc windowed Sinc, but defulting to
00377 %  a 3 lobe support, rather that the default 4 lobe support.
00378 %
00379 %  Special options can be used to override specific, or all the filter
00380 %  settings.   However doing so is not advisible unless you have expert
00381 %  knowledge of the use of resampling filtered techniques. Extreme caution is
00382 %  advised.
00383 %
00384 %    "filter:filter"    Select this function as the filter.
00385 %        If a "filter:window" operation is not provided, then no windowing
00386 %        will be performed on the selected filter, (support clipped)
00387 %
00388 %        This can be used to force the use of a windowing method as filter,
00389 %        request a 'Sinc' filter in a radially filtered operation, or the
00390 %        'Bessel' filter for a othogonal filtered operation.
00391 %
00392 %    "filter:window"   Select this windowing function for the filter.
00393 %        While any filter could be used as a windowing function,
00394 %        using that filters first lobe over the whole support window,
00395 %        using a non-windowing method is not advisible.
00396 %
00397 %    "filter:lobes"    Number of lobes to use for the Sinc/Bessel filter.
00398 %        This a simper method of setting filter support size that will
00399 %        correctly handle the Sinc/Bessel switch for an operators filtering
00400 %        requirements.
00401 %
00402 %    "filter:support"  Set the support size for filtering to the size given
00403 %        This not recomented for Sinc/Bessel windowed filters, but is
00404 %        used for simple filters like FIR filters, and the Gaussian Filter.
00405 %        This will override any 'filter:lobes' option.
00406 %
00407 %    "filter:blur"     Scale the filter and support window by this amount.
00408 %        A value >1 will generally result in a more burred image with
00409 %        more ringing effects, while a value <1 will sharpen the
00410 %        resulting image with more aliasing and Morie effects.
00411 %
00412 %    "filter:win-support"  Scale windowing function to this size instead.
00413 %        This causes the windowing (or self-windowing Lagrange filter)
00414 %        to act is if the support winodw it much much larger than what
00415 %        is actually supplied to the calling operator.  The filter however
00416 %        is still clipped to the real support size given.  If unset this
00417 %        will equal the normal filter support size.
00418 %
00419 %    "filter:b"
00420 %    "filter:c"    Override the preset B,C values for a Cubic type of filter
00421 %         If only one of these are given it is assumes to be a 'Keys'
00422 %         type of filter such that B+2C=1, where Keys 'alpha' value = C
00423 %
00424 %    "filter:verbose"   Output verbose plotting data for graphing the
00425 %         resulting filter over the whole support range (with blur effect).
00426 %
00427 %  Set a true un-windowed Sinc filter with 10 lobes (very slow)
00428 %     -set option:filter:filter  Sinc
00429 %     -set option:filter:lobes   8
00430 %
00431 %  For example force an 8 lobe Lanczos (Sinc or Bessel) filter...
00432 %     -filter Lanczos
00433 %     -set option:filter:lobes   8
00434 %
00435 %  The format of the AcquireResizeFilter method is:
00436 %
00437 %      ResizeFilter *AcquireResizeFilter(const Image *image,
00438 %        const FilterTypes filter_type, const MagickBooleanType radial,
00439 %        ExceptionInfo *exception)
00440 %
00441 %    o image: the image.
00442 %
00443 %    o filter: the filter type, defining a preset filter, window and support.
00444 %
00445 %    o blur: blur the filter by this amount, use 1.0 if unknown.
00446 %            Image artifact "filter:blur"  will override this old usage
00447 %
00448 %    o radial: 1D orthogonal filter (Sinc) or 2D radial filter (Bessel)
00449 %
00450 %    o exception: return any errors or warnings in this structure.
00451 %
00452 */
00453 MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
00454   const FilterTypes filter, const MagickRealType blur,
00455   const MagickBooleanType cylindrical,ExceptionInfo *exception)
00456 {
00457   const char
00458     *artifact;
00459 
00460   FilterTypes
00461     filter_type,
00462     window_type;
00463 
00464   long
00465     filter_artifact;
00466 
00467   MagickRealType
00468     B,
00469     C;
00470 
00471   register ResizeFilter
00472     *resize_filter;
00473 
00474   /*
00475     Table Mapping given Filter, into  Weighting and Windowing functions.
00476     A 'Box' windowing function means its a simble non-windowed filter.
00477     A 'Sinc' filter function (must be windowed) could be upgraded to a
00478     'Bessel' filter if a "cylindrical" filter is requested, unless a "Sinc"
00479     filter specifically request.
00480   */
00481   static struct
00482   {
00483     FilterTypes
00484       filter,
00485       window;
00486   } const mapping[SentinelFilter] =
00487   {
00488     { UndefinedFilter, BoxFilter },  /* undefined */
00489     { PointFilter,     BoxFilter },  /* special, nearest-neighbour filter */
00490     { BoxFilter,       BoxFilter },  /* Box averaging Filter */
00491     { TriangleFilter,  BoxFilter },  /* Linear Interpolation Filter */
00492     { HermiteFilter,   BoxFilter },      /* Hermite interpolation filter */
00493     { SincFilter,      HanningFilter },  /* Hanning -- Cosine-Sinc */
00494     { SincFilter,      HammingFilter },  /* Hamming --  '' variation */
00495     { SincFilter,      BlackmanFilter }, /* Blackman -- 2*Cosine-Sinc */
00496     { GaussianFilter,  BoxFilter },      /* Gaussain Blurring filter */
00497     { QuadraticFilter, BoxFilter },      /* Quadratic Gaussian approximation */
00498     { CubicFilter,     BoxFilter },      /* Cubic Gaussian approximation */
00499     { CatromFilter,    BoxFilter },      /* Cubic Interpolator */
00500     { MitchellFilter,  BoxFilter },      /* 'ideal' Cubic Filter */
00501     { LanczosFilter,   SincFilter },     /* Special, 3 lobed Sinc-Sinc */
00502     { BesselFilter,    BlackmanFilter }, /* 3 lobed bessel -specific request */
00503     { SincFilter,      BlackmanFilter }, /* 4 lobed sinc - specific request */
00504     { SincFilter,      KaiserFilter },   /* Kaiser --  SqRoot-Sinc */
00505     { SincFilter,      WelshFilter },    /* Welsh -- Parabolic-Sinc */
00506     { SincFilter,      CubicFilter },    /* Parzen -- Cubic-Sinc */
00507     { LagrangeFilter,  BoxFilter },      /* Lagrange self-windowing filter */
00508     { SincFilter,      BohmanFilter },   /* Bohman -- 2*Cosine-Sinc */
00509     { SincFilter,      TriangleFilter }  /* Bartlett -- Triangle-Sinc */
00510   };
00511   /*
00512     Table maping the filter/window function from the above table to the actual
00513     filter/window function call to use.  The default support size for that
00514     filter as a weighting function, and the point to scale when that function
00515     is used as a windowing function (typ 1.0).
00516   */
00517   static struct
00518   {
00519     MagickRealType
00520       (*function)(const MagickRealType, const ResizeFilter*),
00521       support,  /* default support size for function as a filter */
00522       scale,    /* size windowing function, for scaling windowing function */
00523       B,
00524       C;        /* Cubic Filter factors for a CubicBC function, else ignored */
00525   } const filters[SentinelFilter] =
00526   {
00527     { Box,       0.0f,  0.5f, 0.0f, 0.0f }, /* Undefined */
00528     { Box,       0.0f,  0.5f, 0.0f, 0.0f }, /* Point */
00529     { Box,       0.5f,  0.5f, 0.0f, 0.0f }, /* Box */
00530     { Triangle,  1.0f,  1.0f, 0.0f, 0.0f }, /* Triangle */
00531     { CubicBC,   1.0f,  1.0f, 0.0f, 0.0f }, /* Hermite, Cubic B=C=0 */
00532     { Hanning,   1.0f,  1.0f, 0.0f, 0.0f }, /* Hanning, Cosine window */
00533     { Hamming,   1.0f,  1.0f, 0.0f, 0.0f }, /* Hamming, '' variation */
00534     { Blackman,  1.0f,  1.0f, 0.0f, 0.0f }, /* Blackman, 2*cos window */
00535     { Gaussian,  1.5f,  1.5f, 0.0f, 0.0f }, /* Gaussian */
00536     { Quadratic, 1.5f,  1.5f, 0.0f, 0.0f }, /* Quadratic Gaussian */
00537     { CubicBC,   2.0f,  2.0f, 1.0f, 0.0f }, /* B-Spline of Gaussian B=1 C=0 */
00538     { CubicBC,   2.0f,  1.0f, 0.0f, 0.5f }, /* Catmull-Rom  B=0 C=1/2 */
00539     { CubicBC,   2.0f,  1.0f, 1.0f/3.0f, 1.0f/3.0f }, /* Mitchel B=C=1/3 */
00540     { Sinc,      3.0f,  1.0f, 0.0f, 0.0f }, /* Lanczos, 3 lobed Sinc-Sinc */
00541     { Bessel,    3.2383f,1.2197f,.0f,.0f }, /* 3 lobed Blackman-Bessel */
00542     { Sinc,      4.0f,  1.0f, 0.0f, 0.0f }, /* 4 lobed Blackman-Sinc   */
00543     { Kaiser,    1.0f,  1.0f, 0.0f, 0.0f }, /* Kaiser, sq-root windowing */
00544     { Welsh,     1.0f,  1.0f, 0.0f, 0.0f }, /* Welsh, Parabolic windowing */
00545     { CubicBC,   2.0f,  2.0f, 1.0f, 0.0f }, /* Parzen, B-Spline windowing */
00546     { Lagrange,  2.0f,  1.0f, 0.0f, 0.0f }, /* Lagrangian Filter */
00547     { Bohman,    1.0f,  1.0f, 0.0f, 0.0f }, /* Bohman, 2*Cosine windowing */
00548     { Triangle,  1.0f,  1.0f, 0.0f, 0.0f }  /* Bartlett, Triangle windowing */
00549   };
00550   /*
00551     The known zero crossings of the Bessel() or the Jinc(x*PI) function
00552     Found by using
00553       http://cose.math.bas.bg/webMathematica/webComputing/BesselZeros.jsp
00554     for Jv-function with v=1,  then dividing X-roots by PI (tabled below)
00555   */
00556   static MagickRealType
00557     bessel_zeros[16] =
00558     {
00559       1.21966989126651f,
00560       2.23313059438153f,
00561       3.23831548416624f,
00562       4.24106286379607f,
00563       5.24276437687019f,
00564       6.24392168986449f,
00565       7.24475986871996f,
00566       8.24539491395205f,
00567       9.24589268494948f,
00568       10.2462933487549f,
00569       11.2466227948779f,
00570       12.2468984611381f,
00571       13.2471325221811f,
00572       14.2473337358069f,
00573       15.2475085630373f,
00574       16.247661874701f
00575    };
00576 
00577   assert(image != (const Image *) NULL);
00578   assert(image->signature == MagickSignature);
00579   if (image->debug != MagickFalse)
00580     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00581   assert(UndefinedFilter < filter && filter < SentinelFilter);
00582   assert(exception != (ExceptionInfo *) NULL);
00583   assert(exception->signature == MagickSignature);
00584 
00585   resize_filter=(ResizeFilter *) AcquireMagickMemory(sizeof(*resize_filter));
00586   if (resize_filter == (ResizeFilter *) NULL)
00587     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00588 
00589   /* defaults for the requested filter */
00590   filter_type = mapping[filter].filter;
00591   window_type = mapping[filter].window;
00592 
00593 
00594   /* Filter blur -- scaling both filter and support window */
00595   resize_filter->blur = blur;
00596   artifact=GetImageArtifact(image,"filter:blur");
00597   if (artifact != (const char *) NULL)
00598     resize_filter->blur = atof(artifact);
00599   if ( resize_filter->blur < MagickEpsilon )
00600     resize_filter->blur = (MagickRealType) MagickEpsilon;
00601 
00602   /* Modifications for Cylindrical filter use */
00603   if ( cylindrical != MagickFalse && filter != SincFilter ) {
00604     /* promote 1D Sinc Filter to a 2D Bessel filter */
00605     if ( filter_type == SincFilter )
00606       filter_type = BesselFilter;
00607     /* Prompote Lanczos (Sinc-Sinc) to Lanczos (Bessel-Bessel) */
00608     else if ( filter_type == LanczosFilter ) {
00609       filter_type = BesselFilter;
00610       window_type = BesselFilter;
00611     }
00612    /* Blur other filters appropriatally correct cylindrical usage */
00613     else if ( filter_type == GaussianFilter )
00614       /* Gaussian is scaled by  4*ln(2) and not 4*sqrt(2/MagickPI)
00615          - according to Paul Heckbert's paper on EWA resampling */
00616       resize_filter->blur *= 2.0*log(2.0)/sqrt(2.0/MagickPI);
00617     else if ( filter_type != BesselFilter )
00618       /* filters with a 1.0 zero root crossing by the first bessel_zero */
00619       resize_filter->blur *= bessel_zeros[0];
00620   }
00621 
00622   /* Override Filter Selection */
00623   artifact=GetImageArtifact(image,"filter:filter");
00624   if (artifact != (const char *) NULL) {
00625     /* raw filter request - no window function */
00626     filter_artifact=ParseMagickOption(MagickFilterOptions,
00627          MagickFalse,artifact);
00628     if ( UndefinedFilter < filter_artifact &&
00629              filter_artifact < SentinelFilter ) {
00630       filter_type = (FilterTypes) filter_artifact;
00631       window_type = BoxFilter;
00632     }
00633     /* Lanczos is nor a real filter but a self windowing Sinc/Bessel */
00634     if ( filter_artifact == LanczosFilter ) {
00635       filter_type = (cylindrical!=MagickFalse) ? BesselFilter : LanczosFilter;
00636       window_type = (cylindrical!=MagickFalse) ? BesselFilter : SincFilter;
00637     }
00638     /* Filter overwide with a specific window function? */
00639     artifact=GetImageArtifact(image,"filter:window");
00640     if (artifact != (const char *) NULL) {
00641       filter_artifact=ParseMagickOption(MagickFilterOptions,
00642             MagickFalse,artifact);
00643       if ( UndefinedFilter < filter_artifact &&
00644                filter_artifact < SentinelFilter ) {
00645         if ( filter_artifact != LanczosFilter )
00646           window_type = (FilterTypes) filter_artifact;
00647         else
00648           window_type = (cylindrical!=MagickFalse) ? BesselFilter : SincFilter;
00649       }
00650     }
00651   }
00652   else {
00653     /* window specified, but no filter function?  Assume Sinc/Bessel */
00654     artifact=GetImageArtifact(image,"filter:window");
00655     if (artifact != (const char *) NULL) {
00656       filter_artifact=ParseMagickOption(MagickFilterOptions,MagickFalse,
00657         artifact);
00658       if ( UndefinedFilter < filter_artifact &&
00659                filter_artifact < SentinelFilter ) {
00660         filter_type = (cylindrical!=MagickFalse) ? BesselFilter : SincFilter;
00661         if ( filter_artifact != LanczosFilter )
00662           window_type = (FilterTypes) filter_artifact;
00663         else
00664           window_type = filter_type;
00665       }
00666     }
00667   }
00668 
00669   resize_filter->filter   = filters[filter_type].function;
00670   resize_filter->support  = filters[filter_type].support;
00671   resize_filter->window   = filters[window_type].function;
00672   resize_filter->scale    = filters[window_type].scale;
00673   resize_filter->signature=MagickSignature;
00674 
00675   /* Filter support overrides */
00676   artifact=GetImageArtifact(image,"filter:lobes");
00677   if (artifact != (const char *) NULL) {
00678     long lobes = atol(artifact);
00679     if ( lobes < 1  ) lobes = 1;
00680     resize_filter->support = (MagickRealType) lobes;
00681     if ( filter_type == BesselFilter ) {
00682       if ( lobes > 16 ) lobes = 16;
00683       resize_filter->support = bessel_zeros[lobes-1];
00684     }
00685   }
00686   artifact=GetImageArtifact(image,"filter:support");
00687   if (artifact != (const char *) NULL)
00688     resize_filter->support = fabs(atof(artifact));
00689 
00690   /* Scale windowing function separatally to the support 'clipping' window
00691      that calling operator is planning to actually use. - Expert Use Only
00692   */
00693   resize_filter->window_support = resize_filter->support;
00694   artifact=GetImageArtifact(image,"filter:win-support");
00695   if (artifact != (const char *) NULL)
00696     resize_filter->window_support = fabs(atof(artifact));
00697 
00698   /* Set Cubic Spline B,C values, calculate Cubic coefficents */
00699   B=0.0;
00700   C=0.0;
00701   if ( filters[filter_type].function == CubicBC
00702        || filters[window_type].function == CubicBC ) {
00703     if ( filters[filter_type].function == CubicBC ) {
00704       B=filters[filter_type].B;
00705       C=filters[filter_type].C;
00706     }
00707     else if ( filters[window_type].function == CubicBC ) {
00708       B=filters[window_type].B;
00709       C=filters[window_type].C;
00710     }
00711     artifact=GetImageArtifact(image,"filter:b");
00712     if (artifact != (const char *) NULL) {
00713       B=atof(artifact);
00714       C=1.0-2.0*B;  /* Calculate C as if it is a Keys cubic filter */
00715       artifact=GetImageArtifact(image,"filter:c");
00716       if (artifact != (const char *) NULL)
00717         C=atof(artifact);
00718     }
00719     else {
00720       artifact=GetImageArtifact(image,"filter:c");
00721       if (artifact != (const char *) NULL) {
00722         C=atof(artifact);
00723         B=(1.0-C)/2.0; /* Calculate B as if it is a Keys cubic filter */
00724       }
00725     }
00726     /* Convert B,C values into Cubic Coefficents - See CubicBC() */
00727     resize_filter->cubic[0]=(  6.0 -2.0*B       )/6.0;
00728     resize_filter->cubic[1]=0.0;
00729     resize_filter->cubic[2]=(-18.0+12.0*B+ 6.0*C)/6.0;
00730     resize_filter->cubic[3]=( 12.0- 9.0*B- 6.0*C)/6.0;
00731     resize_filter->cubic[4]=(       8.0*B+24.0*C)/6.0;
00732     resize_filter->cubic[5]=(     -12.0*B-48.0*C)/6.0;
00733     resize_filter->cubic[6]=(       6.0*B+30.0*C)/6.0;
00734     resize_filter->cubic[7]=(     - 1.0*B- 6.0*C)/6.0;
00735   }
00736   artifact=GetImageArtifact(image,"filter:verbose");
00737   if (artifact != (const char *) NULL)
00738     {
00739       double
00740         support,
00741         x;
00742 
00743       /*
00744         Output filter graph -- for graphing filter result.
00745       */
00746       support=GetResizeFilterSupport(resize_filter);
00747       (void) printf("# support = %lg\n",support);
00748       for (x=0.0; x <= support; x+=0.01f)
00749         (void) printf("%5.2lf\t%lf\n",x,GetResizeFilterWeight(resize_filter,x));
00750       (void) printf("%5.2lf\t%lf\n",support,0.0);
00751     }
00752   return(resize_filter);
00753 }
00754 
00755 /*
00756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00757 %                                                                             %
00758 %                                                                             %
00759 %                                                                             %
00760 %   A d a p t i v e R e s i z e I m a g e                                     %
00761 %                                                                             %
00762 %                                                                             %
00763 %                                                                             %
00764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00765 %
00766 %  AdaptiveResizeImage() adaptively resize image with pixel resampling.
00767 %
00768 %  The format of the AdaptiveResizeImage method is:
00769 %
00770 %      Image *AdaptiveResizeImage(const Image *image,
00771 %        const unsigned long columns,const unsigned long rows,
00772 %        ExceptionInfo *exception)
00773 %
00774 %  A description of each parameter follows:
00775 %
00776 %    o image: the image.
00777 %
00778 %    o columns: the number of columns in the resized image.
00779 %
00780 %    o rows: the number of rows in the resized image.
00781 %
00782 %    o exception: return any errors or warnings in this structure.
00783 %
00784 */
00785 MagickExport Image *AdaptiveResizeImage(const Image *image,
00786   const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
00787 {
00788 #define AdaptiveResizeImageTag  "Resize/Image"
00789 
00790   Image
00791     *resize_image;
00792 
00793   long
00794     y;
00795 
00796   MagickBooleanType
00797     proceed;
00798 
00799   MagickPixelPacket
00800     pixel;
00801 
00802   PointInfo
00803     offset;
00804 
00805   register IndexPacket
00806     *resize_indexes;
00807 
00808   register long
00809     x;
00810 
00811   register PixelPacket
00812     *q;
00813 
00814   ResampleFilter
00815     *resample_filter;
00816 
00817   ViewInfo
00818     *resize_view;
00819 
00820   /*
00821     Adaptively resize image.
00822   */
00823   assert(image != (const Image *) NULL);
00824   assert(image->signature == MagickSignature);
00825   if (image->debug != MagickFalse)
00826     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00827   assert(exception != (ExceptionInfo *) NULL);
00828   assert(exception->signature == MagickSignature);
00829   if ((columns == 0) || (rows == 0))
00830     return((Image *) NULL);
00831   if ((columns == image->columns) && (rows == image->rows))
00832     return(CloneImage(image,0,0,MagickTrue,exception));
00833   resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
00834   if (resize_image == (Image *) NULL)
00835     return((Image *) NULL);
00836   if (SetImageStorageClass(resize_image,DirectClass) == MagickFalse)
00837     {
00838       InheritException(exception,&resize_image->exception);
00839       resize_image=DestroyImage(resize_image);
00840       return((Image *) NULL);
00841     }
00842   GetMagickPixelPacket(image,&pixel);
00843   resample_filter=AcquireResampleFilter(image,exception);
00844   if (image->interpolate == UndefinedInterpolatePixel)
00845     (void) SetResampleFilterInterpolateMethod(resample_filter,
00846       MeshInterpolatePixel);
00847   resize_view=AcquireCacheView(resize_image);
00848   for (y=0; y < (long) resize_image->rows; y++)
00849   {
00850     q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
00851       exception);
00852     if (q == (PixelPacket *) NULL)
00853       break;
00854     resize_indexes=GetCacheViewAuthenticIndexQueue(resize_view);
00855     offset.y=((MagickRealType) y*image->rows/resize_image->rows);
00856     for (x=0; x < (long) resize_image->columns; x++)
00857     {
00858       offset.x=((MagickRealType) x*image->columns/resize_image->columns);
00859       (void) ResamplePixelColor(resample_filter,offset.x-0.5,offset.y-0.5,
00860         &pixel);
00861       SetPixelPacket(resize_image,&pixel,q,resize_indexes+x);
00862       q++;
00863     }
00864     if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
00865       break;
00866     proceed=SetImageProgress(image,AdaptiveResizeImageTag,y,image->rows);
00867     if (proceed == MagickFalse)
00868       break;
00869   }
00870   resample_filter=DestroyResampleFilter(resample_filter);
00871   resize_view=DestroyCacheView(resize_view);
00872   return(resize_image);
00873 }
00874 
00875 /*
00876 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00877 %                                                                             %
00878 %                                                                             %
00879 %                                                                             %
00880 +   B e s s e l O r d e r O n e                                               %
00881 %                                                                             %
00882 %                                                                             %
00883 %                                                                             %
00884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00885 %
00886 %  BesselOrderOne() computes the Bessel function of x of the first kind of
00887 %  order 0:
00888 %
00889 %    Reduce x to |x| since j1(x)= -j1(-x), and for x in (0,8]
00890 %
00891 %       j1(x) = x*j1(x);
00892 %
00893 %    For x in (8,inf)
00894 %
00895 %       j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1))
00896 %
00897 %    where x1 = x-3*pi/4. Compute sin(x1) and cos(x1) as follow:
00898 %
00899 %       cos(x1) =  cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
00900 %               =  1/sqrt(2) * (sin(x) - cos(x))
00901 %       sin(x1) =  sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
00902 %               = -1/sqrt(2) * (sin(x) + cos(x))
00903 %
00904 %  The format of the BesselOrderOne method is:
00905 %
00906 %      MagickRealType BesselOrderOne(MagickRealType x)
00907 %
00908 %  A description of each parameter follows:
00909 %
00910 %    o x: MagickRealType value.
00911 %
00912 */
00913 
00914 #undef I0
00915 static MagickRealType I0(MagickRealType x)
00916 {
00917   MagickRealType
00918     sum,
00919     t,
00920     y;
00921 
00922   register long
00923     i;
00924 
00925   /*
00926     Zeroth order Bessel function of the first kind.
00927   */
00928   sum=1.0;
00929   y=x*x/4.0;
00930   t=y;
00931   for (i=2; t > MagickEpsilon; i++)
00932   {
00933     sum+=t;
00934     t*=y/((MagickRealType) i*i);
00935   }
00936   return(sum);
00937 }
00938 
00939 #undef J1
00940 static MagickRealType J1(MagickRealType x)
00941 {
00942   MagickRealType
00943     p,
00944     q;
00945 
00946   register long
00947     i;
00948 
00949   static const double
00950     Pone[] =
00951     {
00952        0.581199354001606143928050809e+21,
00953       -0.6672106568924916298020941484e+20,
00954        0.2316433580634002297931815435e+19,
00955       -0.3588817569910106050743641413e+17,
00956        0.2908795263834775409737601689e+15,
00957       -0.1322983480332126453125473247e+13,
00958        0.3413234182301700539091292655e+10,
00959       -0.4695753530642995859767162166e+7,
00960        0.270112271089232341485679099e+4
00961     },
00962     Qone[] =
00963     {
00964       0.11623987080032122878585294e+22,
00965       0.1185770712190320999837113348e+20,
00966       0.6092061398917521746105196863e+17,
00967       0.2081661221307607351240184229e+15,
00968       0.5243710262167649715406728642e+12,
00969       0.1013863514358673989967045588e+10,
00970       0.1501793594998585505921097578e+7,
00971       0.1606931573481487801970916749e+4,
00972       0.1e+1
00973     };
00974 
00975   p=Pone[8];
00976   q=Qone[8];
00977   for (i=7; i >= 0; i--)
00978   {
00979     p=p*x*x+Pone[i];
00980     q=q*x*x+Qone[i];
00981   }
00982   return(p/q);
00983 }
00984 
00985 #undef P1
00986 static MagickRealType P1(MagickRealType x)
00987 {
00988   MagickRealType
00989     p,
00990     q;
00991 
00992   register long
00993     i;
00994 
00995   static const double
00996     Pone[] =
00997     {
00998       0.352246649133679798341724373e+5,
00999       0.62758845247161281269005675e+5,
01000       0.313539631109159574238669888e+5,
01001       0.49854832060594338434500455e+4,
01002       0.2111529182853962382105718e+3,
01003       0.12571716929145341558495e+1
01004     },
01005     Qone[] =
01006     {
01007       0.352246649133679798068390431e+5,
01008       0.626943469593560511888833731e+5,
01009       0.312404063819041039923015703e+5,
01010       0.4930396490181088979386097e+4,
01011       0.2030775189134759322293574e+3,
01012       0.1e+1
01013     };
01014 
01015   p=Pone[5];
01016   q=Qone[5];
01017   for (i=4; i >= 0; i--)
01018   {
01019     p=p*(8.0/x)*(8.0/x)+Pone[i];
01020     q=q*(8.0/x)*(8.0/x)+Qone[i];
01021   }
01022   return(p/q);
01023 }
01024 
01025 #undef Q1
01026 static MagickRealType Q1(MagickRealType x)
01027 {
01028   MagickRealType
01029     p,
01030     q;
01031 
01032   register long
01033     i;
01034 
01035   static const double
01036     Pone[] =
01037     {
01038       0.3511751914303552822533318e+3,
01039       0.7210391804904475039280863e+3,
01040       0.4259873011654442389886993e+3,
01041       0.831898957673850827325226e+2,
01042       0.45681716295512267064405e+1,
01043       0.3532840052740123642735e-1
01044     },
01045     Qone[] =
01046     {
01047       0.74917374171809127714519505e+4,
01048       0.154141773392650970499848051e+5,
01049       0.91522317015169922705904727e+4,
01050       0.18111867005523513506724158e+4,
01051       0.1038187585462133728776636e+3,
01052       0.1e+1
01053     };
01054 
01055   p=Pone[5];
01056   q=Qone[5];
01057   for (i=4; i >= 0; i--)
01058   {
01059     p=p*(8.0/x)*(8.0/x)+Pone[i];
01060     q=q*(8.0/x)*(8.0/x)+Qone[i];
01061   }
01062   return(p/q);
01063 }
01064 
01065 static MagickRealType BesselOrderOne(MagickRealType x)
01066 {
01067   MagickRealType
01068     p,
01069     q;
01070 
01071   if (x == 0.0)
01072     return(0.0);
01073   p=x;
01074   if (x < 0.0)
01075     x=(-x);
01076   if (x < 8.0)
01077     return(p*J1(x));
01078   q=sqrt((double) (2.0/(MagickPI*x)))*(P1(x)*(1.0/sqrt(2.0)*(sin((double) x)-
01079     cos((double) x)))-8.0/x*Q1(x)*(-1.0/sqrt(2.0)*(sin((double) x)+
01080     cos((double) x))));
01081   if (p < 0.0)
01082     q=(-q);
01083   return(q);
01084 }
01085 
01086 /*
01087 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01088 %                                                                             %
01089 %                                                                             %
01090 %                                                                             %
01091 +   D e s t r o y R e s i z e F i l t e r                                     %
01092 %                                                                             %
01093 %                                                                             %
01094 %                                                                             %
01095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01096 %
01097 %  DestroyResizeFilter() destroy the resize filter.
01098 %
01099 %  The format of the AcquireResizeFilter method is: