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 % 16de984cdc3631106b1cbbb8d3972b76a0fc27e8e8cristy% Cristy % 173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Anthony Thyssen % 183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% August 2007 % 193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 217ce65e7125a4e1df1a274ce373c537a9df9c16cdCristy% Copyright 1999-2016 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*/ 434c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/studio.h" 444c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/artifact.h" 454c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/color-private.h" 464c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/cache.h" 474c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/draw.h" 484c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception-private.h" 494c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/gem.h" 504c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image.h" 514c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image-private.h" 524c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/log.h" 534c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/magick.h" 544c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/memory_.h" 554c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel.h" 564c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel-accessor.h" 574c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantum.h" 584c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/random_.h" 594c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/resample.h" 604c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/resize.h" 614c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/resize-private.h" 62ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy#include "MagickCore/resource_.h" 6363a81879d3568083e4ee4f78ebcae2bc831cb764cristy#include "MagickCore/token.h" 644c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/transform.h" 654c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/signature-private.h" 664c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/utility.h" 67d1dd6e4fefa0810b9893e6ac9418f79c97c1b39acristy#include "MagickCore/utility-private.h" 689cb63ccb02272521283da6d251068d91196cc5bfanthony#include "MagickCore/option.h" 693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/* 70490ab03a4e81aa0943087243055c77e3794d75d9anthony EWA Resampling Options 71490ab03a4e81aa0943087243055c77e3794d75d9anthony*/ 72c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony 73c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony/* select ONE resampling method */ 74c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#define EWA 1 /* Normal EWA handling - raw or clamped */ 75c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony /* if 0 then use "High Quality EWA" */ 76c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#define EWA_CLAMP 1 /* EWA Clamping from Nicolas Robidoux */ 77c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony 785b697cdb1ed6e391b98953aafd362bddad51b453anthony#define FILTER_LUT 1 /* Use a LUT rather then direct filter calls */ 795b697cdb1ed6e391b98953aafd362bddad51b453anthony 80c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony/* output debugging information */ 81490ab03a4e81aa0943087243055c77e3794d75d9anthony#define DEBUG_ELLIPSE 0 /* output ellipse info for debug */ 822e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#define DEBUG_HIT_MISS 0 /* output hit/miss pixels (as gnuplot commands) */ 832e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#define DEBUG_NO_PIXEL_HIT 0 /* Make pixels that fail to hit anything - RED */ 84490ab03a4e81aa0943087243055c77e3794d75d9anthony 855b697cdb1ed6e391b98953aafd362bddad51b453anthony#if ! FILTER_DIRECT 865b697cdb1ed6e391b98953aafd362bddad51b453anthony#define WLUT_WIDTH 1024 /* size of the filter cache */ 875b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif 885b697cdb1ed6e391b98953aafd362bddad51b453anthony 89490ab03a4e81aa0943087243055c77e3794d75d9anthony/* 903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Typedef declarations. 913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/ 923ed852eea50f9d4cd633efb8c2b054b8e33c253cristystruct _ResampleFilter 933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy CacheView 953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *view; 963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 97c4c8d13c0996fea659ce63c682c803e74c1abc8acristy Image 98c4c8d13c0996fea659ce63c682c803e74c1abc8acristy *image; 99c4c8d13c0996fea659ce63c682c803e74c1abc8acristy 1003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ExceptionInfo 1013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *exception; 1023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy MagickBooleanType 1043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy debug; 1053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Information about image being resampled */ 107bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy ssize_t 1083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy image_area; 1093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1105c4e2586d27d4299a742d170d41105de1689aa46cristy PixelInterpolateMethod 1113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy interpolate; 1123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy VirtualPixelMethod 1143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy virtual_pixel; 1153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1168b9f21cab4c50eb7d6e558a7a43a68833fe0b55ddirk FilterType 1173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy filter; 1183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* processing settings needed */ 1203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy MagickBooleanType 1213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy limit_reached, 1223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy do_interpolate, 1233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy average_defined; 1243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1254c08aed51c5899665ade97263692328eea4af106cristy PixelInfo 1263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy average_pixel; 1273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* current ellipitical area being resampled around center point */ 1293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 1303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy A, B, C, 131d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony Vlimit, Ulimit, Uwidth, slope; 1323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 133175defe3237b2e7bab13c9649a837500af6a82c7anthony#if FILTER_LUT 1343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* LUT of weights for filtered average in elliptical area */ 1353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 1365b697cdb1ed6e391b98953aafd362bddad51b453anthony filter_lut[WLUT_WIDTH]; 1375b697cdb1ed6e391b98953aafd362bddad51b453anthony#else 1385b697cdb1ed6e391b98953aafd362bddad51b453anthony /* Use a Direct call to the filter functions */ 1395b697cdb1ed6e391b98953aafd362bddad51b453anthony ResizeFilter 1405b697cdb1ed6e391b98953aafd362bddad51b453anthony *filter_def; 141582b6d79fc381d6c9455f3f1b3e26923950161ebanthony 142582b6d79fc381d6c9455f3f1b3e26923950161ebanthony double 143582b6d79fc381d6c9455f3f1b3e26923950161ebanthony F; 1445b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif 1455b697cdb1ed6e391b98953aafd362bddad51b453anthony 1465b697cdb1ed6e391b98953aafd362bddad51b453anthony /* the practical working support of the filter */ 1475b697cdb1ed6e391b98953aafd362bddad51b453anthony double 1483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy support; 1493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 150bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 1513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy signature; 1523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}; 1533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/* 1553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 1573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 1583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 1593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% A c q u i r e R e s a m p l e I n f o % 1603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 1613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 1623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 1633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 1653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% AcquireResampleFilter() initializes the information resample needs do to a 1663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% scaled lookup of a color from an image, using area sampling. 1673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 1683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% The algorithm is based on a Elliptical Weighted Average, where the pixels 1693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% found in a large elliptical area is averaged together according to a 1703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% weighting (filter) function. For more details see "Fundamentals of Texture 1713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Mapping and Image Warping" a master's thesis by Paul.S.Heckbert, June 17, 1723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 1989. Available for free from, http://www.cs.cmu.edu/~ph/ 1733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 1743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% As EWA resampling (or any sort of resampling) can require a lot of 1753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% calculations to produce a distorted scaling of the source image for each 1763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% output pixel, the ResampleFilter structure generated holds that information 1773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% between individual image resampling. 1783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 1793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% This function will make the appropriate AcquireCacheView() calls 1803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% to view the image, calling functions do not need to open a cache view. 1813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 1823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Usage Example... 1833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% resample_filter=AcquireResampleFilter(image,exception); 1849cb63ccb02272521283da6d251068d91196cc5bfanthony% SetResampleFilter(resample_filter, GaussianFilter); 185bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy% for (y=0; y < (ssize_t) image->rows; y++) { 186bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy% for (x=0; x < (ssize_t) image->columns; x++) { 187c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% u= ....; v= ....; 1883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% ScaleResampleFilter(resample_filter, ... scaling vectors ...); 189c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% (void) ResamplePixelColor(resample_filter,u,v,&pixel); 1903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% ... assign resampled pixel value ... 1913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% } 1923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% } 1933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% DestroyResampleFilter(resample_filter); 1943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 1953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% The format of the AcquireResampleFilter method is: 1963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 1973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% ResampleFilter *AcquireResampleFilter(const Image *image, 1983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% ExceptionInfo *exception) 1993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 2003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% A description of each parameter follows: 2013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 2023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o image: the image. 2033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 2043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o exception: return any errors or warnings in this structure. 2053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 2063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/ 2073ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport ResampleFilter *AcquireResampleFilter(const Image *image, 2083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ExceptionInfo *exception) 2093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 2103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy register ResampleFilter 2113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *resample_filter; 2123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 2133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy assert(image != (Image *) NULL); 214e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(image->signature == MagickCoreSignature); 2153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (image->debug != MagickFalse) 2163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 2173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy assert(exception != (ExceptionInfo *) NULL); 218e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(exception->signature == MagickCoreSignature); 2195c1c858705bf277d750185e970740084cd3f8e68cristy resample_filter=(ResampleFilter *) AcquireMagickMemory(sizeof( 2205c1c858705bf277d750185e970740084cd3f8e68cristy *resample_filter)); 2213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (resample_filter == (ResampleFilter *) NULL) 2223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 2233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ResetMagickMemory(resample_filter,0,sizeof(*resample_filter)); 2242ab242ec7c723f9f95558b30f1275011aa582ca9cristy resample_filter->exception=exception; 2253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->image=ReferenceImage((Image *) image); 2265c1c858705bf277d750185e970740084cd3f8e68cristy resample_filter->view=AcquireVirtualCacheView(resample_filter->image, 2275c1c858705bf277d750185e970740084cd3f8e68cristy exception); 2283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->debug=IsEventLogging(); 2295b697cdb1ed6e391b98953aafd362bddad51b453anthony resample_filter->image_area=(ssize_t) (image->columns*image->rows); 2305c1c858705bf277d750185e970740084cd3f8e68cristy resample_filter->average_defined=MagickFalse; 231e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy resample_filter->signature=MagickCoreSignature; 2325c1c858705bf277d750185e970740084cd3f8e68cristy SetResampleFilter(resample_filter,image->filter); 233aa2c16cb5e695053aa78e40f66bc36fbef4b1ed1cristy (void) SetResampleFilterInterpolateMethod(resample_filter,image->interpolate); 23482fea938ea2a766e32daddb7f2f69d66958e9d45cristy (void) SetResampleFilterVirtualPixelMethod(resample_filter, 23572949796e01f8b94a0976e74cb8eb3f86af280eaanthony GetImageVirtualPixelMethod(image)); 2363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(resample_filter); 2373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 2383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 2393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/* 2403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 2423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 2433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 2443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% D e s t r o y R e s a m p l e I n f o % 2453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 2463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 2473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 2483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 2503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% DestroyResampleFilter() finalizes and cleans up the resampling 2513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% resample_filter as returned by AcquireResampleFilter(), freeing any memory 2523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% or other information as needed. 2533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 2543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% The format of the DestroyResampleFilter method is: 2553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 2563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% ResampleFilter *DestroyResampleFilter(ResampleFilter *resample_filter) 2573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 2583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% A description of each parameter follows: 2593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 2603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o resample_filter: resampling information structure 2613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 2623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/ 2633ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport ResampleFilter *DestroyResampleFilter( 2643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ResampleFilter *resample_filter) 2653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 2663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy assert(resample_filter != (ResampleFilter *) NULL); 267e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(resample_filter->signature == MagickCoreSignature); 2683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy assert(resample_filter->image != (Image *) NULL); 2693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (resample_filter->debug != MagickFalse) 2703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 2713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->image->filename); 2723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->view=DestroyCacheView(resample_filter->view); 2733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->image=DestroyImage(resample_filter->image); 2745b697cdb1ed6e391b98953aafd362bddad51b453anthony#if ! FILTER_LUT 2755b697cdb1ed6e391b98953aafd362bddad51b453anthony resample_filter->filter_def=DestroyResizeFilter(resample_filter->filter_def); 2765b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif 277e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy resample_filter->signature=(~MagickCoreSignature); 2783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter=(ResampleFilter *) RelinquishMagickMemory(resample_filter); 2793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(resample_filter); 2803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 2813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 2823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/* 2833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 2853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 2863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 2873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% R e s a m p l e P i x e l C o l o r % 2883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 2893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 2903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 2913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 2933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% ResamplePixelColor() samples the pixel values surrounding the location 2943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% given using an elliptical weighted average, at the scale previously 2953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% calculated, and in the most efficent manner possible for the 2963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% VirtualPixelMethod setting. 2973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 2983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% The format of the ResamplePixelColor method is: 2993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% MagickBooleanType ResamplePixelColor(ResampleFilter *resample_filter, 301db070957cf6bf959df9283a482377e8854c3d4d2cristy% const double u0,const double v0,PixelInfo *pixel, 302db070957cf6bf959df9283a482377e8854c3d4d2cristy% ExceptionInfo *exception) 3033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% A description of each parameter follows: 3053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o resample_filter: the resample filter. 3073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o u0,v0: A double representing the center of the area to resample, 3093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% The distortion transformed transformed x,y coordinate. 3103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o pixel: the resampled pixel is returned here. 3123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 313db070957cf6bf959df9283a482377e8854c3d4d2cristy% o exception: return any errors or warnings in this structure. 314db070957cf6bf959df9283a482377e8854c3d4d2cristy% 3153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/ 3163ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType ResamplePixelColor( 3173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ResampleFilter *resample_filter,const double u0,const double v0, 318db070957cf6bf959df9283a482377e8854c3d4d2cristy PixelInfo *pixel,ExceptionInfo *exception) 3193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 3203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy MagickBooleanType 3213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status; 3223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 323490ab03a4e81aa0943087243055c77e3794d75d9anthony ssize_t u,v, v1, v2, uw, hit; 3243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double u1; 3253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double U,V,Q,DQ,DDQ; 3263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double divisor_c,divisor_m; 3273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy register double weight; 3284c08aed51c5899665ade97263692328eea4af106cristy register const Quantum *pixels; 3293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy assert(resample_filter != (ResampleFilter *) NULL); 330e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(resample_filter->signature == MagickCoreSignature); 3313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 3323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status=MagickTrue; 3334c08aed51c5899665ade97263692328eea4af106cristy /* GetPixelInfo(resample_filter->image,pixel); */ 3343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( resample_filter->do_interpolate ) { 335f931f0708bbd917a0b880912396f5128994f9137cristy status=InterpolatePixelInfo(resample_filter->image,resample_filter->view, 336f931f0708bbd917a0b880912396f5128994f9137cristy resample_filter->interpolate,u0,v0,pixel,resample_filter->exception); 3373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(status); 3383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 3393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 3402e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#if DEBUG_ELLIPSE 3415acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "u0=%lf; v0=%lf;\n", u0, v0); 3422e6ab68e6538e73abd8d77f505bc9f033c742f1canthony#endif 3432e6ab68e6538e73abd8d77f505bc9f033c742f1canthony 3443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 345c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony Does resample area Miss the image Proper? 346c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony If and that area a simple solid color - then simply return that color! 347c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony This saves a lot of calculation when resampling outside the bounds of 348c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony the source image. 349c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony 350c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony However it probably should be expanded to image bounds plus the filters 351c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony scaled support size. 3523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 3533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy hit = 0; 3543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy switch ( resample_filter->virtual_pixel ) { 3553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BackgroundVirtualPixelMethod: 3563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case TransparentVirtualPixelMethod: 3573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BlackVirtualPixelMethod: 3583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case GrayVirtualPixelMethod: 3593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case WhiteVirtualPixelMethod: 3603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case MaskVirtualPixelMethod: 3613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( resample_filter->limit_reached 362d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony || u0 + resample_filter->Ulimit < 0.0 363c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony || u0 - resample_filter->Ulimit > (double) resample_filter->image->columns-1.0 364d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony || v0 + resample_filter->Vlimit < 0.0 365c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony || v0 - resample_filter->Vlimit > (double) resample_filter->image->rows-1.0 3663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ) 3673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy hit++; 3683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 3693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 3703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case UndefinedVirtualPixelMethod: 3713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case EdgeVirtualPixelMethod: 372d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony if ( ( u0 + resample_filter->Ulimit < 0.0 && v0 + resample_filter->Vlimit < 0.0 ) 373d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony || ( u0 + resample_filter->Ulimit < 0.0 374c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows-1.0 ) 375c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns-1.0 376d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony && v0 + resample_filter->Vlimit < 0.0 ) 377c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns-1.0 378c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows-1.0 ) 3793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ) 3803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy hit++; 3813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 3823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case HorizontalTileVirtualPixelMethod: 383d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony if ( v0 + resample_filter->Vlimit < 0.0 384c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony || v0 - resample_filter->Vlimit > (double) resample_filter->image->rows-1.0 3853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ) 3863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy hit++; /* outside the horizontally tiled images. */ 3873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 3883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case VerticalTileVirtualPixelMethod: 389d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony if ( u0 + resample_filter->Ulimit < 0.0 390c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony || u0 - resample_filter->Ulimit > (double) resample_filter->image->columns-1.0 3913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ) 3923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy hit++; /* outside the vertically tiled images. */ 3933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 3943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case DitherVirtualPixelMethod: 395d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony if ( ( u0 + resample_filter->Ulimit < -32.0 && v0 + resample_filter->Vlimit < -32.0 ) 396d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony || ( u0 + resample_filter->Ulimit < -32.0 397c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows+31.0 ) 398c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns+31.0 399d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony && v0 + resample_filter->Vlimit < -32.0 ) 400c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns+31.0 401c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows+31.0 ) 4023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ) 4033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy hit++; 4043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case TileVirtualPixelMethod: 4063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case MirrorVirtualPixelMethod: 4073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case RandomVirtualPixelMethod: 4083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case HorizontalTileEdgeVirtualPixelMethod: 4093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case VerticalTileEdgeVirtualPixelMethod: 4103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case CheckerTileVirtualPixelMethod: 4113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* resampling of area is always needed - no VP limits */ 4123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 4143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( hit ) { 415c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony /* The area being resampled is simply a solid color 416c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony * just return a single lookup color. 417c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony * 418c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony * Should this return the users requested interpolated color? 419c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony */ 4205c1c858705bf277d750185e970740084cd3f8e68cristy status=InterpolatePixelInfo(resample_filter->image,resample_filter->view, 4215c1c858705bf277d750185e970740084cd3f8e68cristy IntegerInterpolatePixel,u0,v0,pixel,resample_filter->exception); 4223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(status); 4233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 4243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 4253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 426c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony When Scaling limits reached, return an 'averaged' result. 4273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 4283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( resample_filter->limit_reached ) { 4293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy switch ( resample_filter->virtual_pixel ) { 4303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* This is always handled by the above, so no need. 4313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BackgroundVirtualPixelMethod: 4323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case ConstantVirtualPixelMethod: 4333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case TransparentVirtualPixelMethod: 4343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case GrayVirtualPixelMethod, 4353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case WhiteVirtualPixelMethod 4363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case MaskVirtualPixelMethod: 4373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 4383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case UndefinedVirtualPixelMethod: 4393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case EdgeVirtualPixelMethod: 4403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case DitherVirtualPixelMethod: 4413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case HorizontalTileEdgeVirtualPixelMethod: 4423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case VerticalTileEdgeVirtualPixelMethod: 4439b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony /* We need an average edge pixel, from the correct edge! 4443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy How should I calculate an average edge color? 4453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Just returning an averaged neighbourhood, 4463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy works well in general, but falls down for TileEdge methods. 4473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy This needs to be done properly!!!!!! 4483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 4494c08aed51c5899665ade97263692328eea4af106cristy status=InterpolatePixelInfo(resample_filter->image, 450d76c51ed30cf4084f4434ba08925d16001d1e340cristy resample_filter->view,AverageInterpolatePixel,u0,v0,pixel, 451d76c51ed30cf4084f4434ba08925d16001d1e340cristy resample_filter->exception); 4523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case HorizontalTileVirtualPixelMethod: 4543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case VerticalTileVirtualPixelMethod: 4553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* just return the background pixel - Is there more direct way? */ 4564c08aed51c5899665ade97263692328eea4af106cristy status=InterpolatePixelInfo(resample_filter->image, 457d76c51ed30cf4084f4434ba08925d16001d1e340cristy resample_filter->view,IntegerInterpolatePixel,-1.0,-1.0,pixel, 458d76c51ed30cf4084f4434ba08925d16001d1e340cristy resample_filter->exception); 4593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case TileVirtualPixelMethod: 4613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case MirrorVirtualPixelMethod: 4623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case RandomVirtualPixelMethod: 4633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case CheckerTileVirtualPixelMethod: 4643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy default: 4653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* generate a average color of the WHOLE image */ 4663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( resample_filter->average_defined == MagickFalse ) { 4673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Image 4683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *average_image; 4693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 4703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy CacheView 4713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *average_view; 4723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 4734c08aed51c5899665ade97263692328eea4af106cristy GetPixelInfo(resample_filter->image,(PixelInfo *) 474065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy &resample_filter->average_pixel); 475065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy resample_filter->average_defined=MagickTrue; 4763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 4773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Try to get an averaged pixel color of whole image */ 478aa2c16cb5e695053aa78e40f66bc36fbef4b1ed1cristy average_image=ResizeImage(resample_filter->image,1,1,BoxFilter, 479065f8beaaf329a79ab95e99b4104d0d1c0f81e8dcristy resample_filter->exception); 4803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (average_image == (Image *) NULL) 4813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 4823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *pixel=resample_filter->average_pixel; /* FAILED */ 4833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 48546ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy average_view=AcquireVirtualCacheView(average_image,exception); 4864c08aed51c5899665ade97263692328eea4af106cristy pixels=GetCacheViewVirtualPixels(average_view,0,0,1,1, 4873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->exception); 4884c08aed51c5899665ade97263692328eea4af106cristy if (pixels == (const Quantum *) NULL) { 4893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy average_view=DestroyCacheView(average_view); 4903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy average_image=DestroyImage(average_image); 4913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *pixel=resample_filter->average_pixel; /* FAILED */ 4923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 494803640d20a6a664315eddfff6f8531d0c5e0871dcristy GetPixelInfoPixel(resample_filter->image,pixels, 4953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy &(resample_filter->average_pixel)); 4963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy average_view=DestroyCacheView(average_view); 4973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy average_image=DestroyImage(average_image); 498490ab03a4e81aa0943087243055c77e3794d75d9anthony 499490ab03a4e81aa0943087243055c77e3794d75d9anthony if ( resample_filter->virtual_pixel == CheckerTileVirtualPixelMethod ) 500490ab03a4e81aa0943087243055c77e3794d75d9anthony { 5019cb63ccb02272521283da6d251068d91196cc5bfanthony /* CheckerTile is a alpha blend of the image's average pixel 5029cb63ccb02272521283da6d251068d91196cc5bfanthony color and the current background color */ 503490ab03a4e81aa0943087243055c77e3794d75d9anthony 5049cb63ccb02272521283da6d251068d91196cc5bfanthony /* image's average pixel color */ 505a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy weight = QuantumScale*((double) 5064c08aed51c5899665ade97263692328eea4af106cristy resample_filter->average_pixel.alpha); 507490ab03a4e81aa0943087243055c77e3794d75d9anthony resample_filter->average_pixel.red *= weight; 508490ab03a4e81aa0943087243055c77e3794d75d9anthony resample_filter->average_pixel.green *= weight; 509490ab03a4e81aa0943087243055c77e3794d75d9anthony resample_filter->average_pixel.blue *= weight; 510490ab03a4e81aa0943087243055c77e3794d75d9anthony divisor_c = weight; 511490ab03a4e81aa0943087243055c77e3794d75d9anthony 5129cb63ccb02272521283da6d251068d91196cc5bfanthony /* background color */ 513a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy weight = QuantumScale*((double) 5144c08aed51c5899665ade97263692328eea4af106cristy resample_filter->image->background_color.alpha); 515490ab03a4e81aa0943087243055c77e3794d75d9anthony resample_filter->average_pixel.red += 516490ab03a4e81aa0943087243055c77e3794d75d9anthony weight*resample_filter->image->background_color.red; 517490ab03a4e81aa0943087243055c77e3794d75d9anthony resample_filter->average_pixel.green += 518490ab03a4e81aa0943087243055c77e3794d75d9anthony weight*resample_filter->image->background_color.green; 519490ab03a4e81aa0943087243055c77e3794d75d9anthony resample_filter->average_pixel.blue += 520490ab03a4e81aa0943087243055c77e3794d75d9anthony weight*resample_filter->image->background_color.blue; 5214c08aed51c5899665ade97263692328eea4af106cristy resample_filter->average_pixel.alpha += 5224c08aed51c5899665ade97263692328eea4af106cristy resample_filter->image->background_color.alpha; 523490ab03a4e81aa0943087243055c77e3794d75d9anthony divisor_c += weight; 524490ab03a4e81aa0943087243055c77e3794d75d9anthony 5259cb63ccb02272521283da6d251068d91196cc5bfanthony /* alpha blend */ 526490ab03a4e81aa0943087243055c77e3794d75d9anthony resample_filter->average_pixel.red /= divisor_c; 527490ab03a4e81aa0943087243055c77e3794d75d9anthony resample_filter->average_pixel.green /= divisor_c; 528490ab03a4e81aa0943087243055c77e3794d75d9anthony resample_filter->average_pixel.blue /= divisor_c; 5299cb63ccb02272521283da6d251068d91196cc5bfanthony resample_filter->average_pixel.alpha /= 2; /* 50% blend */ 530490ab03a4e81aa0943087243055c77e3794d75d9anthony 531490ab03a4e81aa0943087243055c77e3794d75d9anthony } 5323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 5333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *pixel=resample_filter->average_pixel; 5343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 5353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 5363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(status); 5373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 5383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 5393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 5403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Initialize weighted average data collection 5413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 5423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy hit = 0; 5433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy divisor_c = 0.0; 5443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy divisor_m = 0.0; 5453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy pixel->red = pixel->green = pixel->blue = 0.0; 5464c08aed51c5899665ade97263692328eea4af106cristy if (pixel->colorspace == CMYKColorspace) 5474c08aed51c5899665ade97263692328eea4af106cristy pixel->black = 0.0; 54817f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (pixel->alpha_trait != UndefinedPixelTrait) 5494c08aed51c5899665ade97263692328eea4af106cristy pixel->alpha = 0.0; 5503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 5513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 5523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Determine the parellelogram bounding box fitted to the ellipse 5533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy centered at u0,v0. This area is bounding by the lines... 5543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 555490ab03a4e81aa0943087243055c77e3794d75d9anthony v1 = (ssize_t)ceil(v0 - resample_filter->Vlimit); /* range of scan lines */ 556490ab03a4e81aa0943087243055c77e3794d75d9anthony v2 = (ssize_t)floor(v0 + resample_filter->Vlimit); 557490ab03a4e81aa0943087243055c77e3794d75d9anthony 558490ab03a4e81aa0943087243055c77e3794d75d9anthony /* scan line start and width accross the parallelogram */ 559490ab03a4e81aa0943087243055c77e3794d75d9anthony u1 = u0 + (v1-v0)*resample_filter->slope - resample_filter->Uwidth; 560490ab03a4e81aa0943087243055c77e3794d75d9anthony uw = (ssize_t)(2.0*resample_filter->Uwidth)+1; 5613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 562490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE 5635acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "v1=%ld; v2=%ld\n", (long)v1, (long)v2); 5645acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "u1=%ld; uw=%ld\n", (long)u1, (long)uw); 565490ab03a4e81aa0943087243055c77e3794d75d9anthony#else 566490ab03a4e81aa0943087243055c77e3794d75d9anthony# define DEBUG_HIT_MISS 0 /* only valid if DEBUG_ELLIPSE is enabled */ 567490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif 5683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 5693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 5703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Do weighted resampling of all pixels, within the scaled ellipse, 5713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy bound by a Parellelogram fitted to the ellipse. 5723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 5733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy DDQ = 2*resample_filter->A; 574490ab03a4e81aa0943087243055c77e3794d75d9anthony for( v=v1; v<=v2; v++ ) { 575490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_HIT_MISS 576490ab03a4e81aa0943087243055c77e3794d75d9anthony long uu = ceil(u1); /* actual pixel location (for debug only) */ 5775acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "# scan line from pixel %ld, %ld\n", (long)uu, (long)v); 578490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif 579490ab03a4e81aa0943087243055c77e3794d75d9anthony u = (ssize_t)ceil(u1); /* first pixel in scanline */ 580490ab03a4e81aa0943087243055c77e3794d75d9anthony u1 += resample_filter->slope; /* start of next scan line */ 581490ab03a4e81aa0943087243055c77e3794d75d9anthony 582490ab03a4e81aa0943087243055c77e3794d75d9anthony 583490ab03a4e81aa0943087243055c77e3794d75d9anthony /* location of this first pixel, relative to u0,v0 */ 584490ab03a4e81aa0943087243055c77e3794d75d9anthony U = (double)u-u0; 5853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy V = (double)v-v0; 5863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 5873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Q = ellipse quotent ( if Q<F then pixel is inside ellipse) */ 588490ab03a4e81aa0943087243055c77e3794d75d9anthony Q = (resample_filter->A*U + resample_filter->B*V)*U + resample_filter->C*V*V; 5893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy DQ = resample_filter->A*(2.0*U+1) + resample_filter->B*V; 5903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 5913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* get the scanline of pixels for this v */ 592bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy pixels=GetCacheViewVirtualPixels(resample_filter->view,u,v,(size_t) uw, 5933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1,resample_filter->exception); 5944c08aed51c5899665ade97263692328eea4af106cristy if (pixels == (const Quantum *) NULL) 5953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(MagickFalse); 5963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 5973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* count up the weighted pixel colors */ 5983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for( u=0; u<uw; u++ ) { 5995b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT 6003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Note that the ellipse has been pre-scaled so F = WLUT_WIDTH */ 6013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( Q < (double)WLUT_WIDTH ) { 6023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy weight = resample_filter->filter_lut[(int)Q]; 6035b697cdb1ed6e391b98953aafd362bddad51b453anthony#else 6045b697cdb1ed6e391b98953aafd362bddad51b453anthony /* Note that the ellipse has been pre-scaled so F = support^2 */ 605582b6d79fc381d6c9455f3f1b3e26923950161ebanthony if ( Q < (double)resample_filter->F ) { 606582b6d79fc381d6c9455f3f1b3e26923950161ebanthony weight = GetResizeFilterWeight(resample_filter->filter_def, 607582b6d79fc381d6c9455f3f1b3e26923950161ebanthony sqrt(Q)); /* a SquareRoot! Arrggghhhhh... */ 6085b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif 6093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 6104c08aed51c5899665ade97263692328eea4af106cristy pixel->alpha += weight*GetPixelAlpha(resample_filter->image,pixels); 6113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy divisor_m += weight; 6123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 61317f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (pixel->alpha_trait != UndefinedPixelTrait) 614a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy weight *= QuantumScale*((double) GetPixelAlpha(resample_filter->image,pixels)); 6154c08aed51c5899665ade97263692328eea4af106cristy pixel->red += weight*GetPixelRed(resample_filter->image,pixels); 6164c08aed51c5899665ade97263692328eea4af106cristy pixel->green += weight*GetPixelGreen(resample_filter->image,pixels); 6174c08aed51c5899665ade97263692328eea4af106cristy pixel->blue += weight*GetPixelBlue(resample_filter->image,pixels); 6182ab242ec7c723f9f95558b30f1275011aa582ca9cristy if (pixel->colorspace == CMYKColorspace) 6194c08aed51c5899665ade97263692328eea4af106cristy pixel->black += weight*GetPixelBlack(resample_filter->image,pixels); 6203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy divisor_c += weight; 6213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 6223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy hit++; 623490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_HIT_MISS 624490ab03a4e81aa0943087243055c77e3794d75d9anthony /* mark the pixel according to hit/miss of the ellipse */ 6255acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 3\n", 626490ab03a4e81aa0943087243055c77e3794d75d9anthony (long)uu-.1,(double)v-.1,(long)uu+.1,(long)v+.1); 6275acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 3\n", 628490ab03a4e81aa0943087243055c77e3794d75d9anthony (long)uu+.1,(double)v-.1,(long)uu-.1,(long)v+.1); 629490ab03a4e81aa0943087243055c77e3794d75d9anthony } else { 6305acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 1\n", 631490ab03a4e81aa0943087243055c77e3794d75d9anthony (long)uu-.1,(double)v-.1,(long)uu+.1,(long)v+.1); 6325acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 1\n", 633490ab03a4e81aa0943087243055c77e3794d75d9anthony (long)uu+.1,(double)v-.1,(long)uu-.1,(long)v+.1); 634490ab03a4e81aa0943087243055c77e3794d75d9anthony } 635490ab03a4e81aa0943087243055c77e3794d75d9anthony uu++; 636490ab03a4e81aa0943087243055c77e3794d75d9anthony#else 6373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 638490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif 639ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy pixels+=GetPixelChannels(resample_filter->image); 6403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Q += DQ; 6413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy DQ += DDQ; 6423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 6433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 644490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE 6455acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Hit=%ld; Total=%ld;\n", (long)hit, (long)uw*(v2-v1) ); 646490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif 6473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 6483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 6493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Result sanity check -- this should NOT happen 6503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 6517d2553e6f4849f937e3b32fcac096a23932a6f64anthony if ( hit == 0 || divisor_m <= MagickEpsilon || divisor_c <= MagickEpsilon ) { 6527d2553e6f4849f937e3b32fcac096a23932a6f64anthony /* not enough pixels, or bad weighting in resampling, 6537d2553e6f4849f937e3b32fcac096a23932a6f64anthony resort to direct interpolation */ 654490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_NO_PIXEL_HIT 6554c08aed51c5899665ade97263692328eea4af106cristy pixel->alpha = pixel->red = pixel->green = pixel->blue = 0; 6569b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony pixel->red = QuantumRange; /* show pixels for which EWA fails */ 6579b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony#else 6584c08aed51c5899665ade97263692328eea4af106cristy status=InterpolatePixelInfo(resample_filter->image, 659d76c51ed30cf4084f4434ba08925d16001d1e340cristy resample_filter->view,resample_filter->interpolate,u0,v0,pixel, 660d76c51ed30cf4084f4434ba08925d16001d1e340cristy resample_filter->exception); 6619b8a528e6cd0d30f4cde233b09ae22b9d108a441anthony#endif 6623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return status; 6633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 6643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 6653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 6663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Finialize results of resampling 6673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 6683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy divisor_m = 1.0/divisor_m; 66926323143e202e9d0c23a394934bc48067a5ddf41cristy if (pixel->alpha_trait != UndefinedPixelTrait) 67026323143e202e9d0c23a394934bc48067a5ddf41cristy pixel->alpha = (double) ClampToQuantum(divisor_m*pixel->alpha); 6713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy divisor_c = 1.0/divisor_c; 672a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy pixel->red = (double) ClampToQuantum(divisor_c*pixel->red); 673a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy pixel->green = (double) ClampToQuantum(divisor_c*pixel->green); 674a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy pixel->blue = (double) ClampToQuantum(divisor_c*pixel->blue); 6752ab242ec7c723f9f95558b30f1275011aa582ca9cristy if (pixel->colorspace == CMYKColorspace) 676a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy pixel->black = (double) ClampToQuantum(divisor_c*pixel->black); 6773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(MagickTrue); 6783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 6793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 680c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA && EWA_CLAMP 681c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony/* 682c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 683c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% % 684c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% % 685c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% % 686c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony- C l a m p U p A x e s % 687c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% % 688c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% % 689c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% % 690c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 691c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% 692c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% ClampUpAxes() function converts the input vectors into a major and 69340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% minor axis unit vectors, and their magnitude. This allows us to 69440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% ensure that the ellipse generated is never smaller than the unit 695c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% circle and thus never too small for use in EWA resampling. 696c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% 697c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% This purely mathematical 'magic' was provided by Professor Nicolas 698c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% Robidoux and his Masters student Chantal Racette. 699c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% 70040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% Reference: "We Recommend Singular Value Decomposition", David Austin 701c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% http://www.ams.org/samplings/feature-column/fcarc-svd 702c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% 70340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% By generating major and minor axis vectors, we can actually use the 704c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% ellipse in its "canonical form", by remapping the dx,dy of the 705c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% sampled point into distances along the major and minor axis unit 706c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas% vectors. 70740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% 70840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas% Reference: http://en.wikipedia.org/wiki/Ellipse#Canonical_form 709c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony*/ 710c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthonystatic inline void ClampUpAxes(const double dux, 711c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony const double dvx, 712c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony const double duy, 713c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony const double dvy, 714c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony double *major_mag, 715c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony double *minor_mag, 716c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony double *major_unit_x, 717c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony double *major_unit_y, 718c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony double *minor_unit_x, 719c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony double *minor_unit_y) 720c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony{ 721c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony /* 722c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * ClampUpAxes takes an input 2x2 matrix 723c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 724c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * [ a b ] = [ dux duy ] 725c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * [ c d ] = [ dvx dvy ] 726c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 727c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * and computes from it the major and minor axis vectors [major_x, 728c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * major_y] and [minor_x,minor_y] of the smallest ellipse containing 729c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * both the unit disk and the ellipse which is the image of the unit 730c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * disk by the linear transformation 731c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 732c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * [ dux duy ] [S] = [s] 733c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * [ dvx dvy ] [T] = [t] 734c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 735c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * (The vector [S,T] is the difference between a position in output 736c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * space and [X,Y]; the vector [s,t] is the difference between a 737c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * position in input space and [x,y].) 738c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony */ 739c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony /* 740082f7e49118ae53d297a46feb7ed147f159263b0nicolas * Output: 741c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 742c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * major_mag is the half-length of the major axis of the "new" 74340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * ellipse. 744c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 745c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * minor_mag is the half-length of the minor axis of the "new" 74640ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * ellipse. 747c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 748c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * major_unit_x is the x-coordinate of the major axis direction vector 749c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * of both the "old" and "new" ellipses. 750c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 751c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * major_unit_y is the y-coordinate of the major axis direction vector. 752c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 753c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * minor_unit_x is the x-coordinate of the minor axis direction vector. 754c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 755c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * minor_unit_y is the y-coordinate of the minor axis direction vector. 756c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 757c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * Unit vectors are useful for computing projections, in particular, 758c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * to compute the distance between a point in output space and the 759082f7e49118ae53d297a46feb7ed147f159263b0nicolas * center of a unit disk in output space, using the position of the 760082f7e49118ae53d297a46feb7ed147f159263b0nicolas * corresponding point [s,t] in input space. Following the clamping, 761082f7e49118ae53d297a46feb7ed147f159263b0nicolas * the square of this distance is 762082f7e49118ae53d297a46feb7ed147f159263b0nicolas * 763082f7e49118ae53d297a46feb7ed147f159263b0nicolas * ( ( s * major_unit_x + t * major_unit_y ) / major_mag )^2 764082f7e49118ae53d297a46feb7ed147f159263b0nicolas * + 765082f7e49118ae53d297a46feb7ed147f159263b0nicolas * ( ( s * minor_unit_x + t * minor_unit_y ) / minor_mag )^2 766082f7e49118ae53d297a46feb7ed147f159263b0nicolas * 767082f7e49118ae53d297a46feb7ed147f159263b0nicolas * If such distances will be computed for many [s,t]'s, it makes 768082f7e49118ae53d297a46feb7ed147f159263b0nicolas * sense to actually compute the reciprocal of major_mag and 769082f7e49118ae53d297a46feb7ed147f159263b0nicolas * minor_mag and multiply them by the above unit lengths. 770c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * 771c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * Now, if you want to modify the input pair of tangent vectors so 772c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * that it defines the modified ellipse, all you have to do is set 773c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * 7748b1d981efa1bdef504b79420d43936c49eeecd3dnicolas * newdux = major_mag * major_unit_x 7758b1d981efa1bdef504b79420d43936c49eeecd3dnicolas * newdvx = major_mag * major_unit_y 7768b1d981efa1bdef504b79420d43936c49eeecd3dnicolas * newduy = minor_mag * minor_unit_x = minor_mag * -major_unit_y 7778b1d981efa1bdef504b79420d43936c49eeecd3dnicolas * newdvy = minor_mag * minor_unit_y = minor_mag * major_unit_x 778c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * 779932ef8479742364640c1aed64b795c528afab45cnicolas * and use these tangent vectors as if they were the original ones. 78040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * Usually, this is a drastic change in the tangent vectors even if 781c263aa7cbf22c73eb4fac5a90e333dfe6cc8c24bnicolas * the singular values are not clamped; for example, the minor axis 782c263aa7cbf22c73eb4fac5a90e333dfe6cc8c24bnicolas * vector always points in a direction which is 90 degrees 783c263aa7cbf22c73eb4fac5a90e333dfe6cc8c24bnicolas * counterclockwise from the direction of the major axis vector. 784c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony */ 785c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony /* 786c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * Discussion: 787c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 788c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * GOAL: Fix things so that the pullback, in input space, of a disk 789c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * of radius r in output space is an ellipse which contains, at 790c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * least, a disc of radius r. (Make this hold for any r>0.) 791c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 79240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * ESSENCE OF THE METHOD: Compute the product of the first two 79340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * factors of an SVD of the linear transformation defining the 794f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas * ellipse and make sure that both its columns have norm at least 1. 795f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas * Because rotations and reflexions map disks to themselves, it is 79640ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * not necessary to compute the third (rightmost) factor of the SVD. 797f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas * 798f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas * DETAILS: Find the singular values and (unit) left singular 799f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas * vectors of Jinv, clampling up the singular values to 1, and 800932ef8479742364640c1aed64b795c528afab45cnicolas * multiply the unit left singular vectors by the new singular 801f170e5f8b1f9642c4e3499392d4acf4e684f08a6nicolas * values in order to get the minor and major ellipse axis vectors. 802c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 80340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * Image resampling context: 804c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 805c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * The Jacobian matrix of the transformation at the output point 806c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * under consideration is defined as follows: 807c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 808c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * Consider the transformation (x,y) -> (X,Y) from input locations 8098b1d981efa1bdef504b79420d43936c49eeecd3dnicolas * to output locations. (Anthony Thyssen, elsewhere in resample.c, 81040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * uses the notation (u,v) -> (x,y).) 811c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 81240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * The Jacobian matrix of the transformation at (x,y) is equal to 813c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 81440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * J = [ A, B ] = [ dX/dx, dX/dy ] 81540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * [ C, D ] [ dY/dx, dY/dy ] 816c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 81740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * that is, the vector [A,C] is the tangent vector corresponding to 81840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * input changes in the horizontal direction, and the vector [B,D] 81940ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * is the tangent vector corresponding to input changes in the 82040ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * vertical direction. 821c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 82240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * In the context of resampling, it is natural to use the inverse 82340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * Jacobian matrix Jinv because resampling is generally performed by 82440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * pulling pixel locations in the output image back to locations in 82540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * the input image. Jinv is 826c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 827d0026353a2b71306fc279a94596a7935982d9064nicolas * Jinv = [ a, b ] = [ dx/dX, dx/dY ] 82840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * [ c, d ] [ dy/dX, dy/dY ] 829c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 830c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * Note: Jinv can be computed from J with the following matrix 831c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * formula: 832c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * 833c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * Jinv = 1/(A*D-B*C) [ D, -B ] 834c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * [ -C, A ] 835c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * 83640ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * What we do is modify Jinv so that it generates an ellipse which 83740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * is as close as possible to the original but which contains the 83840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * unit disk. This can be accomplished as follows: 839c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * 840c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * Let 841c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * 842c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * Jinv = U Sigma V^T 843c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * 844932ef8479742364640c1aed64b795c528afab45cnicolas * be an SVD decomposition of Jinv. (The SVD is not unique, but the 84540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * final ellipse does not depend on the particular SVD.) 846cb18092ccb044a899ad125e794ff30067fb42416cristy * 84740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * We could clamp up the entries of the diagonal matrix Sigma so 84840ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * that they are at least 1, and then set 849c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * 850c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * Jinv = U newSigma V^T. 851c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * 85240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * However, we do not need to compute V for the following reason: 85340ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * V^T is an orthogonal matrix (that is, it represents a combination 85440ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * of rotations and reflexions) so that it maps the unit circle to 85540ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * itself. For this reason, the exact value of V does not affect the 85640ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * final ellipse, and we can choose V to be the identity 85740ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * matrix. This gives 858c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * 85940ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * Jinv = U newSigma. 860c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * 86140ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * In the end, we return the two diagonal entries of newSigma 86240ae4631631d59f41ab3ea0a63e75f877c51ec2anicolas * together with the two columns of U. 863c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony */ 864c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony /* 865c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * ClampUpAxes was written by Nicolas Robidoux and Chantal Racette 86647b95659ad624c0c2e8011394239a29e9f1daa8cnicolas * of Laurentian University with insightful suggestions from Anthony 86747b95659ad624c0c2e8011394239a29e9f1daa8cnicolas * Thyssen and funding from the National Science and Engineering 86847b95659ad624c0c2e8011394239a29e9f1daa8cnicolas * Research Council of Canada. It is distinguished from its 86947b95659ad624c0c2e8011394239a29e9f1daa8cnicolas * predecessors by its efficient handling of degenerate cases. 870703291ad3e90f51f084faa12c83bd2cf0f12ae72nicolas * 8718c741cc65e33be2570284c0217701c72c719aecbnicolas * The idea of clamping up the EWA ellipse's major and minor axes so 8728c741cc65e33be2570284c0217701c72c719aecbnicolas * that the result contains the reconstruction kernel filter support 87347b95659ad624c0c2e8011394239a29e9f1daa8cnicolas * is taken from Andreas Gustaffson's Masters thesis "Interactive 87447b95659ad624c0c2e8011394239a29e9f1daa8cnicolas * Image Warping", Helsinki University of Technology, Faculty of 87547b95659ad624c0c2e8011394239a29e9f1daa8cnicolas * Information Technology, 59 pages, 1993 (see Section 3.6). 8768c741cc65e33be2570284c0217701c72c719aecbnicolas * 87747b95659ad624c0c2e8011394239a29e9f1daa8cnicolas * The use of the SVD to clamp up the singular values of the 87847b95659ad624c0c2e8011394239a29e9f1daa8cnicolas * Jacobian matrix of the pullback transformation for EWA resampling 87947b95659ad624c0c2e8011394239a29e9f1daa8cnicolas * is taken from the astrophysicist Craig DeForest. It is 88047b95659ad624c0c2e8011394239a29e9f1daa8cnicolas * implemented in his PDL::Transform code (PDL = Perl Data 88147b95659ad624c0c2e8011394239a29e9f1daa8cnicolas * Language). 882c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony */ 883c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double a = dux; 884c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double b = duy; 885c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double c = dvx; 886c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double d = dvy; 887c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony /* 888c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * n is the matrix Jinv * transpose(Jinv). Eigenvalues of n are the 889c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * squares of the singular values of Jinv. 890c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony */ 891c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double aa = a*a; 892c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double bb = b*b; 893c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double cc = c*c; 894c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double dd = d*d; 895c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony /* 896c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * Eigenvectors of n are left singular vectors of Jinv. 897c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony */ 898c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double n11 = aa+bb; 899c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double n12 = a*c+b*d; 900c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double n21 = n12; 901c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double n22 = cc+dd; 902c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double det = a*d-b*c; 903c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double twice_det = det+det; 904c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double frobenius_squared = n11+n22; 905c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double discriminant = 906c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony (frobenius_squared+twice_det)*(frobenius_squared-twice_det); 907564e05ecd66ac304817909c9ed31a6eca3a71714nicolas /* 908564e05ecd66ac304817909c9ed31a6eca3a71714nicolas * In exact arithmetic, discriminant can't be negative. In floating 909564e05ecd66ac304817909c9ed31a6eca3a71714nicolas * point, it can, because of the bad conditioning of SVD 910564e05ecd66ac304817909c9ed31a6eca3a71714nicolas * decompositions done through the associated normal matrix. 911564e05ecd66ac304817909c9ed31a6eca3a71714nicolas */ 91293c8f1606f63ab2bac5d044f5174dfee75da57cacristy const double sqrt_discriminant = 913bb89b9227e797258cc59dfa6fd449989109e22b2nicolas sqrt(discriminant > 0.0 ? discriminant : 0.0); 914c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony /* 915c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * s1 is the largest singular value of the inverse Jacobian 916c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * matrix. In other words, its reciprocal is the smallest singular 917c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * value of the Jacobian matrix itself. 918c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * If s1 = 0, both singular values are 0, and any orthogonal pair of 919c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * left and right factors produces a singular decomposition of Jinv. 920c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas */ 921c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas /* 9228b1d981efa1bdef504b79420d43936c49eeecd3dnicolas * Initially, we only compute the squares of the singular values. 923c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony */ 924c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double s1s1 = 0.5*(frobenius_squared+sqrt_discriminant); 925c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony /* 926c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * s2 the smallest singular value of the inverse Jacobian 927c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * matrix. Its reciprocal is the largest singular value of the 928c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * Jacobian matrix itself. 929c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony */ 930c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double s2s2 = 0.5*(frobenius_squared-sqrt_discriminant); 931c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double s1s1minusn11 = s1s1-n11; 932c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double s1s1minusn22 = s1s1-n22; 933c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony /* 934c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * u1, the first column of the U factor of a singular decomposition 935c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * of Jinv, is a (non-normalized) left singular vector corresponding 936c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * to s1. It has entries u11 and u21. We compute u1 from the fact 937c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * that it is an eigenvector of n corresponding to the eigenvalue 938c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * s1^2. 939c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony */ 940c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double s1s1minusn11_squared = s1s1minusn11*s1s1minusn11; 941c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double s1s1minusn22_squared = s1s1minusn22*s1s1minusn22; 942c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony /* 943c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * The following selects the largest row of n-s1^2 I as the one 944c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * which is used to find the eigenvector. If both s1^2-n11 and 945c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * s1^2-n22 are zero, n-s1^2 I is the zero matrix. In that case, 946c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * any vector is an eigenvector; in addition, norm below is equal to 947c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * zero, and, in exact arithmetic, this is the only case in which 948c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * norm = 0. So, setting u1 to the simple but arbitrary vector [1,0] 949c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * if norm = 0 safely takes care of all cases. 950c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony */ 951c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double temp_u11 = 952c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony ( (s1s1minusn11_squared>=s1s1minusn22_squared) ? n12 : s1s1minusn22 ); 953c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double temp_u21 = 954c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony ( (s1s1minusn11_squared>=s1s1minusn22_squared) ? s1s1minusn11 : n21 ); 955c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double norm = sqrt(temp_u11*temp_u11+temp_u21*temp_u21); 956c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony /* 957c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * Finalize the entries of first left singular vector (associated 958c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * with the largest singular value). 959c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony */ 960c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double u11 = ( (norm>0.0) ? temp_u11/norm : 1.0 ); 961c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony const double u21 = ( (norm>0.0) ? temp_u21/norm : 0.0 ); 962c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony /* 963c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony * Clamp the singular values up to 1. 964c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony */ 965ed22721389b8ff2983982914d29db84731825a8fnicolas *major_mag = ( (s1s1<=1.0) ? 1.0 : sqrt(s1s1) ); 966ed22721389b8ff2983982914d29db84731825a8fnicolas *minor_mag = ( (s2s2<=1.0) ? 1.0 : sqrt(s2s2) ); 967c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas /* 968c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas * Return the unit major and minor axis direction vectors. 969c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas */ 970c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony *major_unit_x = u11; 971c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony *major_unit_y = u21; 972c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas *minor_unit_x = -u21; 973c90935cab9d995f4881c8b3c9f7bfd5a1e96b4b8nicolas *minor_unit_y = u11; 974c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony} 975c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony 976c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif 9773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/* 9783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 9803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 9813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 9823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% S c a l e R e s a m p l e F i l t e r % 9833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 9843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 9853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 9863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 9883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% ScaleResampleFilter() does all the calculations needed to resample an image 9893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% at a specific scale, defined by two scaling vectors. This not using 9903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% a orthogonal scaling, but two distorted scaling vectors, to allow the 9913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% generation of a angled ellipse. 9923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 9933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% As only two deritive scaling vectors are used the center of the ellipse 9943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% must be the center of the lookup. That is any curvature that the 9953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% distortion may produce is discounted. 9963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 9973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% The input vectors are produced by either finding the derivitives of the 9983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% distortion function, or the partial derivitives from a distortion mapping. 9993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% They do not need to be the orthogonal dx,dy scaling vectors, but can be 10003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% calculated from other derivatives. For example you could use dr,da/r 10013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% polar coordinate vector scaling vectors 10023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 1003c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% If u,v = DistortEquation(x,y) OR u = Fu(x,y); v = Fv(x,y) 1004c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% Then the scaling vectors are determined from the deritives... 10053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% du/dx, dv/dx and du/dy, dv/dy 1006c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% If the resulting scaling vectors is othogonally aligned then... 10073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% dv/dx = 0 and du/dy = 0 1008c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% Producing an othogonally alligned ellipse in source space for the area to 1009c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% be resampled. 10103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 10113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Note that scaling vectors are different to argument order. Argument order 10123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% is the general order the deritives are extracted from the distortion 1013c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% equations, and not the scaling vectors. As such the middle two vaules 1014c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% may be swapped from what you expect. Caution is advised. 10153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 10163ebea1e232532895681cd50101ddad0856e9a1d3anthony% WARNING: It is assumed that any SetResampleFilter() method call will 10173ebea1e232532895681cd50101ddad0856e9a1d3anthony% always be performed before the ScaleResampleFilter() method, so that the 10183ebea1e232532895681cd50101ddad0856e9a1d3anthony% size of the ellipse will match the support for the resampling filter being 10193ebea1e232532895681cd50101ddad0856e9a1d3anthony% used. 1020490ab03a4e81aa0943087243055c77e3794d75d9anthony% 10213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% The format of the ScaleResampleFilter method is: 10223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 10233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% void ScaleResampleFilter(const ResampleFilter *resample_filter, 10243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% const double dux,const double duy,const double dvx,const double dvy) 10253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 10263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% A description of each parameter follows: 10273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 10283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o resample_filter: the resampling resample_filterrmation defining the 10293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% image being resampled 10303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 10313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o dux,duy,dvx,dvy: 1032c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% The deritives or scaling vectors defining the EWA ellipse. 1033c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% NOTE: watch the order, which is based on the order deritives 1034c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% are usally determined from distortion equations (see above). 1035c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% The middle two values may need to be swapped if you are thinking 1036c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony% in terms of scaling vectors. 10373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 10383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/ 10393ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport void ScaleResampleFilter(ResampleFilter *resample_filter, 10403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy const double dux,const double duy,const double dvx,const double dvy) 10413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 1042d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony double A,B,C,F; 10433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 10443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy assert(resample_filter != (ResampleFilter *) NULL); 1045e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(resample_filter->signature == MagickCoreSignature); 10463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 10473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->limit_reached = MagickFalse; 10483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1049b821aafe132291d46e0fb0c2b24e6e467aa17640anthony /* A 'point' filter forces use of interpolation instead of area sampling */ 1050b821aafe132291d46e0fb0c2b24e6e467aa17640anthony if ( resample_filter->filter == PointFilter ) 1051b821aafe132291d46e0fb0c2b24e6e467aa17640anthony return; /* EWA turned off - nothing to do */ 1052b821aafe132291d46e0fb0c2b24e6e467aa17640anthony 1053c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if DEBUG_ELLIPSE 10545acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "# -----\n" ); 10555acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "dux=%lf; dvx=%lf; duy=%lf; dvy=%lf;\n", 1056c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony dux, dvx, duy, dvy); 1057c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif 10583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 10593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Find Ellipse Coefficents such that 10603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy A*u^2 + B*u*v + C*v^2 = F 10613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy With u,v relative to point around which we are resampling. 10623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy And the given scaling dx,dy vectors in u,v space 10633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy du/dx,dv/dx and du/dy,dv/dy 10643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 1065c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA 1066d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony /* Direct conversion of derivatives into elliptical coefficients 1067b821aafe132291d46e0fb0c2b24e6e467aa17640anthony However when magnifying images, the scaling vectors will be small 1068b821aafe132291d46e0fb0c2b24e6e467aa17640anthony resulting in a ellipse that is too small to sample properly. 1069b821aafe132291d46e0fb0c2b24e6e467aa17640anthony As such we need to clamp the major/minor axis to a minumum of 1.0 1070b821aafe132291d46e0fb0c2b24e6e467aa17640anthony to prevent it getting too small. 10713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 1072c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA_CLAMP 1073c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony { double major_mag, 1074c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony minor_mag, 1075c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony major_x, 1076c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony major_y, 1077c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony minor_x, 1078c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony minor_y; 1079c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony 1080c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony ClampUpAxes(dux,dvx,duy,dvy, &major_mag, &minor_mag, 1081c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony &major_x, &major_y, &minor_x, &minor_y); 1082bdfddb0056c20dba73d299334525256fa6a99986anthony major_x *= major_mag; major_y *= major_mag; 1083bdfddb0056c20dba73d299334525256fa6a99986anthony minor_x *= minor_mag; minor_y *= minor_mag; 1084c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if DEBUG_ELLIPSE 10855acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "major_x=%lf; major_y=%lf; minor_x=%lf; minor_y=%lf;\n", 1086c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony major_x, major_y, minor_x, minor_y); 1087c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#endif 1088c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony A = major_y*major_y+minor_y*minor_y; 1089c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony B = -2.0*(major_x*major_y+minor_x*minor_y); 1090c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony C = major_x*major_x+minor_x*minor_x; 1091eaa08628db6764fa5cb6802eaf9bb5753c25eb1fnicolas F = major_mag*minor_mag; 1092c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony F *= F; /* square it */ 1093c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony } 10945b697cdb1ed6e391b98953aafd362bddad51b453anthony#else /* raw unclamped EWA */ 10953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy A = dvx*dvx+dvy*dvy; 1096d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony B = -2.0*(dux*dvx+duy*dvy); 10973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy C = dux*dux+duy*duy; 1098c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony F = dux*dvy-duy*dvx; 10995708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony F *= F; /* square it */ 11005b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif /* EWA_CLAMP */ 1101d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony 1102490ab03a4e81aa0943087243055c77e3794d75d9anthony#else /* HQ_EWA */ 1103d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony /* 1104c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony This Paul Heckbert's "Higher Quality EWA" formula, from page 60 in his 1105c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony thesis, which adds a unit circle to the elliptical area so as to do both 1106c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony Reconstruction and Prefiltering of the pixels in the resampling. It also 1107c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony means it is always likely to have at least 4 pixels within the area of the 1108c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony ellipse, for weighted averaging. No scaling will result with F == 4.0 and 1109c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony a circle of radius 2.0, and F smaller than this means magnification is 1110c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony being used. 1111c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony 1112c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony NOTE: This method produces a very blury result at near unity scale while 1113bdfddb0056c20dba73d299334525256fa6a99986anthony producing perfect results for strong minitification and magnifications. 1114490ab03a4e81aa0943087243055c77e3794d75d9anthony 1115c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony However filter support is fixed to 2.0 (no good for Windowed Sinc filters) 11163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 11173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy A = dvx*dvx+dvy*dvy+1; 1118d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony B = -2.0*(dux*dvx+duy*dvy); 11193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy C = dux*dux+duy*duy+1; 11203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy F = A*C - B*B/4; 11213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif 11223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1123490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE 11245acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "A=%lf; B=%lf; C=%lf; F=%lf\n", A,B,C,F); 11253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1126c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony /* Figure out the various information directly about the ellipse. 11273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy This information currently not needed at this time, but may be 11283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy needed later for better limit determination. 1129d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony 1130d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony It is also good to have as a record for future debugging 11313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 11323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { double alpha, beta, gamma, Major, Minor; 1133490ab03a4e81aa0943087243055c77e3794d75d9anthony double Eccentricity, Ellipse_Area, Ellipse_Angle; 1134d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony 11353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy alpha = A+C; 11363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy beta = A-C; 11373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy gamma = sqrt(beta*beta + B*B ); 11383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 11393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( alpha - gamma <= MagickEpsilon ) 11400283b31ed43486c1b3c6d903f6992b6402419c40cristy Major=MagickMaximumValue; 11413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else 11420283b31ed43486c1b3c6d903f6992b6402419c40cristy Major=sqrt(2*F/(alpha - gamma)); 11433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Minor = sqrt(2*F/(alpha + gamma)); 11443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 11455acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "# Major=%lf; Minor=%lf\n", Major, Minor ); 11463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 11473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* other information about ellipse include... */ 11483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Eccentricity = Major/Minor; 11493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Ellipse_Area = MagickPI*Major*Minor; 1150e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas Ellipse_Angle = atan2(B, A-C); 11513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 11525acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "# Angle=%lf Area=%lf\n", 1153c73fc9412a0bf22993e401c03e6cf1ae38ed46d9anthony (double) RadiansToDegrees(Ellipse_Angle), Ellipse_Area); 11543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 11553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif 11563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 115715c331b918b9c7b71e876965897b66ff6118a269nicolas /* If one or both of the scaling vectors is impossibly large 115815c331b918b9c7b71e876965897b66ff6118a269nicolas (producing a very large raw F value), we may as well not bother 115915c331b918b9c7b71e876965897b66ff6118a269nicolas doing any form of resampling since resampled area is very large. 116015c331b918b9c7b71e876965897b66ff6118a269nicolas In this case some alternative means of pixel sampling, such as 116115c331b918b9c7b71e876965897b66ff6118a269nicolas the average of the whole image is needed to get a reasonable 116215c331b918b9c7b71e876965897b66ff6118a269nicolas result. Calculate only as needed. 11633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 1164fe181a767c3b3e61b9133829c504e75e34916de8cristy if ( (4*A*C - B*B) > MagickMaximumValue ) { 11653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->limit_reached = MagickTrue; 11663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return; 11673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 11683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1169582b6d79fc381d6c9455f3f1b3e26923950161ebanthony /* Scale ellipse to match the filters support 11709cb63ccb02272521283da6d251068d91196cc5bfanthony (that is, multiply F by the square of the support) 11719cb63ccb02272521283da6d251068d91196cc5bfanthony Simplier to just multiply it by the support twice! 1172e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas */ 1173490ab03a4e81aa0943087243055c77e3794d75d9anthony F *= resample_filter->support; 1174490ab03a4e81aa0943087243055c77e3794d75d9anthony F *= resample_filter->support; 11753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1176e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas /* Orthogonal bounds of the ellipse */ 1177c120ce3e122ce1c110efd35b31c4083f192a7209cristy resample_filter->Ulimit = sqrt(C*F/(A*C-0.25*B*B)); 1178c120ce3e122ce1c110efd35b31c4083f192a7209cristy resample_filter->Vlimit = sqrt(A*F/(A*C-0.25*B*B)); 11793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1180e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas /* Horizontally aligned parallelogram fitted to Ellipse */ 1181e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas resample_filter->Uwidth = sqrt(F/A); /* Half of the parallelogram width */ 1182c120ce3e122ce1c110efd35b31c4083f192a7209cristy resample_filter->slope = -B/(2.0*A); /* Reciprocal slope of the parallelogram */ 1183490ab03a4e81aa0943087243055c77e3794d75d9anthony 1184490ab03a4e81aa0943087243055c77e3794d75d9anthony#if DEBUG_ELLIPSE 11855acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Ulimit=%lf; Vlimit=%lf; UWidth=%lf; Slope=%lf;\n", 1186490ab03a4e81aa0943087243055c77e3794d75d9anthony resample_filter->Ulimit, resample_filter->Vlimit, 1187490ab03a4e81aa0943087243055c77e3794d75d9anthony resample_filter->Uwidth, resample_filter->slope ); 1188490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif 11893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1190e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas /* Check the absolute area of the parallelogram involved. 1191e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas * This limit needs more work, as it is too slow for larger images 1192e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas * with tiled views of the horizon. 1193e2ecb24b173a968e2d836a64b74d9fa8303919dbnicolas */ 119439f347aa142535ededfff86309cc2bb4cf222373cristy if ( (resample_filter->Uwidth * resample_filter->Vlimit) 119539f347aa142535ededfff86309cc2bb4cf222373cristy > (4.0*resample_filter->image_area)) { 11963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->limit_reached = MagickTrue; 11973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return; 11983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 11993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 12005708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony /* Scale ellipse formula to directly index the Filter Lookup Table */ 12013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { register double scale; 12025b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT 1203582b6d79fc381d6c9455f3f1b3e26923950161ebanthony /* scale so that F = WLUT_WIDTH; -- hardcoded */ 1204490ab03a4e81aa0943087243055c77e3794d75d9anthony scale = (double)WLUT_WIDTH/F; 12055b697cdb1ed6e391b98953aafd362bddad51b453anthony#else 1206582b6d79fc381d6c9455f3f1b3e26923950161ebanthony /* scale so that F = resample_filter->F (support^2) */ 1207582b6d79fc381d6c9455f3f1b3e26923950161ebanthony scale = resample_filter->F/F; 12085b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif 12093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->A = A*scale; 12103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->B = B*scale; 12113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->C = C*scale; 12123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 12133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 12143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 12153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/* 12163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 12183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 12193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 12203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% S e t R e s a m p l e F i l t e r % 12213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 12223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 12233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 12243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 12263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% SetResampleFilter() set the resampling filter lookup table based on a 12273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% specific filter. Note that the filter is used as a radial filter not as a 12283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% two pass othogonally aligned resampling filter. 12293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 12303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% The format of the SetResampleFilter method is: 12313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 12323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% void SetResampleFilter(ResampleFilter *resample_filter, 12338b9f21cab4c50eb7d6e558a7a43a68833fe0b55ddirk% const FilterType filter) 12343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 12353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% A description of each parameter follows: 12363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 12373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o resample_filter: resampling resample_filterrmation structure 12383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 12393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o filter: the resize filter for elliptical weighting LUT 12403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 12413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/ 12423ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport void SetResampleFilter(ResampleFilter *resample_filter, 12438b9f21cab4c50eb7d6e558a7a43a68833fe0b55ddirk const FilterType filter) 12443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 12453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ResizeFilter 12463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *resize_filter; 12473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 12483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy assert(resample_filter != (ResampleFilter *) NULL); 1249e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(resample_filter->signature == MagickCoreSignature); 12503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 12512e6ab68e6538e73abd8d77f505bc9f033c742f1canthony resample_filter->do_interpolate = MagickFalse; 12523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->filter = filter; 12533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 12549cb63ccb02272521283da6d251068d91196cc5bfanthony /* Default cylindrical filter is a Cubic Keys filter */ 1255490ab03a4e81aa0943087243055c77e3794d75d9anthony if ( filter == UndefinedFilter ) 1256853d6979aa2981592af7020163b5030aa7185783anthony resample_filter->filter = RobidouxFilter; 1257490ab03a4e81aa0943087243055c77e3794d75d9anthony 12589cb63ccb02272521283da6d251068d91196cc5bfanthony if ( resample_filter->filter == PointFilter ) { 12599cb63ccb02272521283da6d251068d91196cc5bfanthony resample_filter->do_interpolate = MagickTrue; 12609cb63ccb02272521283da6d251068d91196cc5bfanthony return; /* EWA turned off - nothing more to do */ 12619cb63ccb02272521283da6d251068d91196cc5bfanthony } 12629cb63ccb02272521283da6d251068d91196cc5bfanthony 1263490ab03a4e81aa0943087243055c77e3794d75d9anthony resize_filter = AcquireResizeFilter(resample_filter->image, 1264aa2c16cb5e695053aa78e40f66bc36fbef4b1ed1cristy resample_filter->filter,MagickTrue,resample_filter->exception); 12659cb63ccb02272521283da6d251068d91196cc5bfanthony if (resize_filter == (ResizeFilter *) NULL) { 12669cb63ccb02272521283da6d251068d91196cc5bfanthony (void) ThrowMagickException(resample_filter->exception,GetMagickModule(), 12679cb63ccb02272521283da6d251068d91196cc5bfanthony ModuleError, "UnableToSetFilteringValue", 12689cb63ccb02272521283da6d251068d91196cc5bfanthony "Fall back to Interpolated 'Point' filter"); 12699cb63ccb02272521283da6d251068d91196cc5bfanthony resample_filter->filter = PointFilter; 12709cb63ccb02272521283da6d251068d91196cc5bfanthony resample_filter->do_interpolate = MagickTrue; 12719cb63ccb02272521283da6d251068d91196cc5bfanthony return; /* EWA turned off - nothing more to do */ 12729cb63ccb02272521283da6d251068d91196cc5bfanthony } 1273490ab03a4e81aa0943087243055c77e3794d75d9anthony 127410b8bc801774c852503dfc90a706dfa942f9cc2eanthony /* Get the practical working support for the filter, 127510b8bc801774c852503dfc90a706dfa942f9cc2eanthony * after any API call blur factors have been accoded for. 127610b8bc801774c852503dfc90a706dfa942f9cc2eanthony */ 1277c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#if EWA 1278490ab03a4e81aa0943087243055c77e3794d75d9anthony resample_filter->support = GetResizeFilterSupport(resize_filter); 1279c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony#else 1280c7b82f23bddac7a7ced841ae4fdc225b8e4763afanthony resample_filter->support = 2.0; /* fixed support size for HQ-EWA */ 1281490ab03a4e81aa0943087243055c77e3794d75d9anthony#endif 1282490ab03a4e81aa0943087243055c77e3794d75d9anthony 12835b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT 12845b697cdb1ed6e391b98953aafd362bddad51b453anthony /* Fill the LUT with the weights from the selected filter function */ 12855b697cdb1ed6e391b98953aafd362bddad51b453anthony { register int 12865b697cdb1ed6e391b98953aafd362bddad51b453anthony Q; 12875b697cdb1ed6e391b98953aafd362bddad51b453anthony double 12885b697cdb1ed6e391b98953aafd362bddad51b453anthony r_scale; 12899cb63ccb02272521283da6d251068d91196cc5bfanthony 12905b697cdb1ed6e391b98953aafd362bddad51b453anthony /* Scale radius so the filter LUT covers the full support range */ 12915b697cdb1ed6e391b98953aafd362bddad51b453anthony r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH); 12925b697cdb1ed6e391b98953aafd362bddad51b453anthony for(Q=0; Q<WLUT_WIDTH; Q++) 12935b697cdb1ed6e391b98953aafd362bddad51b453anthony resample_filter->filter_lut[Q] = (double) 12945b697cdb1ed6e391b98953aafd362bddad51b453anthony GetResizeFilterWeight(resize_filter,sqrt((double)Q)*r_scale); 12955b697cdb1ed6e391b98953aafd362bddad51b453anthony 12965b697cdb1ed6e391b98953aafd362bddad51b453anthony /* finished with the resize filter */ 12975b697cdb1ed6e391b98953aafd362bddad51b453anthony resize_filter = DestroyResizeFilter(resize_filter); 12985b697cdb1ed6e391b98953aafd362bddad51b453anthony } 12995b697cdb1ed6e391b98953aafd362bddad51b453anthony#else 1300582b6d79fc381d6c9455f3f1b3e26923950161ebanthony /* save the filter and the scaled ellipse bounds needed for filter */ 13015b697cdb1ed6e391b98953aafd362bddad51b453anthony resample_filter->filter_def = resize_filter; 1302582b6d79fc381d6c9455f3f1b3e26923950161ebanthony resample_filter->F = resample_filter->support*resample_filter->support; 13035b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif 1304490ab03a4e81aa0943087243055c77e3794d75d9anthony 13053ebea1e232532895681cd50101ddad0856e9a1d3anthony /* 13063ebea1e232532895681cd50101ddad0856e9a1d3anthony Adjust the scaling of the default unit circle 13073ebea1e232532895681cd50101ddad0856e9a1d3anthony This assumes that any real scaling changes will always 13083ebea1e232532895681cd50101ddad0856e9a1d3anthony take place AFTER the filter method has been initialized. 13093ebea1e232532895681cd50101ddad0856e9a1d3anthony */ 13103ebea1e232532895681cd50101ddad0856e9a1d3anthony ScaleResampleFilter(resample_filter, 1.0, 0.0, 0.0, 1.0); 13113ebea1e232532895681cd50101ddad0856e9a1d3anthony 13125708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony#if 0 1313d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony /* 13149cb63ccb02272521283da6d251068d91196cc5bfanthony This is old code kept as a reference only. Basically it generates 13159cb63ccb02272521283da6d251068d91196cc5bfanthony a Gaussian bell curve, with sigma = 0.5 if the support is 2.0 13169cb63ccb02272521283da6d251068d91196cc5bfanthony 1317d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony Create Normal Gaussian 2D Filter Weighted Lookup Table. 1318d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony A normal EWA guassual lookup would use exp(Q*ALPHA) 1319d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony where Q = distance squared from 0.0 (center) to 1.0 (edge) 1320d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony and ALPHA = -4.0*ln(2.0) ==> -2.77258872223978123767 13215b697cdb1ed6e391b98953aafd362bddad51b453anthony The table is of length 1024, and equates to support radius of 2.0 1322d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony thus needs to be scaled by ALPHA*4/1024 and any blur factor squared 1323d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony 13249cb63ccb02272521283da6d251068d91196cc5bfanthony The it comes from reference code provided by Fred Weinhaus. 1325d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony */ 1326d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony r_scale = -2.77258872223978123767/(WLUT_WIDTH*blur*blur); 1327d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony for(Q=0; Q<WLUT_WIDTH; Q++) 1328d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony resample_filter->filter_lut[Q] = exp((double)Q*r_scale); 1329d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony resample_filter->support = WLUT_WIDTH; 13305708fc6b0e0f06db8096b93f8c0f7eefe2346e32anthony#endif 1331490ab03a4e81aa0943087243055c77e3794d75d9anthony 13325b697cdb1ed6e391b98953aafd362bddad51b453anthony#if FILTER_LUT 1333e06e4c180324bebbd41bce9ea4898642f380b614anthony#if defined(MAGICKCORE_OPENMP_SUPPORT) 133472949796e01f8b94a0976e74cb8eb3f86af280eaanthony #pragma omp single 1335e06e4c180324bebbd41bce9ea4898642f380b614anthony#endif 13369cb63ccb02272521283da6d251068d91196cc5bfanthony { 1337972c2e42a2171341bbf55a48cb36882616a591b1dirk if (IsStringTrue(GetImageArtifact(resample_filter->image, 1338972c2e42a2171341bbf55a48cb36882616a591b1dirk "resample:verbose")) != MagickFalse) 1339e06e4c180324bebbd41bce9ea4898642f380b614anthony { 13409cb63ccb02272521283da6d251068d91196cc5bfanthony register int 13419cb63ccb02272521283da6d251068d91196cc5bfanthony Q; 13429cb63ccb02272521283da6d251068d91196cc5bfanthony double 13439cb63ccb02272521283da6d251068d91196cc5bfanthony r_scale; 13449cb63ccb02272521283da6d251068d91196cc5bfanthony 1345e06e4c180324bebbd41bce9ea4898642f380b614anthony /* Debug output of the filter weighting LUT 13469cb63ccb02272521283da6d251068d91196cc5bfanthony Gnuplot the LUT data, the x scale index has been adjusted 13479cb63ccb02272521283da6d251068d91196cc5bfanthony plot [0:2][-.2:1] "lut.dat" with lines 13489cb63ccb02272521283da6d251068d91196cc5bfanthony The filter values should be normalized for comparision 1349e06e4c180324bebbd41bce9ea4898642f380b614anthony */ 1350d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony printf("#\n"); 13519cb63ccb02272521283da6d251068d91196cc5bfanthony printf("# Resampling Filter LUT (%d values) for '%s' filter\n", 13529cb63ccb02272521283da6d251068d91196cc5bfanthony WLUT_WIDTH, CommandOptionToMnemonic(MagickFilterOptions, 13539cb63ccb02272521283da6d251068d91196cc5bfanthony resample_filter->filter) ); 1354e06e4c180324bebbd41bce9ea4898642f380b614anthony printf("#\n"); 1355d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony printf("# Note: values in table are using a squared radius lookup.\n"); 13569cb63ccb02272521283da6d251068d91196cc5bfanthony printf("# As such its distribution is not uniform.\n"); 13579cb63ccb02272521283da6d251068d91196cc5bfanthony printf("#\n"); 13589cb63ccb02272521283da6d251068d91196cc5bfanthony printf("# The X value is the support distance for the Y weight\n"); 13599cb63ccb02272521283da6d251068d91196cc5bfanthony printf("# so you can use gnuplot to plot this cylindrical filter\n"); 13609cb63ccb02272521283da6d251068d91196cc5bfanthony printf("# plot [0:2][-.2:1] \"lut.dat\" with lines\n"); 13619cb63ccb02272521283da6d251068d91196cc5bfanthony printf("#\n"); 13629cb63ccb02272521283da6d251068d91196cc5bfanthony 13639cb63ccb02272521283da6d251068d91196cc5bfanthony /* Scale radius so the filter LUT covers the full support range */ 13649cb63ccb02272521283da6d251068d91196cc5bfanthony r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH); 1365e06e4c180324bebbd41bce9ea4898642f380b614anthony for(Q=0; Q<WLUT_WIDTH; Q++) 1366d638d31054aa44f6f9ea9507d23eca8e29414bd1anthony printf("%8.*g %.*g\n", 13679cb63ccb02272521283da6d251068d91196cc5bfanthony GetMagickPrecision(),sqrt((double)Q)*r_scale, 13689cb63ccb02272521283da6d251068d91196cc5bfanthony GetMagickPrecision(),resample_filter->filter_lut[Q] ); 13699cb63ccb02272521283da6d251068d91196cc5bfanthony printf("\n\n"); /* generate a 'break' in gnuplot if multiple outputs */ 1370e06e4c180324bebbd41bce9ea4898642f380b614anthony } 13719cb63ccb02272521283da6d251068d91196cc5bfanthony /* Output the above once only for each image, and each setting 137272949796e01f8b94a0976e74cb8eb3f86af280eaanthony (void) DeleteImageArtifact(resample_filter->image,"resample:verbose"); 13739cb63ccb02272521283da6d251068d91196cc5bfanthony */ 137472949796e01f8b94a0976e74cb8eb3f86af280eaanthony } 13755b697cdb1ed6e391b98953aafd362bddad51b453anthony#endif /* FILTER_LUT */ 13763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return; 13773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 13783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 13793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/* 13803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 13823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 13833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 13843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 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 % 13853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 13863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 13873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 13883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 13902ab242ec7c723f9f95558b30f1275011aa582ca9cristy% SetResampleFilterInterpolateMethod() sets the resample filter interpolation 13912ab242ec7c723f9f95558b30f1275011aa582ca9cristy% method. 13923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 13933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% The format of the SetResampleFilterInterpolateMethod method is: 13943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 13953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% MagickBooleanType SetResampleFilterInterpolateMethod( 13963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% ResampleFilter *resample_filter,const InterpolateMethod method) 13973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 13983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% A description of each parameter follows: 13993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 14003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o resample_filter: the resample filter. 14013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 14023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o method: the interpolation method. 14033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 14043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/ 14053ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType SetResampleFilterInterpolateMethod( 14065c4e2586d27d4299a742d170d41105de1689aa46cristy ResampleFilter *resample_filter,const PixelInterpolateMethod method) 14073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 14083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy assert(resample_filter != (ResampleFilter *) NULL); 1409e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(resample_filter->signature == MagickCoreSignature); 14103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy assert(resample_filter->image != (Image *) NULL); 14113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (resample_filter->debug != MagickFalse) 14123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 14133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->image->filename); 14143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->interpolate=method; 14152ab242ec7c723f9f95558b30f1275011aa582ca9cristy return(MagickTrue); 14162ab242ec7c723f9f95558b30f1275011aa582ca9cristy} 14172ab242ec7c723f9f95558b30f1275011aa582ca9cristy 14182ab242ec7c723f9f95558b30f1275011aa582ca9cristy/* 14192ab242ec7c723f9f95558b30f1275011aa582ca9cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14202ab242ec7c723f9f95558b30f1275011aa582ca9cristy% % 14212ab242ec7c723f9f95558b30f1275011aa582ca9cristy% % 14222ab242ec7c723f9f95558b30f1275011aa582ca9cristy% % 14233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 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 % 14243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 14253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 14263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 14273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 14293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% SetResampleFilterVirtualPixelMethod() changes the virtual pixel method 14303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% associated with the specified resample filter. 14313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 14323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% The format of the SetResampleFilterVirtualPixelMethod method is: 14333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 14343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% MagickBooleanType SetResampleFilterVirtualPixelMethod( 14353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% ResampleFilter *resample_filter,const VirtualPixelMethod method) 14363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 14373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% A description of each parameter follows: 14383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 14393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o resample_filter: the resample filter. 14403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 14413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o method: the virtual pixel method. 14423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 14433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/ 14443ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport MagickBooleanType SetResampleFilterVirtualPixelMethod( 14453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ResampleFilter *resample_filter,const VirtualPixelMethod method) 14463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 14473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy assert(resample_filter != (ResampleFilter *) NULL); 1448e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(resample_filter->signature == MagickCoreSignature); 14493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy assert(resample_filter->image != (Image *) NULL); 14503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (resample_filter->debug != MagickFalse) 14513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 14523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->image->filename); 14533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter->virtual_pixel=method; 14542d5e44dc510676c5dd9c2a3abefcd5e2556b0fe4cristy if (method != UndefinedVirtualPixelMethod) 14552d5e44dc510676c5dd9c2a3abefcd5e2556b0fe4cristy (void) SetCacheViewVirtualPixelMethod(resample_filter->view,method); 14563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(MagickTrue); 14573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 1458