resample.c revision 2ab242ec7c723f9f95558b30f1275011aa582ca9
13ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
23ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
43ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
53ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
63ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%           RRRR    EEEEE   SSSSS   AAA   M   M  PPPP   L      EEEEE          %
73ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%           R   R   E       SS     A   A  MM MM  P   P  L      E              %
83ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%           RRRR    EEE      SSS   AAAAA  M M M  PPPP   L      EEE            %
93ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%           R R     E          SS  A   A  M   M  P      L      E              %
103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%           R  R    EEEEE   SSSSS  A   A  M   M  P      LLLLL  EEEEE          %
113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                      MagickCore Pixel Resampling Methods                    %
143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                              Software Design                                %
163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                John Cristy                                  %
173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                              Anthony Thyssen                                %
183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                August 2007                                  %
193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
217e41fe84a841d7b9d7b36b245b65e9dcb3314943cristy%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  dedicated to making software imaging solutions freely available.           %
233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  You may not use this file except in compliance with the License.  You may  %
253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  obtain a copy of the License at                                            %
263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    http://www.imagemagick.org/script/license.php                            %
283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Unless required by applicable law or agreed to in writing, software        %
303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distributed under the License is distributed on an "AS IS" BASIS,          %
313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  See the License for the specific language governing permissions and        %
333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  limitations under the License.                                             %
343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Include declarations.
423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/studio.h"
443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/artifact.h"
453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/color-private.h"
463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/cache.h"
473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/draw.h"
483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/exception-private.h"
493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/gem.h"
503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/image.h"
513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/image-private.h"
523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/log.h"
53d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony#include "magick/magick.h"
543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/memory_.h"
553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/pixel-private.h"
563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/quantum.h"
573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/random_.h"
583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/resample.h"
593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/resize.h"
603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/resize-private.h"
613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/transform.h"
623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#include "magick/signature-private.h"
6328ad1d779b6ca95852e860514185a7a97e06af77anthony#include "magick/utility.h"
643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
65490ab03a4e81aa0943087243055c77e3794d75d9anthony  EWA Resampling Options
66490ab03a4e81aa0943087243055c77e3794d75d9anthony*/
67c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
68c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony/* select ONE resampling method */
69c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#define EWA 1                 /* Normal EWA handling - raw or clamped */
70c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                              /* if 0 then use "High Quality EWA" */
71c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#define EWA_CLAMP 1           /* EWA Clamping from Nicolas Robidoux */
72c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
735b697cdb1ed6e391b98953aafd362bddad51b453anthony#define FILTER_LUT 1          /* Use a LUT rather then direct filter calls */
745b697cdb1ed6e391b98953aafd362bddad51b453anthony
75c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony/* output debugging information */
76490ab03a4e81aa0943087243055c77e3794d75d9anthony#define DEBUG_ELLIPSE 0       /* output ellipse info for debug */
772e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#define DEBUG_HIT_MISS 0      /* output hit/miss pixels (as gnuplot commands) */
782e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#define DEBUG_NO_PIXEL_HIT 0  /* Make pixels that fail to hit anything - RED */
79490ab03a4e81aa0943087243055c77e3794d75d9anthony
805b697cdb1ed6e391b98953aafd362bddad51b453anthony#if ! FILTER_DIRECT
815b697cdb1ed6e391b98953aafd362bddad51b453anthony#define WLUT_WIDTH 1024       /* size of the filter cache */
825b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
835b697cdb1ed6e391b98953aafd362bddad51b453anthony
84490ab03a4e81aa0943087243055c77e3794d75d9anthony/*
853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Typedef declarations.
863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
873ed852eea50f9d4cd633efb8c2b054b8e33c253cristystruct _ResampleFilter
883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CacheView
903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *view;
913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
92c4c8d13c0996fea659ce63c682c803e74c1abc8acristy  Image
93c4c8d13c0996fea659ce63c682c803e74c1abc8acristy    *image;
94c4c8d13c0996fea659ce63c682c803e74c1abc8acristy
952ab242ec7c723f9f95558b30f1275011aa582ca9cristy  MagickBooleanType
962ab242ec7c723f9f95558b30f1275011aa582ca9cristy    matte;
972ab242ec7c723f9f95558b30f1275011aa582ca9cristy
982ab242ec7c723f9f95558b30f1275011aa582ca9cristy  ColorspaceType
992ab242ec7c723f9f95558b30f1275011aa582ca9cristy    colorspace;
1002ab242ec7c723f9f95558b30f1275011aa582ca9cristy
1013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ExceptionInfo
1023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *exception;
1033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
1053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    debug;
1063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* Information about image being resampled */
108bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t
1093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    image_area;
1103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  InterpolatePixelMethod
1123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    interpolate;
1133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  VirtualPixelMethod
1153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    virtual_pixel;
1163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FilterTypes
1183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    filter;
1193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* processing settings needed */
1213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
1223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    limit_reached,
1233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    do_interpolate,
1243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    average_defined;
1253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickPixelPacket
1273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    average_pixel;
1283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* current ellipitical area being resampled around center point */
1303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
1313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    A, B, C,
132d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    Vlimit, Ulimit, Uwidth, slope;
1333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
134175defe3237b2e7bab13c9649a837500af6a82c7anthony#if FILTER_LUT
1353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* LUT of weights for filtered average in elliptical area */
1363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
1375b697cdb1ed6e391b98953aafd362bddad51b453anthony    filter_lut[WLUT_WIDTH];
1385b697cdb1ed6e391b98953aafd362bddad51b453anthony#else
1395b697cdb1ed6e391b98953aafd362bddad51b453anthony  /* Use a Direct call to the filter functions */
1405b697cdb1ed6e391b98953aafd362bddad51b453anthony  ResizeFilter
1415b697cdb1ed6e391b98953aafd362bddad51b453anthony    *filter_def;
142582b6d79fc381d6c9455f3f1b3e26923950161ebanthony
143582b6d79fc381d6c9455f3f1b3e26923950161ebanthony  double
144582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    F;
1455b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
1465b697cdb1ed6e391b98953aafd362bddad51b453anthony
1475b697cdb1ed6e391b98953aafd362bddad51b453anthony  /* the practical working support of the filter */
1485b697cdb1ed6e391b98953aafd362bddad51b453anthony  double
1493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    support;
1503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
151bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
1523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    signature;
1533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy};
1543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
1563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   A c q u i r e R e s a m p l e I n f o                                     %
1613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  AcquireResampleFilter() initializes the information resample needs do to a
1673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  scaled lookup of a color from an image, using area sampling.
1683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The algorithm is based on a Elliptical Weighted Average, where the pixels
1703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  found in a large elliptical area is averaged together according to a
1713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  weighting (filter) function.  For more details see "Fundamentals of Texture
1723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Mapping and Image Warping" a master's thesis by Paul.S.Heckbert, June 17,
1733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  1989.  Available for free from, http://www.cs.cmu.edu/~ph/
1743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  As EWA resampling (or any sort of resampling) can require a lot of
1763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  calculations to produce a distorted scaling of the source image for each
1773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  output pixel, the ResampleFilter structure generated holds that information
1783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  between individual image resampling.
1793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  This function will make the appropriate AcquireCacheView() calls
1813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  to view the image, calling functions do not need to open a cache view.
1823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Usage Example...
1843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      resample_filter=AcquireResampleFilter(image,exception);
185c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%      SetResampleFilter(resample_filter, GaussianFilter, 1.0);
186bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%      for (y=0; y < (ssize_t) image->rows; y++) {
187bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%        for (x=0; x < (ssize_t) image->columns; x++) {
188c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%          u= ....;   v= ....;
1893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%          ScaleResampleFilter(resample_filter, ... scaling vectors ...);
190c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%          (void) ResamplePixelColor(resample_filter,u,v,&pixel);
1913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%          ... assign resampled pixel value ...
1923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        }
1933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      }
1943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      DestroyResampleFilter(resample_filter);
1953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the AcquireResampleFilter method is:
1973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     ResampleFilter *AcquireResampleFilter(const Image *image,
1993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%       ExceptionInfo *exception)
2003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
2023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image: the image.
2043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o exception: return any errors or warnings in this structure.
2063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2083ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport ResampleFilter *AcquireResampleFilter(const Image *image,
2093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ExceptionInfo *exception)
2103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register ResampleFilter
2123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *resample_filter;
2133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
2153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image->signature == MagickSignature);
2163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
2173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(exception != (ExceptionInfo *) NULL);
2193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(exception->signature == MagickSignature);
2203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter=(ResampleFilter *) AcquireMagickMemory(
2223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    sizeof(*resample_filter));
2233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter == (ResampleFilter *) NULL)
2243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
2253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ResetMagickMemory(resample_filter,0,sizeof(*resample_filter));
2263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2272ab242ec7c723f9f95558b30f1275011aa582ca9cristy  resample_filter->exception=exception;
2283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->image=ReferenceImage((Image *) image);
2292ab242ec7c723f9f95558b30f1275011aa582ca9cristy  resample_filter->matte=image->matte;
2303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->view=AcquireCacheView(resample_filter->image);
2313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->debug=IsEventLogging();
2333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->signature=MagickSignature;
2343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2355b697cdb1ed6e391b98953aafd362bddad51b453anthony  resample_filter->image_area=(ssize_t) (image->columns*image->rows);
2363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->average_defined = MagickFalse;
2373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* initialise the resampling filter settings */
2395b697cdb1ed6e391b98953aafd362bddad51b453anthony  SetResampleFilter(resample_filter, image->filter, image->blur);
24082fea938ea2a766e32daddb7f2f69d66958e9d45cristy  (void) SetResampleFilterInterpolateMethod(resample_filter,
24182fea938ea2a766e32daddb7f2f69d66958e9d45cristy    image->interpolate);
24282fea938ea2a766e32daddb7f2f69d66958e9d45cristy  (void) SetResampleFilterVirtualPixelMethod(resample_filter,
24372949796e01f8b94a0976e74cb8eb3f86af280eaanthony    GetImageVirtualPixelMethod(image));
2443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(resample_filter);
2463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
2473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
2493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   D e s t r o y R e s a m p l e I n f o                                     %
2543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  DestroyResampleFilter() finalizes and cleans up the resampling
2603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  resample_filter as returned by AcquireResampleFilter(), freeing any memory
2613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  or other information as needed.
2623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the DestroyResampleFilter method is:
2643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      ResampleFilter *DestroyResampleFilter(ResampleFilter *resample_filter)
2663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
2683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: resampling information structure
2703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2723ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport ResampleFilter *DestroyResampleFilter(
2733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter)
2743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
2763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
2773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->image != (Image *) NULL);
2783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->debug != MagickFalse)
2793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->image->filename);
2813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->view=DestroyCacheView(resample_filter->view);
2823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->image=DestroyImage(resample_filter->image);
2835b697cdb1ed6e391b98953aafd362bddad51b453anthony#if ! FILTER_LUT
2845b697cdb1ed6e391b98953aafd362bddad51b453anthony  resample_filter->filter_def=DestroyResizeFilter(resample_filter->filter_def);
2855b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
2863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->signature=(~MagickSignature);
2873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter=(ResampleFilter *) RelinquishMagickMemory(resample_filter);
2883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(resample_filter);
2893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
2903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
2923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   I n t e r p o l a t e R e s a m p l e F i l t e r                         %
2973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
3003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  InterpolateResampleFilter() applies bi-linear or tri-linear interpolation
3033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  between a floating point coordinate and the pixels surrounding that
3043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  coordinate.  No pixel area resampling, or scaling of the result is
3053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  performed.
3063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the InterpolateResampleFilter method is:
3083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType InterpolateResampleFilter(
3103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        ResampleInfo *resample_filter,const InterpolatePixelMethod method,
3113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        const double x,const double y,MagickPixelPacket *pixel)
3123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
3143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resample filter.
3163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o method: the pixel clor interpolation method.
3183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o x,y: A double representing the current (x,y) position of the pixel.
3203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o pixel: return the interpolated pixel here.
3223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
3233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
3243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3253ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic inline double MagickMax(const double x,const double y)
3263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (x > y)
3283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(x);
3293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(y);
3303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3323ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic void BicubicInterpolate(const MagickPixelPacket *pixels,const double dx,
3333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickPixelPacket *pixel)
3343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickRealType
3363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    dx2,
3373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    p,
3383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    q,
3393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    r,
3403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    s;
3413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  dx2=dx*dx;
3433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  p=(pixels[3].red-pixels[2].red)-(pixels[0].red-pixels[1].red);
3443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  q=(pixels[0].red-pixels[1].red)-p;
3453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  r=pixels[2].red-pixels[0].red;
3463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  s=pixels[1].red;
3473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->red=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
3483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  p=(pixels[3].green-pixels[2].green)-(pixels[0].green-pixels[1].green);
3493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  q=(pixels[0].green-pixels[1].green)-p;
3503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  r=pixels[2].green-pixels[0].green;
3513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  s=pixels[1].green;
3523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->green=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
3533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  p=(pixels[3].blue-pixels[2].blue)-(pixels[0].blue-pixels[1].blue);
3543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  q=(pixels[0].blue-pixels[1].blue)-p;
3553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  r=pixels[2].blue-pixels[0].blue;
3563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  s=pixels[1].blue;
3573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->blue=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
3583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  p=(pixels[3].opacity-pixels[2].opacity)-(pixels[0].opacity-pixels[1].opacity);
3593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  q=(pixels[0].opacity-pixels[1].opacity)-p;
3603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  r=pixels[2].opacity-pixels[0].opacity;
3613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  s=pixels[1].opacity;
3623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->opacity=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
3633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (pixel->colorspace == CMYKColorspace)
3643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
3653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p=(pixels[3].index-pixels[2].index)-(pixels[0].index-pixels[1].index);
3663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      q=(pixels[0].index-pixels[1].index)-p;
3673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      r=pixels[2].index-pixels[0].index;
3683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      s=pixels[1].index;
3693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel->index=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
3703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
3713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3733ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic inline MagickRealType CubicWeightingFunction(const MagickRealType x)
3743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickRealType
3763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    alpha,
3773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    gamma;
3783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  alpha=MagickMax(x+2.0,0.0);
3803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gamma=1.0*alpha*alpha*alpha;
3813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  alpha=MagickMax(x+1.0,0.0);
3823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gamma-=4.0*alpha*alpha*alpha;
3833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  alpha=MagickMax(x+0.0,0.0);
3843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gamma+=6.0*alpha*alpha*alpha;
3853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  alpha=MagickMax(x-1.0,0.0);
3863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  gamma-=4.0*alpha*alpha*alpha;
3873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(gamma/6.0);
3883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3903ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic inline double MeshInterpolate(const PointInfo *delta,const double p,
3913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const double x,const double y)
3923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(delta->x*x+delta->y*y+(1.0-delta->x-delta->y)*p);
3943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
3953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
396bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic inline ssize_t NearestNeighbor(MagickRealType x)
3973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
3983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (x >= 0.0)
399bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    return((ssize_t) (x+0.5));
400bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  return((ssize_t) (x-0.5));
4013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
4023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4033ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType InterpolateResampleFilter(
4043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter,const InterpolatePixelMethod method,
4053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const double x,const double y,MagickPixelPacket *pixel)
4063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
4073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
4083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
4093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register const IndexPacket
4113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *indexes;
4123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register const PixelPacket
4143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *p;
4153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
416bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
4173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
4183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
4203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
4213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=MagickTrue;
4222e6ab68e6538e73abd8d77f505bc9f033c742f1canthony
4233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  switch (method)
4243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
4253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case AverageInterpolatePixel:
4263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
4273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
4283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[16];
4293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickRealType
4313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[16],
4323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma;
4333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
43454ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x)-1,
43554ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y)-1,4,4,resample_filter->exception);
4363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
4373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
4383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
4393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
4403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
4413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
4423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 16L; i++)
4433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        GetMagickPixelPacket(resample_filter->image,pixels+i);
4453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        SetMagickPixelPacket(resample_filter->image,p,indexes+i,pixels+i);
4463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[i]=1.0;
4472ab242ec7c723f9f95558b30f1275011aa582ca9cristy        if (resample_filter->matte != MagickFalse)
4483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
44946f08209f719f4adeea742c45873c2714e80cdb9cristy            alpha[i]=QuantumScale*((MagickRealType) GetAlphaPixelComponent(p));
4503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].red*=alpha[i];
4513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].green*=alpha[i];
4523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].blue*=alpha[i];
4532ab242ec7c723f9f95558b30f1275011aa582ca9cristy            if (pixels[i].colorspace == CMYKColorspace)
4543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[i].index*=alpha[i];
4553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
4563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma=alpha[i];
4573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
4583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->red+=gamma*0.0625*pixels[i].red;
4593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->green+=gamma*0.0625*pixels[i].green;
4603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->blue+=gamma*0.0625*pixels[i].blue;
4613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->opacity+=0.0625*pixels[i].opacity;
4622ab242ec7c723f9f95558b30f1275011aa582ca9cristy        if (pixel->colorspace == CMYKColorspace)
4633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel->index+=gamma*0.0625*pixels[i].index;
4643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        p++;
4653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
4673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
4683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case BicubicInterpolatePixel:
4693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
4703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
4713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[16],
4723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        u[4];
4733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickRealType
4753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[16];
4763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      PointInfo
4783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        delta;
4793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
48054ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x)-1,
48154ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y)-1,4,4,resample_filter->exception);
4823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
4833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
4843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
4853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
4863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
4873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
4883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 16L; i++)
4893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        GetMagickPixelPacket(resample_filter->image,pixels+i);
4913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        SetMagickPixelPacket(resample_filter->image,p,indexes+i,pixels+i);
4923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[i]=1.0;
4932ab242ec7c723f9f95558b30f1275011aa582ca9cristy        if (resample_filter->matte != MagickFalse)
4943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
49546f08209f719f4adeea742c45873c2714e80cdb9cristy            alpha[i]=QuantumScale*((MagickRealType) GetAlphaPixelComponent(p));
4963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].red*=alpha[i];
4973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].green*=alpha[i];
4983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].blue*=alpha[i];
4992ab242ec7c723f9f95558b30f1275011aa582ca9cristy            if (pixels[i].colorspace == CMYKColorspace)
5003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[i].index*=alpha[i];
5013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
5023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        p++;
5033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
5043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.x=x-floor(x);
5053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 4L; i++)
5063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        BicubicInterpolate(pixels+4*i,delta.x,u+i);
5073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.y=y-floor(y);
5083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      BicubicInterpolate(u,delta.y,pixel);
5093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
5103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
5113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case BilinearInterpolatePixel:
5123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    default:
5133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
5143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
5153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[4];
5163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickRealType
5183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[4],
5193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma;
5203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      PointInfo
5223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        delta,
5233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        epsilon;
5243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
52554ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x),
52654ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y),2,2,resample_filter->exception);
5273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
5283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
5303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
5313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
5333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 4L; i++)
5343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
5353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[i].red=(MagickRealType) p[i].red;
5363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[i].green=(MagickRealType) p[i].green;
5373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[i].blue=(MagickRealType) p[i].blue;
5383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[i].opacity=(MagickRealType) p[i].opacity;
5393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[i]=1.0;
5403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
5412ab242ec7c723f9f95558b30f1275011aa582ca9cristy      if (resample_filter->matte != MagickFalse)
5423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        for (i=0; i < 4L; i++)
5433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          alpha[i]=QuantumScale*((MagickRealType) QuantumRange-p[i].opacity);
5453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[i].red*=alpha[i];
5463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[i].green*=alpha[i];
5473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[i].blue*=alpha[i];
5483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (indexes != (IndexPacket *) NULL)
5503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        for (i=0; i < 4L; i++)
5513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
5523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[i].index=(MagickRealType) indexes[i];
5532ab242ec7c723f9f95558b30f1275011aa582ca9cristy          if (pixels[i].colorspace == CMYKColorspace)
5543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].index*=alpha[i];
5553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
5563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.x=x-floor(x);
5573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.y=y-floor(y);
5583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      epsilon.x=1.0-delta.x;
5593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      epsilon.y=1.0-delta.y;
5603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      gamma=((epsilon.y*(epsilon.x*alpha[0]+delta.x*alpha[1])+delta.y*
5613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (epsilon.x*alpha[2]+delta.x*alpha[3])));
5623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
5633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel->red=gamma*(epsilon.y*(epsilon.x*pixels[0].red+delta.x*
5643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1].red)+delta.y*(epsilon.x*pixels[2].red+delta.x*pixels[3].red));
5653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel->green=gamma*(epsilon.y*(epsilon.x*pixels[0].green+delta.x*
5663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1].green)+delta.y*(epsilon.x*pixels[2].green+delta.x*
5673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[3].green));
5683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel->blue=gamma*(epsilon.y*(epsilon.x*pixels[0].blue+delta.x*
5693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1].blue)+delta.y*(epsilon.x*pixels[2].blue+delta.x*
5703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[3].blue));
5713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixel->opacity=(epsilon.y*(epsilon.x*pixels[0].opacity+delta.x*
5723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1].opacity)+delta.y*(epsilon.x*pixels[2].opacity+delta.x*
5733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[3].opacity));
5742ab242ec7c723f9f95558b30f1275011aa582ca9cristy      if (pixel->colorspace == CMYKColorspace)
5753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->index=gamma*(epsilon.y*(epsilon.x*pixels[0].index+delta.x*
5763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[1].index)+delta.y*(epsilon.x*pixels[2].index+delta.x*
5773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels[3].index));
5783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
5793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
5803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case FilterInterpolatePixel:
5813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
58254ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      CacheView
58354ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        *filter_view;
58454ffe7c6780ec1e33f8707e228b962d1accf58f8cristy
5853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Image
5863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        *excerpt_image,
5873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        *filter_image;
5883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
5903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1];
5913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      RectangleInfo
5933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        geometry;
5943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      geometry.width=4L;
5963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      geometry.height=4L;
597bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      geometry.x=(ssize_t) floor(x)-1L;
598bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      geometry.y=(ssize_t) floor(y)-1L;
5993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      excerpt_image=ExcerptImage(resample_filter->image,&geometry,
6003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        resample_filter->exception);
6013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (excerpt_image == (Image *) NULL)
6023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
6043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
6063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      filter_image=ResizeImage(excerpt_image,1,1,resample_filter->image->filter,
6073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        resample_filter->image->blur,resample_filter->exception);
6083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      excerpt_image=DestroyImage(excerpt_image);
6093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (filter_image == (Image *) NULL)
6103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
6113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      filter_view=AcquireCacheView(filter_image);
6123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p=GetCacheViewVirtualPixels(filter_view,0,0,1,1,
6133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        resample_filter->exception);
6143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p != (const PixelPacket *) NULL)
6153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          indexes=GetVirtualIndexQueue(filter_image);
6173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          GetMagickPixelPacket(resample_filter->image,pixels);
6183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          SetMagickPixelPacket(resample_filter->image,p,indexes,pixel);
6193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
6203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      filter_view=DestroyCacheView(filter_view);
6213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      filter_image=DestroyImage(filter_image);
6223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
6233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
6243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case IntegerInterpolatePixel:
6253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
6263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
6273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1];
6283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
62954ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x),
63054ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y),1,1,resample_filter->exception);
6313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
6323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
6343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
6363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
6373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      GetMagickPixelPacket(resample_filter->image,pixels);
6383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      SetMagickPixelPacket(resample_filter->image,p,indexes,pixel);
6393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
6403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
6413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case MeshInterpolatePixel:
6423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
6433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
6443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[4];
6453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickRealType
6473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[4],
6483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma;
6493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      PointInfo
6513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        delta,
6523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        luminance;
6533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
65454ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x),
65554ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y),2,2,resample_filter->exception);
6563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
6573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
6593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
6603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
6613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
6623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 4L; i++)
6633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
6643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        GetMagickPixelPacket(resample_filter->image,pixels+i);
6653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        SetMagickPixelPacket(resample_filter->image,p,indexes+i,pixels+i);
6663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[i]=1.0;
6672ab242ec7c723f9f95558b30f1275011aa582ca9cristy        if (resample_filter->matte != MagickFalse)
6683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
66946f08209f719f4adeea742c45873c2714e80cdb9cristy            alpha[i]=QuantumScale*((MagickRealType) GetAlphaPixelComponent(p));
6703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].red*=alpha[i];
6713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].green*=alpha[i];
6723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixels[i].blue*=alpha[i];
6732ab242ec7c723f9f95558b30f1275011aa582ca9cristy            if (pixels[i].colorspace == CMYKColorspace)
6743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[i].index*=alpha[i];
6753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
6763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        p++;
6773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
6783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.x=x-floor(x);
6793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.y=y-floor(y);
6803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      luminance.x=MagickPixelLuminance(pixels+0)-MagickPixelLuminance(pixels+3);
6813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      luminance.y=MagickPixelLuminance(pixels+1)-MagickPixelLuminance(pixels+2);
6823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (fabs(luminance.x) < fabs(luminance.y))
6833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
6843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /*
6853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            Diagonal 0-3 NW-SE.
6863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          */
6873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (delta.x <= delta.y)
6883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
6893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              /*
6903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                Bottom-left triangle  (pixel:2, diagonal: 0-3).
6913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              */
6923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              delta.y=1.0-delta.y;
6933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=MeshInterpolate(&delta,alpha[2],alpha[3],alpha[0]);
6943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
6953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->red=gamma*MeshInterpolate(&delta,pixels[2].red,
6963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[3].red,pixels[0].red);
6973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->green=gamma*MeshInterpolate(&delta,pixels[2].green,
6983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[3].green,pixels[0].green);
6993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->blue=gamma*MeshInterpolate(&delta,pixels[2].blue,
7003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[3].blue,pixels[0].blue);
7013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[2].opacity,
7023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[3].opacity,pixels[0].opacity);
7032ab242ec7c723f9f95558b30f1275011aa582ca9cristy              if (pixel->colorspace == CMYKColorspace)
7043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixel->index=gamma*MeshInterpolate(&delta,pixels[2].index,
7053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  pixels[3].index,pixels[0].index);
7063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
7073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          else
7083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
7093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              /*
7103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                Top-right triangle (pixel:1, diagonal: 0-3).
7113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              */
7123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              delta.x=1.0-delta.x;
7133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=MeshInterpolate(&delta,alpha[1],alpha[0],alpha[3]);
7143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
7153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->red=gamma*MeshInterpolate(&delta,pixels[1].red,
7163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[0].red,pixels[3].red);
7173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->green=gamma*MeshInterpolate(&delta,pixels[1].green,
7183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[0].green,pixels[3].green);
7193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->blue=gamma*MeshInterpolate(&delta,pixels[1].blue,
7203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[0].blue,pixels[3].blue);
7213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[1].opacity,
7223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[0].opacity,pixels[3].opacity);
7232ab242ec7c723f9f95558b30f1275011aa582ca9cristy              if (pixel->colorspace == CMYKColorspace)
7243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixel->index=gamma*MeshInterpolate(&delta,pixels[1].index,
7253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  pixels[0].index,pixels[3].index);
7263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
7273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
7283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      else
7293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
7303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /*
7313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            Diagonal 1-2 NE-SW.
7323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          */
7333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (delta.x <= (1.0-delta.y))
7343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
7353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              /*
7363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                Top-left triangle (pixel 0, diagonal: 1-2).
7373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              */
7383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=MeshInterpolate(&delta,alpha[0],alpha[1],alpha[2]);
7393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
7403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->red=gamma*MeshInterpolate(&delta,pixels[0].red,
7413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[1].red,pixels[2].red);
7423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->green=gamma*MeshInterpolate(&delta,pixels[0].green,
7433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[1].green,pixels[2].green);
7443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->blue=gamma*MeshInterpolate(&delta,pixels[0].blue,
7453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[1].blue,pixels[2].blue);
7463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[0].opacity,
7473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[1].opacity,pixels[2].opacity);
7482ab242ec7c723f9f95558b30f1275011aa582ca9cristy              if (pixel->colorspace == CMYKColorspace)
7493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixel->index=gamma*MeshInterpolate(&delta,pixels[0].index,
7503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  pixels[1].index,pixels[2].index);
7513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
7523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          else
7533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
7543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              /*
7553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                Bottom-right triangle (pixel: 3, diagonal: 1-2).
7563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              */
7573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              delta.x=1.0-delta.x;
7583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              delta.y=1.0-delta.y;
7593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=MeshInterpolate(&delta,alpha[3],alpha[2],alpha[1]);
7603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
7613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->red=gamma*MeshInterpolate(&delta,pixels[3].red,
7623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[2].red,pixels[1].red);
7633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->green=gamma*MeshInterpolate(&delta,pixels[3].green,
7643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[2].green,pixels[1].green);
7653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->blue=gamma*MeshInterpolate(&delta,pixels[3].blue,
7663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[2].blue,pixels[1].blue);
7673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[3].opacity,
7683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[2].opacity,pixels[1].opacity);
7692ab242ec7c723f9f95558b30f1275011aa582ca9cristy              if (pixel->colorspace == CMYKColorspace)
7703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixel->index=gamma*MeshInterpolate(&delta,pixels[3].index,
7713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                  pixels[2].index,pixels[1].index);
7723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
7733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
7743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
7753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
7763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case NearestNeighborInterpolatePixel:
7773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
7783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
7793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[1];
7803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p=GetCacheViewVirtualPixels(resample_filter->view,NearestNeighbor(x),
7823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        NearestNeighbor(y),1,1,resample_filter->exception);
7833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
7843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
7853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
7863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
7873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
7883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
7893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      GetMagickPixelPacket(resample_filter->image,pixels);
7903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      SetMagickPixelPacket(resample_filter->image,p,indexes,pixel);
7913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
7923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
7933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case SplineInterpolatePixel:
7943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
7953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickPixelPacket
7963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixels[16];
7973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
7983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      MagickRealType
7993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        alpha[16],
8003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        dx,
8013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        dy,
8023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        gamma;
8033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      PointInfo
8053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        delta;
8063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
80754ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      ssize_t
80854ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        j,
80954ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        n;
81054ffe7c6780ec1e33f8707e228b962d1accf58f8cristy
81154ffe7c6780ec1e33f8707e228b962d1accf58f8cristy      p=GetCacheViewVirtualPixels(resample_filter->view,(ssize_t) floor(x)-1,
81254ffe7c6780ec1e33f8707e228b962d1accf58f8cristy        (ssize_t) floor(y)-1,4,4,resample_filter->exception);
8133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (p == (const PixelPacket *) NULL)
8143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
8153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          status=MagickFalse;
8163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
8173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
8183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
8193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      n=0;
8203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.x=x-floor(x);
8213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      delta.y=y-floor(y);
8223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=(-1); i < 3L; i++)
8233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
8243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        dy=CubicWeightingFunction((MagickRealType) i-delta.y);
8253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        for (j=(-1); j < 3L; j++)
8263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
8273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          GetMagickPixelPacket(resample_filter->image,pixels+n);
8283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          SetMagickPixelPacket(resample_filter->image,p,indexes+n,pixels+n);
8293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          alpha[n]=1.0;
8302ab242ec7c723f9f95558b30f1275011aa582ca9cristy          if (resample_filter->matte != MagickFalse)
8313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
83254ffe7c6780ec1e33f8707e228b962d1accf58f8cristy              alpha[n]=QuantumScale*((MagickRealType)
83354ffe7c6780ec1e33f8707e228b962d1accf58f8cristy                GetAlphaPixelComponent(p));
8343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[n].red*=alpha[n];
8353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[n].green*=alpha[n];
8363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              pixels[n].blue*=alpha[n];
8372ab242ec7c723f9f95558b30f1275011aa582ca9cristy              if (pixels[i].colorspace == CMYKColorspace)
8383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                pixels[n].index*=alpha[n];
8393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
8403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          dx=CubicWeightingFunction(delta.x-(MagickRealType) j);
8413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          gamma=alpha[n];
8423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
8433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel->red+=gamma*dx*dy*pixels[n].red;
8443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel->green+=gamma*dx*dy*pixels[n].green;
8453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel->blue+=gamma*dx*dy*pixels[n].blue;
8462ab242ec7c723f9f95558b30f1275011aa582ca9cristy          if (resample_filter->matte != MagickFalse)
8473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixel->opacity+=dx*dy*pixels[n].opacity;
8482ab242ec7c723f9f95558b30f1275011aa582ca9cristy          if (pixel->colorspace == CMYKColorspace)
8493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            pixel->index+=gamma*dx*dy*pixels[n].index;
8503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          n++;
8513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          p++;
8523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
8533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
8543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
8553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
8563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
8573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
8583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
8593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
8613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   R e s a m p l e P i x e l C o l o r                                       %
8663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
8693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  ResamplePixelColor() samples the pixel values surrounding the location
8723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  given using an elliptical weighted average, at the scale previously
8733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  calculated, and in the most efficent manner possible for the
8743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  VirtualPixelMethod setting.
8753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the ResamplePixelColor method is:
8773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     MagickBooleanType ResamplePixelColor(ResampleFilter *resample_filter,
8793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%       const double u0,const double v0,MagickPixelPacket *pixel)
8803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
8823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resample filter.
8843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o u0,v0: A double representing the center of the area to resample,
8863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        The distortion transformed transformed x,y coordinate.
8873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o pixel: the resampled pixel is returned here.
8893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
8903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
8913ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType ResamplePixelColor(
8923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter,const double u0,const double v0,
8933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickPixelPacket *pixel)
8943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
8953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
8963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
8973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
898490ab03a4e81aa0943087243055c77e3794d75d9anthony  ssize_t u,v, v1, v2, uw, hit;
8993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double u1;
9003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double U,V,Q,DQ,DDQ;
9013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double divisor_c,divisor_m;
9023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register double weight;
9033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register const PixelPacket *pixels;
9043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register const IndexPacket *indexes;
9053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
9063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
9073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=MagickTrue;
9093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  GetMagickPixelPacket(resample_filter->image,pixel);
9103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ( resample_filter->do_interpolate ) {
9113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status=InterpolateResampleFilter(resample_filter,
9123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->interpolate,u0,v0,pixel);
9133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(status);
9143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
9153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9162e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#if DEBUG_ELLIPSE
9172e6ab68e6538e73abd8d77f505bc9f033c742f1canthony  fprintf(stderr, "u0=%lf; v0=%lf;\n", u0, v0);
9182e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#endif
9192e6ab68e6538e73abd8d77f505bc9f033c742f1canthony
9203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
9213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Does resample area Miss the image?
9223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    And is that area a simple solid color - then return that color
9233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
9243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  hit = 0;
9253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  switch ( resample_filter->virtual_pixel ) {
9263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case BackgroundVirtualPixelMethod:
9273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case ConstantVirtualPixelMethod:
9283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case TransparentVirtualPixelMethod:
9293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case BlackVirtualPixelMethod:
9303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case GrayVirtualPixelMethod:
9313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case WhiteVirtualPixelMethod:
9323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case MaskVirtualPixelMethod:
9333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if ( resample_filter->limit_reached
934d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || u0 + resample_filter->Ulimit < 0.0
935d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
936d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || v0 + resample_filter->Vlimit < 0.0
937d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || v0 - resample_filter->Vlimit > (double) resample_filter->image->rows
9383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
9393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
9403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case UndefinedVirtualPixelMethod:
9433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case EdgeVirtualPixelMethod:
944d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    ( u0 + resample_filter->Ulimit < 0.0 && v0 + resample_filter->Vlimit < 0.0 )
945d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 + resample_filter->Ulimit < 0.0
946d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows )
947d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
948d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 + resample_filter->Vlimit < 0.0 )
949d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
950d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows )
9513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
9523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
9533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case HorizontalTileVirtualPixelMethod:
955d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    v0 + resample_filter->Vlimit < 0.0
956d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || v0 - resample_filter->Vlimit > (double) resample_filter->image->rows
9573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
9583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;  /* outside the horizontally tiled images. */
9593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case VerticalTileVirtualPixelMethod:
961d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    u0 + resample_filter->Ulimit < 0.0
962d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
9633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
9643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;  /* outside the vertically tiled images. */
9653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case DitherVirtualPixelMethod:
967d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony      if (    ( u0 + resample_filter->Ulimit < -32.0 && v0 + resample_filter->Vlimit < -32.0 )
968d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 + resample_filter->Ulimit < -32.0
969d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows+32.0 )
970d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns+32.0
971d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 + resample_filter->Vlimit < -32.0 )
972d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns+32.0
973d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows+32.0 )
9743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           )
9753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
9763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case TileVirtualPixelMethod:
9783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case MirrorVirtualPixelMethod:
9793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case RandomVirtualPixelMethod:
9803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case HorizontalTileEdgeVirtualPixelMethod:
9813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case VerticalTileEdgeVirtualPixelMethod:
9823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case CheckerTileVirtualPixelMethod:
9833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /* resampling of area is always needed - no VP limits */
9843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
9853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
9863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ( hit ) {
9873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* whole area is a solid color -- just return that color */
9883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status=InterpolateResampleFilter(resample_filter,IntegerInterpolatePixel,
9893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      u0,v0,pixel);
9903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(status);
9913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
9923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
9943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Scaling limits reached, return an 'averaged' result.
9953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
9963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ( resample_filter->limit_reached ) {
9973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    switch ( resample_filter->virtual_pixel ) {
9983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*  This is always handled by the above, so no need.
9993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case BackgroundVirtualPixelMethod:
10003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case ConstantVirtualPixelMethod:
10013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case TransparentVirtualPixelMethod:
10023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case GrayVirtualPixelMethod,
10033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case WhiteVirtualPixelMethod
10043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        case MaskVirtualPixelMethod:
10053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
10063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case UndefinedVirtualPixelMethod:
10073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case EdgeVirtualPixelMethod:
10083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case DitherVirtualPixelMethod:
10093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case HorizontalTileEdgeVirtualPixelMethod:
10103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case VerticalTileEdgeVirtualPixelMethod:
10119b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony        /* We need an average edge pixel, from the correct edge!
10123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           How should I calculate an average edge color?
10133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           Just returning an averaged neighbourhood,
10143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           works well in general, but falls down for TileEdge methods.
10153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           This needs to be done properly!!!!!!
10163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        */
10173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        status=InterpolateResampleFilter(resample_filter,
10183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          AverageInterpolatePixel,u0,v0,pixel);
10193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
10203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case HorizontalTileVirtualPixelMethod:
10213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case VerticalTileVirtualPixelMethod:
10223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        /* just return the background pixel - Is there more direct way? */
10233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        status=InterpolateResampleFilter(resample_filter,
10243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           IntegerInterpolatePixel,(double)-1,(double)-1,pixel);
10253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
10263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case TileVirtualPixelMethod:
10273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case MirrorVirtualPixelMethod:
10283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case RandomVirtualPixelMethod:
10293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case CheckerTileVirtualPixelMethod:
10303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      default:
10313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        /* generate a average color of the WHOLE image */
10323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if ( resample_filter->average_defined == MagickFalse ) {
10333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          Image
10343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            *average_image;
10353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          CacheView
10373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            *average_view;
10383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1039065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy          GetMagickPixelPacket(resample_filter->image,(MagickPixelPacket *)
1040065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy            &resample_filter->average_pixel);
1041065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy          resample_filter->average_defined=MagickTrue;
10423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
10433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /* Try to get an averaged pixel color of whole image */
1044065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy          average_image=ResizeImage(resample_filter->image,1,1,BoxFilter,1.0,
1045065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy            resample_filter->exception);
10463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (average_image == (Image *) NULL)
10473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            {
10483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              *pixel=resample_filter->average_pixel; /* FAILED */
10493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              break;
10503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            }
10513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          average_view=AcquireCacheView(average_image);
10523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixels=(PixelPacket *)GetCacheViewVirtualPixels(average_view,0,0,1,1,
10533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            resample_filter->exception);
10543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (pixels == (const PixelPacket *) NULL) {
10553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            average_view=DestroyCacheView(average_view);
10563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            average_image=DestroyImage(average_image);
10573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            *pixel=resample_filter->average_pixel; /* FAILED */
10583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            break;
10593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
10603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          indexes=(IndexPacket *) GetCacheViewAuthenticIndexQueue(average_view);
10613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          SetMagickPixelPacket(resample_filter->image,pixels,indexes,
10623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            &(resample_filter->average_pixel));
10633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          average_view=DestroyCacheView(average_view);
10643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          average_image=DestroyImage(average_image);
1065490ab03a4e81aa0943087243055c77e3794d75d9anthony
1066490ab03a4e81aa0943087243055c77e3794d75d9anthony          if ( resample_filter->virtual_pixel == CheckerTileVirtualPixelMethod )
1067490ab03a4e81aa0943087243055c77e3794d75d9anthony            {
1068490ab03a4e81aa0943087243055c77e3794d75d9anthony              /* CheckerTile is avergae of image average half background */
1069490ab03a4e81aa0943087243055c77e3794d75d9anthony              /* FUTURE: replace with a 50% blend of both pixels */
1070490ab03a4e81aa0943087243055c77e3794d75d9anthony
1071490ab03a4e81aa0943087243055c77e3794d75d9anthony              weight = QuantumScale*((MagickRealType)(QuantumRange-
1072490ab03a4e81aa0943087243055c77e3794d75d9anthony                          resample_filter->average_pixel.opacity));
1073490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.red *= weight;
1074490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.green *= weight;
1075490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.blue *= weight;
1076490ab03a4e81aa0943087243055c77e3794d75d9anthony              divisor_c = weight;
1077490ab03a4e81aa0943087243055c77e3794d75d9anthony
1078490ab03a4e81aa0943087243055c77e3794d75d9anthony              weight = QuantumScale*((MagickRealType)(QuantumRange-
1079490ab03a4e81aa0943087243055c77e3794d75d9anthony                          resample_filter->image->background_color.opacity));
1080490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.red +=
1081490ab03a4e81aa0943087243055c77e3794d75d9anthony                      weight*resample_filter->image->background_color.red;
1082490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.green +=
1083490ab03a4e81aa0943087243055c77e3794d75d9anthony                      weight*resample_filter->image->background_color.green;
1084490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.blue +=
1085490ab03a4e81aa0943087243055c77e3794d75d9anthony                      weight*resample_filter->image->background_color.blue;
1086bb66d9ce1d174e871ae1ac4ee9b300d1f0d5cdddcristy              resample_filter->average_pixel.opacity +=
1087490ab03a4e81aa0943087243055c77e3794d75d9anthony                      resample_filter->image->background_color.opacity;
1088490ab03a4e81aa0943087243055c77e3794d75d9anthony              divisor_c += weight;
1089490ab03a4e81aa0943087243055c77e3794d75d9anthony
1090490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.red /= divisor_c;
1091490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.green /= divisor_c;
1092490ab03a4e81aa0943087243055c77e3794d75d9anthony              resample_filter->average_pixel.blue /= divisor_c;
1093bb66d9ce1d174e871ae1ac4ee9b300d1f0d5cdddcristy              resample_filter->average_pixel.opacity /= 2;
1094490ab03a4e81aa0943087243055c77e3794d75d9anthony
1095490ab03a4e81aa0943087243055c77e3794d75d9anthony            }
10963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
10973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        *pixel=resample_filter->average_pixel;
10983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
10993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
11003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(status);
11013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
11023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
11043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize weighted average data collection
11053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
11063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  hit = 0;
11073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_c = 0.0;
11083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_m = 0.0;
11093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  pixel->red = pixel->green = pixel->blue = 0.0;
11102ab242ec7c723f9f95558b30f1275011aa582ca9cristy  if (resample_filter->matte != MagickFalse) pixel->opacity = 0.0;
11112ab242ec7c723f9f95558b30f1275011aa582ca9cristy  if (pixel->colorspace == CMYKColorspace) pixel->index = 0.0;
11123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
11143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Determine the parellelogram bounding box fitted to the ellipse
11153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    centered at u0,v0.  This area is bounding by the lines...
11163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1117490ab03a4e81aa0943087243055c77e3794d75d9anthony  v1 = (ssize_t)ceil(v0 - resample_filter->Vlimit);  /* range of scan lines */
1118490ab03a4e81aa0943087243055c77e3794d75d9anthony  v2 = (ssize_t)floor(v0 + resample_filter->Vlimit);
1119490ab03a4e81aa0943087243055c77e3794d75d9anthony
1120490ab03a4e81aa0943087243055c77e3794d75d9anthony  /* scan line start and width accross the parallelogram */
1121490ab03a4e81aa0943087243055c77e3794d75d9anthony  u1 = u0 + (v1-v0)*resample_filter->slope - resample_filter->Uwidth;
1122490ab03a4e81aa0943087243055c77e3794d75d9anthony  uw = (ssize_t)(2.0*resample_filter->Uwidth)+1;
11233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1124490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
1125490ab03a4e81aa0943087243055c77e3794d75d9anthony  fprintf(stderr, "v1=%ld; v2=%ld\n", (long)v1, (long)v2);
1126490ab03a4e81aa0943087243055c77e3794d75d9anthony  fprintf(stderr, "u1=%ld; uw=%ld\n", (long)u1, (long)uw);
1127490ab03a4e81aa0943087243055c77e3794d75d9anthony#else
1128490ab03a4e81aa0943087243055c77e3794d75d9anthony# define DEBUG_HIT_MISS 0 /* only valid if DEBUG_ELLIPSE is enabled */
1129490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
11303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
11323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Do weighted resampling of all pixels,  within the scaled ellipse,
11333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    bound by a Parellelogram fitted to the ellipse.
11343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
11353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  DDQ = 2*resample_filter->A;
1136490ab03a4e81aa0943087243055c77e3794d75d9anthony  for( v=v1; v<=v2;  v++ ) {
1137490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_HIT_MISS
1138490ab03a4e81aa0943087243055c77e3794d75d9anthony    long uu = ceil(u1);   /* actual pixel location (for debug only) */
1139490ab03a4e81aa0943087243055c77e3794d75d9anthony    fprintf(stderr, "# scan line from pixel %ld, %ld\n", (long)uu, (long)v);
1140490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
1141490ab03a4e81aa0943087243055c77e3794d75d9anthony    u = (ssize_t)ceil(u1);        /* first pixel in scanline */
1142490ab03a4e81aa0943087243055c77e3794d75d9anthony    u1 += resample_filter->slope; /* start of next scan line */
1143490ab03a4e81aa0943087243055c77e3794d75d9anthony
1144490ab03a4e81aa0943087243055c77e3794d75d9anthony
1145490ab03a4e81aa0943087243055c77e3794d75d9anthony    /* location of this first pixel, relative to u0,v0 */
1146490ab03a4e81aa0943087243055c77e3794d75d9anthony    U = (double)u-u0;
11473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    V = (double)v-v0;
11483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* Q = ellipse quotent ( if Q<F then pixel is inside ellipse) */
1150490ab03a4e81aa0943087243055c77e3794d75d9anthony    Q = (resample_filter->A*U + resample_filter->B*V)*U + resample_filter->C*V*V;
11513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    DQ = resample_filter->A*(2.0*U+1) + resample_filter->B*V;
11523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* get the scanline of pixels for this v */
1154bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    pixels=GetCacheViewVirtualPixels(resample_filter->view,u,v,(size_t) uw,
11553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      1,resample_filter->exception);
11563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (pixels == (const PixelPacket *) NULL)
11573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return(MagickFalse);
11583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    indexes=GetCacheViewVirtualIndexQueue(resample_filter->view);
11593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* count up the weighted pixel colors */
11613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    for( u=0; u<uw; u++ ) {
11625b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT
11633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /* Note that the ellipse has been pre-scaled so F = WLUT_WIDTH */
11643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if ( Q < (double)WLUT_WIDTH ) {
11653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        weight = resample_filter->filter_lut[(int)Q];
11665b697cdb1ed6e391b98953aafd362bddad51b453anthony#else
11675b697cdb1ed6e391b98953aafd362bddad51b453anthony      /* Note that the ellipse has been pre-scaled so F = support^2 */
1168582b6d79fc381d6c9455f3f1b3e26923950161ebanthony      if ( Q < (double)resample_filter->F ) {
1169582b6d79fc381d6c9455f3f1b3e26923950161ebanthony        weight = GetResizeFilterWeight(resample_filter->filter_def,
1170582b6d79fc381d6c9455f3f1b3e26923950161ebanthony             sqrt(Q));    /* a SquareRoot!  Arrggghhhhh... */
11715b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
11723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->opacity  += weight*pixels->opacity;
11743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        divisor_m += weight;
11753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11762ab242ec7c723f9f95558b30f1275011aa582ca9cristy        if (resample_filter->matte != MagickFalse)
11773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          weight *= QuantumScale*((MagickRealType)(QuantumRange-pixels->opacity));
11783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->red   += weight*pixels->red;
11793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->green += weight*pixels->green;
11803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel->blue  += weight*pixels->blue;
11812ab242ec7c723f9f95558b30f1275011aa582ca9cristy        if (pixel->colorspace == CMYKColorspace)
11823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          pixel->index += weight*(*indexes);
11833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        divisor_c += weight;
11843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
11853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        hit++;
1186490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_HIT_MISS
1187490ab03a4e81aa0943087243055c77e3794d75d9anthony        /* mark the pixel according to hit/miss of the ellipse */
1188490ab03a4e81aa0943087243055c77e3794d75d9anthony        fprintf(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 3\n",
1189490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu-.1,(double)v-.1,(long)uu+.1,(long)v+.1);
1190490ab03a4e81aa0943087243055c77e3794d75d9anthony        fprintf(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 3\n",
1191490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu+.1,(double)v-.1,(long)uu-.1,(long)v+.1);
1192490ab03a4e81aa0943087243055c77e3794d75d9anthony      } else {
1193490ab03a4e81aa0943087243055c77e3794d75d9anthony        fprintf(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 1\n",
1194490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu-.1,(double)v-.1,(long)uu+.1,(long)v+.1);
1195490ab03a4e81aa0943087243055c77e3794d75d9anthony        fprintf(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 1\n",
1196490ab03a4e81aa0943087243055c77e3794d75d9anthony                     (long)uu+.1,(double)v-.1,(long)uu-.1,(long)v+.1);
1197490ab03a4e81aa0943087243055c77e3794d75d9anthony      }
1198490ab03a4e81aa0943087243055c77e3794d75d9anthony      uu++;
1199490ab03a4e81aa0943087243055c77e3794d75d9anthony#else
12003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
1201490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
12023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      pixels++;
12033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      indexes++;
12043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Q += DQ;
12053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      DQ += DDQ;
12063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
12073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
1208490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
1209490ab03a4e81aa0943087243055c77e3794d75d9anthony  fprintf(stderr, "Hit=%ld;  Total=%ld;\n", (long)hit, (long)uw*(v2-v1) );
1210490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
12113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
12133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Result sanity check -- this should NOT happen
12143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1215490ab03a4e81aa0943087243055c77e3794d75d9anthony  if ( hit == 0 ) {
12163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* not enough pixels in resampling, resort to direct interpolation */
1217490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_NO_PIXEL_HIT
12189b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony    pixel->opacity = pixel->red = pixel->green = pixel->blue = 0;
12199b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony    pixel->red = QuantumRange; /* show pixels for which EWA fails */
12209b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony#else
12213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status=InterpolateResampleFilter(resample_filter,
12223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->interpolate,u0,v0,pixel);
12239b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony#endif
12243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return status;
12253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
12263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
12273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
12283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Finialize results of resampling
12293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
12303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_m = 1.0/divisor_m;
1231ce70c17bb6433add2eb069515a4f3105989e0662cristy  pixel->opacity = (MagickRealType) ClampToQuantum(divisor_m*pixel->opacity);
12323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  divisor_c = 1.0/divisor_c;
1233ce70c17bb6433add2eb069515a4f3105989e0662cristy  pixel->red   = (MagickRealType) ClampToQuantum(divisor_c*pixel->red);
1234ce70c17bb6433add2eb069515a4f3105989e0662cristy  pixel->green = (MagickRealType) ClampToQuantum(divisor_c*pixel->green);
1235ce70c17bb6433add2eb069515a4f3105989e0662cristy  pixel->blue  = (MagickRealType) ClampToQuantum(divisor_c*pixel->blue);
12362ab242ec7c723f9f95558b30f1275011aa582ca9cristy  if (pixel->colorspace == CMYKColorspace)
1237ce70c17bb6433add2eb069515a4f3105989e0662cristy    pixel->index = (MagickRealType) ClampToQuantum(divisor_c*pixel->index);
12383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
12393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
12403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1241c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA && EWA_CLAMP
1242c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony/*
1243c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1244c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1245c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1246c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1247c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony-   C l a m p U p A x e s                                                     %
1248c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1249c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1250c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%                                                                             %
1251c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1252c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
1253c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% ClampUpAxes() function converts the input vectors into a major and
125440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% minor axis unit vectors, and their magnitude.  This allows us to
125540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% ensure that the ellipse generated is never smaller than the unit
1256c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% circle and thus never too small for use in EWA resampling.
1257c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
1258c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% This purely mathematical 'magic' was provided by Professor Nicolas
1259c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% Robidoux and his Masters student Chantal Racette.
1260c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
126140ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% Reference: "We Recommend Singular Value Decomposition", David Austin
1262c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%   http://www.ams.org/samplings/feature-column/fcarc-svd
1263c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%
126440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% By generating major and minor axis vectors, we can actually use the
1265c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% ellipse in its "canonical form", by remapping the dx,dy of the
1266c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% sampled point into distances along the major and minor axis unit
1267c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% vectors.
126840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas%
126940ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% Reference: http://en.wikipedia.org/wiki/Ellipse#Canonical_form
1270c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony*/
127115c331b918b9c7b71e876965897b66ff6118a269nicolasstatic inline void ClampUpAxes(const double dux,
127215c331b918b9c7b71e876965897b66ff6118a269nicolas			       const double dvx,
127315c331b918b9c7b71e876965897b66ff6118a269nicolas			       const double duy,
127415c331b918b9c7b71e876965897b66ff6118a269nicolas			       const double dvy,
127515c331b918b9c7b71e876965897b66ff6118a269nicolas			       double *major_mag,
127615c331b918b9c7b71e876965897b66ff6118a269nicolas			       double *minor_mag,
127715c331b918b9c7b71e876965897b66ff6118a269nicolas			       double *major_unit_x,
127815c331b918b9c7b71e876965897b66ff6118a269nicolas			       double *major_unit_y,
127915c331b918b9c7b71e876965897b66ff6118a269nicolas			       double *minor_unit_x,
128015c331b918b9c7b71e876965897b66ff6118a269nicolas			       double *minor_unit_y)
1281c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony{
1282c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1283c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * ClampUpAxes takes an input 2x2 matrix
1284c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1285c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ a b ] = [ dux duy ]
1286c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ c d ] = [ dvx dvy ]
1287c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1288c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * and computes from it the major and minor axis vectors [major_x,
1289c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_y] and [minor_x,minor_y] of the smallest ellipse containing
1290c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * both the unit disk and the ellipse which is the image of the unit
1291c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * disk by the linear transformation
1292c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1293c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ dux duy ] [S] = [s]
1294c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * [ dvx dvy ] [T] = [t]
1295c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1296c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * (The vector [S,T] is the difference between a position in output
1297c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * space and [X,Y]; the vector [s,t] is the difference between a
1298c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * position in input space and [x,y].)
1299c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1300c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1301c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Outputs:
1302c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1303c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_mag is the half-length of the major axis of the "new"
130440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * ellipse.
1305c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1306c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * minor_mag is the half-length of the minor axis of the "new"
130740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * ellipse.
1308c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1309c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_unit_x is the x-coordinate of the major axis direction vector
1310c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * of both the "old" and "new" ellipses.
1311c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1312c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * major_unit_y is the y-coordinate of the major axis direction vector.
1313c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1314c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * minor_unit_x is the x-coordinate of the minor axis direction vector.
1315c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1316c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * minor_unit_y is the y-coordinate of the minor axis direction vector.
1317c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1318c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Unit vectors are useful for computing projections, in particular,
1319c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * to compute the distance between a point in output space and the
1320c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * center (of a disk) from the position of the corresponding point
1321c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * in input space.
1322c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1323c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * Now, if you want to modify the input pair of tangent vectors so
1324c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * that it defines the modified ellipse, all you have to do is set
1325c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
13268b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newdux = major_mag * major_unit_x
13278b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newdvx = major_mag * major_unit_y
13288b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newduy = minor_mag * minor_unit_x = minor_mag * -major_unit_y
13298b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * newdvy = minor_mag * minor_unit_y = minor_mag *  major_unit_x
1330c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1331932ef8479742364640c1aed64b795c528afab45cnicolas   * and use these tangent vectors as if they were the original ones.
133240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * Usually, this is a drastic change in the tangent vectors even if
1333c263aa7cbf22c73eb4fac5a90e333dfe6cc8c24bnicolas   * the singular values are not clamped; for example, the minor axis
1334c263aa7cbf22c73eb4fac5a90e333dfe6cc8c24bnicolas   * vector always points in a direction which is 90 degrees
1335c263aa7cbf22c73eb4fac5a90e333dfe6cc8c24bnicolas   * counterclockwise from the direction of the major axis vector.
1336c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1337c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1338c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Discussion:
1339c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1340c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * GOAL: Fix things so that the pullback, in input space, of a disk
1341c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * of radius r in output space is an ellipse which contains, at
1342c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * least, a disc of radius r. (Make this hold for any r>0.)
1343c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
134440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * ESSENCE OF THE METHOD: Compute the product of the first two
134540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * factors of an SVD of the linear transformation defining the
1346f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   * ellipse and make sure that both its columns have norm at least 1.
1347f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   * Because rotations and reflexions map disks to themselves, it is
134840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * not necessary to compute the third (rightmost) factor of the SVD.
1349f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   *
1350f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   * DETAILS: Find the singular values and (unit) left singular
1351f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   * vectors of Jinv, clampling up the singular values to 1, and
1352932ef8479742364640c1aed64b795c528afab45cnicolas   * multiply the unit left singular vectors by the new singular
1353f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas   * values in order to get the minor and major ellipse axis vectors.
1354c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
135540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * Image resampling context:
1356c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1357c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * The Jacobian matrix of the transformation at the output point
1358c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * under consideration is defined as follows:
1359c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1360c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Consider the transformation (x,y) -> (X,Y) from input locations
13618b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * to output locations. (Anthony Thyssen, elsewhere in resample.c,
136240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * uses the notation (u,v) -> (x,y).)
1363c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
136440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * The Jacobian matrix of the transformation at (x,y) is equal to
1365c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
136640ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *   J = [ A, B ] = [ dX/dx, dX/dy ]
136740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *       [ C, D ]   [ dY/dx, dY/dy ]
1368c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
136940ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * that is, the vector [A,C] is the tangent vector corresponding to
137040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * input changes in the horizontal direction, and the vector [B,D]
137140ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * is the tangent vector corresponding to input changes in the
137240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * vertical direction.
1373c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
137440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * In the context of resampling, it is natural to use the inverse
137540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * Jacobian matrix Jinv because resampling is generally performed by
137640ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * pulling pixel locations in the output image back to locations in
137740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * the input image. Jinv is
1378c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
137940ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *   Jinb = [ a, b ] = [ dx/dX, dx/dY ]
138040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *          [ c, d ]   [ dy/dX, dy/dY ]
1381c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1382c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Note: Jinv can be computed from J with the following matrix
1383c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * formula:
1384c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   *
1385c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   Jinv = 1/(A*D-B*C) [  D, -B ]
1386c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *                      [ -C,  A ]
1387c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
138840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * What we do is modify Jinv so that it generates an ellipse which
138940ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * is as close as possible to the original but which contains the
139040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * unit disk. This can be accomplished as follows:
1391c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1392c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * Let
1393c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1394c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   Jinv = U Sigma V^T
1395c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1396932ef8479742364640c1aed64b795c528afab45cnicolas   * be an SVD decomposition of Jinv. (The SVD is not unique, but the
139740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * final ellipse does not depend on the particular SVD.)
139840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *
139940ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * We could clamp up the entries of the diagonal matrix Sigma so
140040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * that they are at least 1, and then set
1401c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
1402c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *   Jinv = U newSigma V^T.
1403c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
140440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * However, we do not need to compute V for the following reason:
140540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * V^T is an orthogonal matrix (that is, it represents a combination
140640ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * of rotations and reflexions) so that it maps the unit circle to
140740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * itself. For this reason, the exact value of V does not affect the
140840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * final ellipse, and we can choose V to be the identity
140940ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * matrix. This gives
1410c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
141140ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   *   Jinv = U newSigma.
1412c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   *
141340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * In the end, we return the two diagonal entries of newSigma
141440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas   * together with the two columns of U.
1415c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1416c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1417c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * ClampUpAxes was written by Nicolas Robidoux and Chantal Racette
141847b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * of Laurentian University with insightful suggestions from Anthony
141947b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * Thyssen and funding from the National Science and Engineering
142047b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * Research Council of Canada. It is distinguished from its
142147b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * predecessors by its efficient handling of degenerate cases.
1422703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas   *
14238c741cc65e33be2570284c0217701c72c719aecbnicolas   * The idea of clamping up the EWA ellipse's major and minor axes so
14248c741cc65e33be2570284c0217701c72c719aecbnicolas   * that the result contains the reconstruction kernel filter support
142547b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * is taken from Andreas Gustaffson's Masters thesis "Interactive
142647b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * Image Warping", Helsinki University of Technology, Faculty of
142747b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * Information Technology, 59 pages, 1993 (see Section 3.6).
14288c741cc65e33be2570284c0217701c72c719aecbnicolas   *
142947b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * The use of the SVD to clamp up the singular values of the
143047b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * Jacobian matrix of the pullback transformation for EWA resampling
143147b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * is taken from the astrophysicist Craig DeForest.  It is
143247b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * implemented in his PDL::Transform code (PDL = Perl Data
143347b95659ad624c0c2e8011394239a29e9f1daa8cnicolas   * Language).
1434c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1435c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double a = dux;
1436c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double b = duy;
1437c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double c = dvx;
1438c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double d = dvy;
1439c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1440c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * n is the matrix Jinv * transpose(Jinv). Eigenvalues of n are the
1441c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * squares of the singular values of Jinv.
1442c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1443c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double aa = a*a;
1444c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double bb = b*b;
1445c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double cc = c*c;
1446c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double dd = d*d;
1447c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1448c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Eigenvectors of n are left singular vectors of Jinv.
1449c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1450c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n11 = aa+bb;
1451c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n12 = a*c+b*d;
1452c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n21 = n12;
1453c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double n22 = cc+dd;
1454c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double det = a*d-b*c;
1455c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double twice_det = det+det;
1456c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double frobenius_squared = n11+n22;
1457c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double discriminant =
1458c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    (frobenius_squared+twice_det)*(frobenius_squared-twice_det);
1459c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double sqrt_discriminant = sqrt(discriminant);
1460c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1461c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * s1 is the largest singular value of the inverse Jacobian
1462c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * matrix. In other words, its reciprocal is the smallest singular
1463c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * value of the Jacobian matrix itself.
1464c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * If s1 = 0, both singular values are 0, and any orthogonal pair of
1465c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * left and right factors produces a singular decomposition of Jinv.
1466c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   */
1467c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  /*
14688b1d981efa1bdef504b79420d43936c49eeecd3dnicolas   * Initially, we only compute the squares of the singular values.
1469c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1470c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1 = 0.5*(frobenius_squared+sqrt_discriminant);
1471c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1472c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * s2 the smallest singular value of the inverse Jacobian
1473c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * matrix. Its reciprocal is the largest singular value of the
1474c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Jacobian matrix itself.
1475c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1476c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s2s2 = 0.5*(frobenius_squared-sqrt_discriminant);
1477c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn11 = s1s1-n11;
1478c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn22 = s1s1-n22;
1479c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1480c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * u1, the first column of the U factor of a singular decomposition
1481c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * of Jinv, is a (non-normalized) left singular vector corresponding
1482c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * to s1. It has entries u11 and u21. We compute u1 from the fact
1483c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * that it is an eigenvector of n corresponding to the eigenvalue
1484c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * s1^2.
1485c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1486c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn11_squared = s1s1minusn11*s1s1minusn11;
1487c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double s1s1minusn22_squared = s1s1minusn22*s1s1minusn22;
1488c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1489c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * The following selects the largest row of n-s1^2 I as the one
1490c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * which is used to find the eigenvector. If both s1^2-n11 and
1491c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * s1^2-n22 are zero, n-s1^2 I is the zero matrix.  In that case,
1492c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * any vector is an eigenvector; in addition, norm below is equal to
1493c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * zero, and, in exact arithmetic, this is the only case in which
1494c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * norm = 0. So, setting u1 to the simple but arbitrary vector [1,0]
1495c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * if norm = 0 safely takes care of all cases.
1496c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1497c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double temp_u11 =
1498c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    ( (s1s1minusn11_squared>=s1s1minusn22_squared) ? n12 : s1s1minusn22 );
1499c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double temp_u21 =
1500c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    ( (s1s1minusn11_squared>=s1s1minusn22_squared) ? s1s1minusn11 : n21 );
1501c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double norm = sqrt(temp_u11*temp_u11+temp_u21*temp_u21);
1502c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1503c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Finalize the entries of first left singular vector (associated
1504c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * with the largest singular value).
1505c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1506c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double u11 = ( (norm>0.0) ? temp_u11/norm : 1.0 );
1507c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  const double u21 = ( (norm>0.0) ? temp_u21/norm : 0.0 );
1508c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /*
1509c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   * Clamp the singular values up to 1.
1510c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony   */
1511ed22721389b8ff2983982914d29db84731825a8fnicolas  *major_mag = ( (s1s1<=1.0) ? 1.0 : sqrt(s1s1) );
1512ed22721389b8ff2983982914d29db84731825a8fnicolas  *minor_mag = ( (s2s2<=1.0) ? 1.0 : sqrt(s2s2) );
1513c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  /*
1514c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   * Return the unit major and minor axis direction vectors.
1515c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas   */
1516c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  *major_unit_x = u11;
1517c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  *major_unit_y = u21;
1518c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  *minor_unit_x = -u21;
1519c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas  *minor_unit_y = u11;
1520c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony}
1521c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
1522c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif
15233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
15243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
15263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
15273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
15283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   S c a l e R e s a m p l e F i l t e r                                     %
15293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
15303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
15313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
15323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  ScaleResampleFilter() does all the calculations needed to resample an image
15353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  at a specific scale, defined by two scaling vectors.  This not using
15363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  a orthogonal scaling, but two distorted scaling vectors, to allow the
15373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  generation of a angled ellipse.
15383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  As only two deritive scaling vectors are used the center of the ellipse
15403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  must be the center of the lookup.  That is any curvature that the
15413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distortion may produce is discounted.
15423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The input vectors are produced by either finding the derivitives of the
15443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distortion function, or the partial derivitives from a distortion mapping.
15453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  They do not need to be the orthogonal dx,dy scaling vectors, but can be
15463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  calculated from other derivatives.  For example you could use  dr,da/r
15473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  polar coordinate vector scaling vectors
15483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1549c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  If   u,v =  DistortEquation(x,y)   OR   u = Fu(x,y); v = Fv(x,y)
1550c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  Then the scaling vectors are determined from the deritives...
15513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      du/dx, dv/dx     and    du/dy, dv/dy
1552c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  If the resulting scaling vectors is othogonally aligned then...
15533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      dv/dx = 0   and   du/dy  =  0
1554c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  Producing an othogonally alligned ellipse in source space for the area to
1555c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  be resampled.
15563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Note that scaling vectors are different to argument order.  Argument order
15583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  is the general order the deritives are extracted from the distortion
1559c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  equations, and not the scaling vectors. As such the middle two vaules
1560c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%  may be swapped from what you expect.  Caution is advised.
15613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15623ebea1e232532895681cd50101ddad0856e9a1d3anthony%  WARNING: It is assumed that any SetResampleFilter() method call will
15633ebea1e232532895681cd50101ddad0856e9a1d3anthony%  always be performed before the ScaleResampleFilter() method, so that the
15643ebea1e232532895681cd50101ddad0856e9a1d3anthony%  size of the ellipse will match the support for the resampling filter being
15653ebea1e232532895681cd50101ddad0856e9a1d3anthony%  used.
1566490ab03a4e81aa0943087243055c77e3794d75d9anthony%
15673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the ScaleResampleFilter method is:
15683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%     void ScaleResampleFilter(const ResampleFilter *resample_filter,
15703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%       const double dux,const double duy,const double dvx,const double dvy)
15713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
15733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resampling resample_filterrmation defining the
15753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      image being resampled
15763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o dux,duy,dvx,dvy:
1578c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         The deritives or scaling vectors defining the EWA ellipse.
1579c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         NOTE: watch the order, which is based on the order deritives
1580c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         are usally determined from distortion equations (see above).
1581c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         The middle two values may need to be swapped if you are thinking
1582c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%         in terms of scaling vectors.
15833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
15843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
15853ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport void ScaleResampleFilter(ResampleFilter *resample_filter,
15863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const double dux,const double duy,const double dvx,const double dvy)
15873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
1588d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  double A,B,C,F;
15893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
15903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
15913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
15923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
15933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->limit_reached = MagickFalse;
15943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1595b821aafe132291d46e0fb0c2b24e6e467aa17640anthony  /* A 'point' filter forces use of interpolation instead of area sampling */
1596b821aafe132291d46e0fb0c2b24e6e467aa17640anthony  if ( resample_filter->filter == PointFilter )
1597b821aafe132291d46e0fb0c2b24e6e467aa17640anthony    return; /* EWA turned off - nothing to do */
1598b821aafe132291d46e0fb0c2b24e6e467aa17640anthony
1599c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if DEBUG_ELLIPSE
1600c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  fprintf(stderr, "# -----\n" );
1601c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  fprintf(stderr, "dux=%lf; dvx=%lf;   duy=%lf; dvy=%lf;\n",
1602c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony       dux, dvx, duy, dvy);
1603c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif
16043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
16053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* Find Ellipse Coefficents such that
16063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        A*u^2 + B*u*v + C*v^2 = F
16073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     With u,v relative to point around which we are resampling.
16083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     And the given scaling dx,dy vectors in u,v space
16093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy         du/dx,dv/dx   and  du/dy,dv/dy
16103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1611c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA
1612d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  /* Direct conversion of derivatives into elliptical coefficients
1613b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     However when magnifying images, the scaling vectors will be small
1614b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     resulting in a ellipse that is too small to sample properly.
1615b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     As such we need to clamp the major/minor axis to a minumum of 1.0
1616b821aafe132291d46e0fb0c2b24e6e467aa17640anthony     to prevent it getting too small.
16173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1618c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA_CLAMP
1619c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  { double major_mag,
1620c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           minor_mag,
1621c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           major_x,
1622c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           major_y,
1623c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           minor_x,
1624c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony           minor_y;
1625c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
1626c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  ClampUpAxes(dux,dvx,duy,dvy, &major_mag, &minor_mag,
1627c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony                &major_x, &major_y, &minor_x, &minor_y);
1628bdfddb0056c20dba73d299334525256fa6a99986anthony  major_x *= major_mag;  major_y *= major_mag;
1629bdfddb0056c20dba73d299334525256fa6a99986anthony  minor_x *= minor_mag;  minor_y *= minor_mag;
1630c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if DEBUG_ELLIPSE
1631c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  fprintf(stderr, "major_x=%lf; major_y=%lf;  minor_x=%lf; minor_y=%lf;\n",
1632c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony        major_x, major_y, minor_x, minor_y);
1633c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif
1634c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  A = major_y*major_y+minor_y*minor_y;
1635c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  B = -2.0*(major_x*major_y+minor_x*minor_y);
1636c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  C = major_x*major_x+minor_x*minor_x;
1637eaa08628db6764fa5cb6802eaf9bb5753c25eb1fnicolas  F = major_mag*minor_mag;
1638c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  F *= F; /* square it */
1639c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  }
16405b697cdb1ed6e391b98953aafd362bddad51b453anthony#else /* raw unclamped EWA */
16413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  A = dvx*dvx+dvy*dvy;
1642d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  B = -2.0*(dux*dvx+duy*dvy);
16433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  C = dux*dux+duy*duy;
1644c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  F = dux*dvy-duy*dvx;
16455708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony  F *= F; /* square it */
16465b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif /* EWA_CLAMP */
1647d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
1648490ab03a4e81aa0943087243055c77e3794d75d9anthony#else /* HQ_EWA */
1649d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  /*
1650c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    This Paul Heckbert's "Higher Quality EWA" formula, from page 60 in his
1651c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    thesis, which adds a unit circle to the elliptical area so as to do both
1652c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    Reconstruction and Prefiltering of the pixels in the resampling.  It also
1653c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    means it is always likely to have at least 4 pixels within the area of the
1654c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    ellipse, for weighted averaging.  No scaling will result with F == 4.0 and
1655c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    a circle of radius 2.0, and F smaller than this means magnification is
1656c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    being used.
1657c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony
1658c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    NOTE: This method produces a very blury result at near unity scale while
1659bdfddb0056c20dba73d299334525256fa6a99986anthony    producing perfect results for strong minitification and magnifications.
1660490ab03a4e81aa0943087243055c77e3794d75d9anthony
1661c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    However filter support is fixed to 2.0 (no good for Windowed Sinc filters)
16623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
16633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  A = dvx*dvx+dvy*dvy+1;
1664d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  B = -2.0*(dux*dvx+duy*dvy);
16653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  C = dux*dux+duy*duy+1;
16663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  F = A*C - B*B/4;
16673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
16683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1669490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
16703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fprintf(stderr, "A=%lf; B=%lf; C=%lf; F=%lf\n", A,B,C,F);
16713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1672c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  /* Figure out the various information directly about the ellipse.
16733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     This information currently not needed at this time, but may be
16743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     needed later for better limit determination.
1675d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
1676d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony     It is also good to have as a record for future debugging
16773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
16783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  { double alpha, beta, gamma, Major, Minor;
1679490ab03a4e81aa0943087243055c77e3794d75d9anthony    double Eccentricity, Ellipse_Area, Ellipse_Angle;
1680d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
16813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    alpha = A+C;
16823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    beta  = A-C;
16833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    gamma = sqrt(beta*beta + B*B );
16843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
16853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if ( alpha - gamma <= MagickEpsilon )
16863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Major = MagickHuge;
16873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    else
16883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Major = sqrt(2*F/(alpha - gamma));
16893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Minor = sqrt(2*F/(alpha + gamma));
16903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1691490ab03a4e81aa0943087243055c77e3794d75d9anthony    fprintf(stderr, "# Major=%lf; Minor=%lf\n", Major, Minor );
16923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
16933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* other information about ellipse include... */
16943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Eccentricity = Major/Minor;
16953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Ellipse_Area = MagickPI*Major*Minor;
1696e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas    Ellipse_Angle = atan2(B, A-C);
16973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1698c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    fprintf(stderr, "# Angle=%lf   Area=%lf\n",
1699e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas         RadiansToDegrees(Ellipse_Angle), Ellipse_Area);
17003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
17013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif
17023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
170315c331b918b9c7b71e876965897b66ff6118a269nicolas  /* If one or both of the scaling vectors is impossibly large
170415c331b918b9c7b71e876965897b66ff6118a269nicolas     (producing a very large raw F value), we may as well not bother
170515c331b918b9c7b71e876965897b66ff6118a269nicolas     doing any form of resampling since resampled area is very large.
170615c331b918b9c7b71e876965897b66ff6118a269nicolas     In this case some alternative means of pixel sampling, such as
170715c331b918b9c7b71e876965897b66ff6118a269nicolas     the average of the whole image is needed to get a reasonable
170815c331b918b9c7b71e876965897b66ff6118a269nicolas     result. Calculate only as needed.
17093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
1710490ab03a4e81aa0943087243055c77e3794d75d9anthony  if ( (4*A*C - B*B) > MagickHuge ) {
17113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->limit_reached = MagickTrue;
17123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return;
17133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
17143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1715582b6d79fc381d6c9455f3f1b3e26923950161ebanthony  /* Scale ellipse to match the filters support
1716582b6d79fc381d6c9455f3f1b3e26923950161ebanthony     (that is, multiply F by the square of the support).
1717e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  */
1718490ab03a4e81aa0943087243055c77e3794d75d9anthony  F *= resample_filter->support;
1719490ab03a4e81aa0943087243055c77e3794d75d9anthony  F *= resample_filter->support;
17203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1721e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  /* Orthogonal bounds of the ellipse */
1722490ab03a4e81aa0943087243055c77e3794d75d9anthony  resample_filter->Ulimit = sqrt(4*C*F/(4*A*C-B*B));
1723490ab03a4e81aa0943087243055c77e3794d75d9anthony  resample_filter->Vlimit = sqrt(4*A*F/(4*A*C-B*B));
17243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1725e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  /* Horizontally aligned parallelogram fitted to Ellipse */
1726e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  resample_filter->Uwidth = sqrt(F/A); /* Half of the parallelogram width */
1727e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  resample_filter->slope = -B/(2*A); /* Reciprocal slope of the parallelogram */
1728490ab03a4e81aa0943087243055c77e3794d75d9anthony
1729490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE
1730490ab03a4e81aa0943087243055c77e3794d75d9anthony  fprintf(stderr, "Ulimit=%lf; Vlimit=%lf; UWidth=%lf; Slope=%lf;\n",
1731490ab03a4e81aa0943087243055c77e3794d75d9anthony           resample_filter->Ulimit, resample_filter->Vlimit,
1732490ab03a4e81aa0943087243055c77e3794d75d9anthony           resample_filter->Uwidth, resample_filter->slope );
1733490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
17343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1735e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  /* Check the absolute area of the parallelogram involved.
1736e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas   * This limit needs more work, as it is too slow for larger images
1737e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas   * with tiled views of the horizon.
1738e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas  */
173939f347aa142535ededfff86309cc2bb4cf222373cristy  if ( (resample_filter->Uwidth * resample_filter->Vlimit)
174039f347aa142535ededfff86309cc2bb4cf222373cristy         > (4.0*resample_filter->image_area)) {
17413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->limit_reached = MagickTrue;
17423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return;
17433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
17443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
17455708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony  /* Scale ellipse formula to directly index the Filter Lookup Table */
17463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  { register double scale;
17475b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT
1748582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    /* scale so that F = WLUT_WIDTH; -- hardcoded */
1749490ab03a4e81aa0943087243055c77e3794d75d9anthony    scale = (double)WLUT_WIDTH/F;
17505b697cdb1ed6e391b98953aafd362bddad51b453anthony#else
1751582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    /* scale so that F = resample_filter->F (support^2) */
1752582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    scale = resample_filter->F/F;
17535b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
17543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->A = A*scale;
17553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->B = B*scale;
17563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    resample_filter->C = C*scale;
17573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
17583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
17593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
17603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
17613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
17623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   S e t R e s a m p l e F i l t e r                                         %
17663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
17693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
17703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  SetResampleFilter() set the resampling filter lookup table based on a
17723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  specific filter.  Note that the filter is used as a radial filter not as a
17733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  two pass othogonally aligned resampling filter.
17743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The default Filter, is Gaussian, which is the standard filter used by the
17763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  original paper on the Elliptical Weighted Everage Algorithm. However other
17773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  filters can also be used.
17783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the SetResampleFilter method is:
17803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    void SetResampleFilter(ResampleFilter *resample_filter,
17823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      const FilterTypes filter,const double blur)
17833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
17853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: resampling resample_filterrmation structure
17873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o filter: the resize filter for elliptical weighting LUT
17893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o blur: filter blur factor (radial scaling) for elliptical weighting LUT
17913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
17923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
17933ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport void SetResampleFilter(ResampleFilter *resample_filter,
17943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const FilterTypes filter,const double blur)
17953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
17963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResizeFilter
17973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     *resize_filter;
17983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
17993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
18003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
18013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
18022e6ab68e6538e73abd8d77f505bc9f033c742f1canthony  resample_filter->do_interpolate = MagickFalse;
18033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->filter = filter;
18043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1805490ab03a4e81aa0943087243055c77e3794d75d9anthony  if ( filter == PointFilter )
1806b821aafe132291d46e0fb0c2b24e6e467aa17640anthony    {
1807b821aafe132291d46e0fb0c2b24e6e467aa17640anthony      resample_filter->do_interpolate = MagickTrue;
1808b821aafe132291d46e0fb0c2b24e6e467aa17640anthony      return;  /* EWA turned off - nothing more to do */
1809b821aafe132291d46e0fb0c2b24e6e467aa17640anthony    }
18103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
181161b5ddd7008c09f611076719e86f6f65ef5a9a4danthony  /* Set a default cylindrical filter of a 'low blur' Jinc windowed Jinc */
1812490ab03a4e81aa0943087243055c77e3794d75d9anthony  if ( filter == UndefinedFilter )
1813853d6979aa2981592af7020163b5030aa7185783anthony    resample_filter->filter = RobidouxFilter;
1814490ab03a4e81aa0943087243055c77e3794d75d9anthony
1815490ab03a4e81aa0943087243055c77e3794d75d9anthony  resize_filter = AcquireResizeFilter(resample_filter->image,
1816490ab03a4e81aa0943087243055c77e3794d75d9anthony       resample_filter->filter,blur,MagickTrue,resample_filter->exception);
1817bdfddb0056c20dba73d299334525256fa6a99986anthony  if (resize_filter == (ResizeFilter *) NULL)
1818490ab03a4e81aa0943087243055c77e3794d75d9anthony    {
18193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ThrowMagickException(resample_filter->exception,GetMagickModule(),
18203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           ModuleError, "UnableToSetFilteringValue",
18213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy           "Fall back to default EWA gaussian filter");
1822490ab03a4e81aa0943087243055c77e3794d75d9anthony      resample_filter->filter = PointFilter;
18233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1824490ab03a4e81aa0943087243055c77e3794d75d9anthony
182510b8bc801774c852503dfc90a706dfa942f9cc2eanthony  /* Get the practical working support for the filter,
182610b8bc801774c852503dfc90a706dfa942f9cc2eanthony   * after any API call blur factors have been accoded for.
182710b8bc801774c852503dfc90a706dfa942f9cc2eanthony   */
1828c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA
1829490ab03a4e81aa0943087243055c77e3794d75d9anthony  resample_filter->support = GetResizeFilterSupport(resize_filter);
1830c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#else
1831c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony  resample_filter->support = 2.0;  /* fixed support size for HQ-EWA */
1832490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif
1833490ab03a4e81aa0943087243055c77e3794d75d9anthony
18345b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT
18355b697cdb1ed6e391b98953aafd362bddad51b453anthony  /* Fill the LUT with the weights from the selected filter function */
18365b697cdb1ed6e391b98953aafd362bddad51b453anthony  { register int
18375b697cdb1ed6e391b98953aafd362bddad51b453anthony       Q;
18385b697cdb1ed6e391b98953aafd362bddad51b453anthony    double
18395b697cdb1ed6e391b98953aafd362bddad51b453anthony       r_scale;
18405b697cdb1ed6e391b98953aafd362bddad51b453anthony    /* Scale radius so the filter LUT covers the full support range */
18415b697cdb1ed6e391b98953aafd362bddad51b453anthony    r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH);
18425b697cdb1ed6e391b98953aafd362bddad51b453anthony    for(Q=0; Q<WLUT_WIDTH; Q++)
18435b697cdb1ed6e391b98953aafd362bddad51b453anthony      resample_filter->filter_lut[Q] = (double)
18445b697cdb1ed6e391b98953aafd362bddad51b453anthony           GetResizeFilterWeight(resize_filter,sqrt((double)Q)*r_scale);
18455b697cdb1ed6e391b98953aafd362bddad51b453anthony
18465b697cdb1ed6e391b98953aafd362bddad51b453anthony    /* finished with the resize filter */
18475b697cdb1ed6e391b98953aafd362bddad51b453anthony    resize_filter = DestroyResizeFilter(resize_filter);
18485b697cdb1ed6e391b98953aafd362bddad51b453anthony  }
18495b697cdb1ed6e391b98953aafd362bddad51b453anthony#else
1850582b6d79fc381d6c9455f3f1b3e26923950161ebanthony  /* save the filter and the scaled ellipse bounds needed for filter */
18515b697cdb1ed6e391b98953aafd362bddad51b453anthony  resample_filter->filter_def = resize_filter;
1852582b6d79fc381d6c9455f3f1b3e26923950161ebanthony  resample_filter->F = resample_filter->support*resample_filter->support;
18535b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif
1854490ab03a4e81aa0943087243055c77e3794d75d9anthony
18553ebea1e232532895681cd50101ddad0856e9a1d3anthony  /*
18563ebea1e232532895681cd50101ddad0856e9a1d3anthony    Adjust the scaling of the default unit circle
18573ebea1e232532895681cd50101ddad0856e9a1d3anthony    This assumes that any real scaling changes will always
18583ebea1e232532895681cd50101ddad0856e9a1d3anthony    take place AFTER the filter method has been initialized.
18593ebea1e232532895681cd50101ddad0856e9a1d3anthony  */
18603ebea1e232532895681cd50101ddad0856e9a1d3anthony  ScaleResampleFilter(resample_filter, 1.0, 0.0, 0.0, 1.0);
18613ebea1e232532895681cd50101ddad0856e9a1d3anthony
18625708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony#if 0
18635b697cdb1ed6e391b98953aafd362bddad51b453anthony  /* This is old code kept as a reference only.  It is very wrong,
18645b697cdb1ed6e391b98953aafd362bddad51b453anthony     and I don't understand exactly what it was attempting to do.
18655b697cdb1ed6e391b98953aafd362bddad51b453anthony  */
1866d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  /*
1867d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    Create Normal Gaussian 2D Filter Weighted Lookup Table.
1868d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    A normal EWA guassual lookup would use   exp(Q*ALPHA)
1869d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    where  Q = distance squared from 0.0 (center) to 1.0 (edge)
1870d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    and    ALPHA = -4.0*ln(2.0)  ==>  -2.77258872223978123767
18715b697cdb1ed6e391b98953aafd362bddad51b453anthony    The table is of length 1024, and equates to support radius of 2.0
1872d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    thus needs to be scaled by  ALPHA*4/1024 and any blur factor squared
1873d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony
1874c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    The above came from some reference code provided by Fred Weinhaus
1875c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    and seems to have been a guess that was appropriate for its use
1876c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony    in a 3d perspective landscape mapping program.
1877d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  */
1878d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  r_scale = -2.77258872223978123767/(WLUT_WIDTH*blur*blur);
1879d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  for(Q=0; Q<WLUT_WIDTH; Q++)
1880d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony    resample_filter->filter_lut[Q] = exp((double)Q*r_scale);
1881d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  resample_filter->support = WLUT_WIDTH;
1882d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony  break;
18835708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony#endif
1884490ab03a4e81aa0943087243055c77e3794d75d9anthony
18855b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT
1886e06e4c180324bebbd41bce9ea4898642f380b614anthony#if defined(MAGICKCORE_OPENMP_SUPPORT)
188772949796e01f8b94a0976e74cb8eb3f86af280eaanthony  #pragma omp single
1888e06e4c180324bebbd41bce9ea4898642f380b614anthony#endif
1889582b6d79fc381d6c9455f3f1b3e26923950161ebanthony  { register int
1890582b6d79fc381d6c9455f3f1b3e26923950161ebanthony       Q;
1891582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    double
1892582b6d79fc381d6c9455f3f1b3e26923950161ebanthony       r_scale;
189328ad1d779b6ca95852e860514185a7a97e06af77anthony
1894582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    /* Scale radius so the filter LUT covers the full support range */
1895582b6d79fc381d6c9455f3f1b3e26923950161ebanthony    r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH);
189628ad1d779b6ca95852e860514185a7a97e06af77anthony    if (IsMagickTrue(GetImageArtifact(resample_filter->image,"resample:verbose")) )
1897e06e4c180324bebbd41bce9ea4898642f380b614anthony      {
1898e06e4c180324bebbd41bce9ea4898642f380b614anthony        /* Debug output of the filter weighting LUT
1899e06e4c180324bebbd41bce9ea4898642f380b614anthony          Gnuplot the LUT with hoizontal adjusted to 'r' using...
1900e06e4c180324bebbd41bce9ea4898642f380b614anthony            plot [0:2][-.2:1] "lut.dat" using (sqrt($0/1024)*2):1 with lines
1901e06e4c180324bebbd41bce9ea4898642f380b614anthony          The filter values is normalized for comparision
1902e06e4c180324bebbd41bce9ea4898642f380b614anthony        */
1903d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony        printf("#\n");
1904e06e4c180324bebbd41bce9ea4898642f380b614anthony        printf("# Resampling Filter LUT (%d values)\n", WLUT_WIDTH);
1905e06e4c180324bebbd41bce9ea4898642f380b614anthony        printf("#\n");
1906d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony        printf("# Note: values in table are using a squared radius lookup.\n");
1907d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony        printf("# And the whole table represents the filters support.\n");
190861b5ddd7008c09f611076719e86f6f65ef5a9a4danthony        printf("\n"); /* generates a 'break' in gnuplot if multiple outputs */
1909e06e4c180324bebbd41bce9ea4898642f380b614anthony        for(Q=0; Q<WLUT_WIDTH; Q++)
1910d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony          printf("%8.*g %.*g\n",
1911d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony               GetMagickPrecision(),sqrt((double)Q)*r_scale,
1912d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony               GetMagickPrecision(),resample_filter->filter_lut[Q] );
1913e06e4c180324bebbd41bce9ea4898642f380b614anthony      }
191472949796e01f8b94a0976e74cb8eb3f86af280eaanthony    /* output the above once only for each image, and each setting */
191572949796e01f8b94a0976e74cb8eb3f86af280eaanthony    (void) DeleteImageArtifact(resample_filter->image,"resample:verbose");
191672949796e01f8b94a0976e74cb8eb3f86af280eaanthony  }
19175b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif /* FILTER_LUT */
19183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return;
19193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
19203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
19213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
19223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   S e t R e s a m p l e F i l t e r I n t e r p o l a t e M e t h o d       %
19273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
19303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19322ab242ec7c723f9f95558b30f1275011aa582ca9cristy%  SetResampleFilterInterpolateMethod() sets the resample filter interpolation
19332ab242ec7c723f9f95558b30f1275011aa582ca9cristy%  method.
19343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the SetResampleFilterInterpolateMethod method is:
19363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType SetResampleFilterInterpolateMethod(
19383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        ResampleFilter *resample_filter,const InterpolateMethod method)
19393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
19413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resample filter.
19433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o method: the interpolation method.
19453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
19463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
19473ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType SetResampleFilterInterpolateMethod(
19483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter,const InterpolatePixelMethod method)
19493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
19503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
19513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
19523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->image != (Image *) NULL);
19533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->debug != MagickFalse)
19543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
19553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->image->filename);
19563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->interpolate=method;
19572ab242ec7c723f9f95558b30f1275011aa582ca9cristy  return(MagickTrue);
19582ab242ec7c723f9f95558b30f1275011aa582ca9cristy}
19592ab242ec7c723f9f95558b30f1275011aa582ca9cristy
19602ab242ec7c723f9f95558b30f1275011aa582ca9cristy/*
19612ab242ec7c723f9f95558b30f1275011aa582ca9cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19622ab242ec7c723f9f95558b30f1275011aa582ca9cristy%                                                                             %
19632ab242ec7c723f9f95558b30f1275011aa582ca9cristy%                                                                             %
19642ab242ec7c723f9f95558b30f1275011aa582ca9cristy%                                                                             %
19652ab242ec7c723f9f95558b30f1275011aa582ca9cristy%   S e t R e s a m p l e F i l t e r M a t t e                               %
19662ab242ec7c723f9f95558b30f1275011aa582ca9cristy%                                                                             %
19672ab242ec7c723f9f95558b30f1275011aa582ca9cristy%                                                                             %
19682ab242ec7c723f9f95558b30f1275011aa582ca9cristy%                                                                             %
19692ab242ec7c723f9f95558b30f1275011aa582ca9cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19702ab242ec7c723f9f95558b30f1275011aa582ca9cristy%
19712ab242ec7c723f9f95558b30f1275011aa582ca9cristy%  SetResampleFilterColorspace() sets the resample filter matte.
19722ab242ec7c723f9f95558b30f1275011aa582ca9cristy%
19732ab242ec7c723f9f95558b30f1275011aa582ca9cristy%  The format of the SetResampleFilterColorspace method is:
19742ab242ec7c723f9f95558b30f1275011aa582ca9cristy%
19752ab242ec7c723f9f95558b30f1275011aa582ca9cristy%      MagickBooleanType SetResampleFilterColorspace(
19762ab242ec7c723f9f95558b30f1275011aa582ca9cristy%        ResampleFilter *resample_filter,const MagickBooleanType matte)
19772ab242ec7c723f9f95558b30f1275011aa582ca9cristy%
19782ab242ec7c723f9f95558b30f1275011aa582ca9cristy%  A description of each parameter follows:
19792ab242ec7c723f9f95558b30f1275011aa582ca9cristy%
19802ab242ec7c723f9f95558b30f1275011aa582ca9cristy%    o resample_filter: the resample filter.
19812ab242ec7c723f9f95558b30f1275011aa582ca9cristy%
19822ab242ec7c723f9f95558b30f1275011aa582ca9cristy%    o matte: the filter matte.
19832ab242ec7c723f9f95558b30f1275011aa582ca9cristy%
19842ab242ec7c723f9f95558b30f1275011aa582ca9cristy*/
19852ab242ec7c723f9f95558b30f1275011aa582ca9cristyMagickExport MagickBooleanType SetResampleFilterMatte(
19862ab242ec7c723f9f95558b30f1275011aa582ca9cristy  ResampleFilter *resample_filter,const MagickBooleanType matte)
19872ab242ec7c723f9f95558b30f1275011aa582ca9cristy{
19882ab242ec7c723f9f95558b30f1275011aa582ca9cristy  assert(resample_filter != (ResampleFilter *) NULL);
19892ab242ec7c723f9f95558b30f1275011aa582ca9cristy  assert(resample_filter->signature == MagickSignature);
19902ab242ec7c723f9f95558b30f1275011aa582ca9cristy  assert(resample_filter->image != (Image *) NULL);
19912ab242ec7c723f9f95558b30f1275011aa582ca9cristy  if (resample_filter->debug != MagickFalse)
19922ab242ec7c723f9f95558b30f1275011aa582ca9cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
19932ab242ec7c723f9f95558b30f1275011aa582ca9cristy      resample_filter->image->filename);
19942ab242ec7c723f9f95558b30f1275011aa582ca9cristy  resample_filter->matte=matte;
19953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
19963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
19973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
19983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
19993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
20003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   S e t R e s a m p l e F i l t e r V i r t u a l P i x e l M e t h o d     %
20043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
20083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  SetResampleFilterVirtualPixelMethod() changes the virtual pixel method
20103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  associated with the specified resample filter.
20113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the SetResampleFilterVirtualPixelMethod method is:
20133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType SetResampleFilterVirtualPixelMethod(
20153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        ResampleFilter *resample_filter,const VirtualPixelMethod method)
20163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
20183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o resample_filter: the resample filter.
20203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o method: the virtual pixel method.
20223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
20243ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType SetResampleFilterVirtualPixelMethod(
20253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ResampleFilter *resample_filter,const VirtualPixelMethod method)
20263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
20273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter != (ResampleFilter *) NULL);
20283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->signature == MagickSignature);
20293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(resample_filter->image != (Image *) NULL);
20303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (resample_filter->debug != MagickFalse)
20313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
20323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      resample_filter->image->filename);
20333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  resample_filter->virtual_pixel=method;
20342d5e44dc510676c5dd9c2a3abefcd5e2556b0fe4cristy  if (method != UndefinedVirtualPixelMethod)
20352d5e44dc510676c5dd9c2a3abefcd5e2556b0fe4cristy    (void) SetCacheViewVirtualPixelMethod(resample_filter->view,method);
20363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
20373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
2038