distort.c

Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %               DDDD   IIIII  SSSSS  TTTTT   OOO   RRRR   TTTTT               %
00007 %               D   D    I    SS       T    O   O  R   R    T                 %
00008 %               D   D    I     SSS     T    O   O  RRRR     T                 %
00009 %               D   D    I       SS    T    O   O  R R      T                 %
00010 %               DDDD   IIIII  SSSSS    T     OOO   R  R     T                 %
00011 %                                                                             %
00012 %                                                                             %
00013 %                     MagickCore Image Distortion Methods                     %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                              Anthony Thyssen                                %
00018 %                                 June 2007                                   %
00019 %                                                                             %
00020 %                                                                             %
00021 %  Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization      %
00022 %  dedicated to making software imaging solutions freely available.           %
00023 %                                                                             %
00024 %  You may not use this file except in compliance with the License.  You may  %
00025 %  obtain a copy of the License at                                            %
00026 %                                                                             %
00027 %    http://www.imagemagick.org/script/license.php                            %
00028 %                                                                             %
00029 %  Unless required by applicable law or agreed to in writing, software        %
00030 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00031 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00032 %  See the License for the specific language governing permissions and        %
00033 %  limitations under the License.                                             %
00034 %                                                                             %
00035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00036 %
00037 %
00038 */
00039 
00040 /*
00041   Include declarations.
00042 */
00043 #include "magick/studio.h"
00044 #include "magick/artifact.h"
00045 #include "magick/cache.h"
00046 #include "magick/cache-view.h"
00047 #include "magick/colorspace-private.h"
00048 #include "magick/composite-private.h"
00049 #include "magick/distort.h"
00050 #include "magick/exception.h"
00051 #include "magick/exception-private.h"
00052 #include "magick/gem.h"
00053 #include "magick/hashmap.h"
00054 #include "magick/image.h"
00055 #include "magick/list.h"
00056 #include "magick/matrix.h"
00057 #include "magick/memory_.h"
00058 #include "magick/monitor-private.h"
00059 #include "magick/pixel.h"
00060 #include "magick/pixel-private.h"
00061 #include "magick/resample.h"
00062 #include "magick/resample-private.h"
00063 #include "magick/registry.h"
00064 #include "magick/semaphore.h"
00065 #include "magick/string_.h"
00066 #include "magick/thread-private.h"
00067 #include "magick/token.h"
00068 
00069 /*
00070   Numerous internal routines for image distortions.
00071 */
00072 static inline double MagickMin(const double x,const double y)
00073 {
00074   return( x < y ? x : y);
00075 }
00076 static inline double MagickMax(const double x,const double y)
00077 {
00078   return( x > y ? x : y);
00079 }
00080 
00081 static inline void AffineArgsToCoefficients(double *affine)
00082 {
00083   /* map  external sx,ry,rx,sy,tx,ty  to  internal c0,c2,c4,c1,c3,c5 */
00084   double tmp[4];  /* note indexes  0 and 5 remain unchanged */
00085   tmp[0]=affine[1]; tmp[1]=affine[2]; tmp[2]=affine[3]; tmp[3]=affine[4];
00086   affine[3]=tmp[0]; affine[1]=tmp[1]; affine[4]=tmp[2]; affine[2]=tmp[3];
00087 }
00088 static inline void CoefficientsToAffineArgs(double *coeff)
00089 {
00090   /* map  internal c0,c1,c2,c3,c4,c5  to  external sx,ry,rx,sy,tx,ty */
00091   double tmp[4];  /* note indexes 0 and 5 remain unchanged */
00092   tmp[0]=coeff[3]; tmp[1]=coeff[1]; tmp[2]=coeff[4]; tmp[3]=coeff[2];
00093   coeff[1]=tmp[0]; coeff[2]=tmp[1]; coeff[3]=tmp[2]; coeff[4]=tmp[3];
00094 }
00095 static void InvertAffineCoefficients(const double *coeff,double *inverse)
00096 {
00097   /* From "Digital Image Warping" by George Wolberg, page 50 */
00098   double determinant;
00099 
00100   determinant=1.0/(coeff[0]*coeff[4]-coeff[1]*coeff[3]);
00101   inverse[0]=determinant*coeff[4];
00102   inverse[1]=determinant*(-coeff[1]);
00103   inverse[2]=determinant*(coeff[1]*coeff[5]-coeff[2]*coeff[4]);
00104   inverse[3]=determinant*(-coeff[3]);
00105   inverse[4]=determinant*coeff[0];
00106   inverse[5]=determinant*(coeff[2]*coeff[3]-coeff[0]*coeff[5]);
00107 }
00108 
00109 static void InvertPerspectiveCoefficients(const double *coeff,
00110   double *inverse)
00111 {
00112   /* From "Digital Image Warping" by George Wolberg, page 53 */
00113   double determinant;
00114 
00115   determinant=1.0/(coeff[0]*coeff[4]-coeff[3]*coeff[1]);
00116   inverse[0]=determinant*(coeff[4]-coeff[7]*coeff[5]);
00117   inverse[1]=determinant*(coeff[7]*coeff[2]-coeff[1]);
00118   inverse[2]=determinant*(coeff[1]*coeff[5]-coeff[4]*coeff[2]);
00119   inverse[3]=determinant*(coeff[6]*coeff[5]-coeff[3]);
00120   inverse[4]=determinant*(coeff[0]-coeff[6]*coeff[2]);
00121   inverse[5]=determinant*(coeff[3]*coeff[2]-coeff[0]*coeff[5]);
00122   inverse[6]=determinant*(coeff[3]*coeff[7]-coeff[6]*coeff[4]);
00123   inverse[7]=determinant*(coeff[6]*coeff[1]-coeff[0]*coeff[7]);
00124 }
00125 
00126 static inline double MagickRound(double x)
00127 {
00128   /* round the fraction to nearest integer */
00129   if (x >= 0.0)
00130     return((double) ((long) (x+0.5)));
00131   return((double) ((long) (x-0.5)));
00132 }
00133 
00134 /*
00135  * Polynomial Term Defining Functions
00136  *
00137  * Order must either be an integer, or 1.5 to produce
00138  * the 2 number_valuesal polyminal function...
00139  *    affine     1 (3)      u = c0 + c1*x + c2*y
00140  *    bilinear  1.5 (4)     u = '' + c3*x*y
00141  *    quadratic  2 (6)      u = '' + c4*x*x + c5*y*y
00142  *    cubic      3 (10)     u = '' + c6*x^3 + c7*x*x*y + c8*x*y*y + c9*y^3
00143  *    quartic    4 (15)     u = '' + c10*x^4 + ... + c14*y^4
00144  *    quintic    5 (21)     u = '' + c15*x^5 + ... + c20*y^5
00145  * number in parenthesis minimum number of points needed.
00146  * Anything beyond quintic, has not been implemented until
00147  * a more automated way of determined terms is found.
00148 
00149  * Note the slight re-ordering of the terms for a quadratic polynomial
00150  * which is to allow the use of a bi-linear (order=1.5) polynomial.
00151  * All the later polynomials are ordered simply from x^N to y^N
00152  */
00153 static unsigned long poly_number_terms(double order)
00154 {
00155  /* Return the number of terms for a 2d polynomial */
00156   if ( order < 1 || order > 5 ||
00157        ( order != floor(order) && (order-1.5) > MagickEpsilon) )
00158     return 0; /* invalid polynomial order */
00159   return((unsigned long) floor((order+1)*(order+2)/2));
00160 }
00161 
00162 static double poly_basis_fn(long n, double x, double y)
00163 {
00164   /* Return the result for this polynomial term */
00165   switch(n) {
00166     case  0:  return( 1.0 ); /* constant */
00167     case  1:  return(  x  );
00168     case  2:  return(  y  ); /* affine      order = 1   terms = 3 */
00169     case  3:  return( x*y ); /* bilinear    order = 1.5 terms = 4 */
00170     case  4:  return( x*x );
00171     case  5:  return( y*y ); /* quadratic   order = 2   terms = 6 */
00172     case  6:  return( x*x*x );
00173     case  7:  return( x*x*y );
00174     case  8:  return( x*y*y );
00175     case  9:  return( y*y*y ); /* cubic       order = 3   terms = 10 */
00176     case 10:  return( x*x*x*x );
00177     case 11:  return( x*x*x*y );
00178     case 12:  return( x*x*y*y );
00179     case 13:  return( x*y*y*y );
00180     case 14:  return( y*y*y*y ); /* quartic     order = 4   terms = 15 */
00181     case 15:  return( x*x*x*x*x );
00182     case 16:  return( x*x*x*x*y );
00183     case 17:  return( x*x*x*y*y );
00184     case 18:  return( x*x*y*y*y );
00185     case 19:  return( x*y*y*y*y );
00186     case 20:  return( y*y*y*y*y ); /* quintic     order = 5   terms = 21 */
00187   }
00188   return( 0 ); /* should never happen */
00189 }
00190 static const char *poly_basis_str(long n)
00191 {
00192   /* return the result for this polynomial term */
00193   switch(n) {
00194     case  0:  return(""); /* constant */
00195     case  1:  return("*ii");
00196     case  2:  return("*jj"); /* affiine      order = 1   terms = 3 */
00197     case  3:  return("*ii*jj"); /* biiliinear    order = 1.5 terms = 4 */
00198     case  4:  return("*ii*ii");
00199     case  5:  return("*jj*jj"); /* quadratiic   order = 2   terms = 6 */
00200     case  6:  return("*ii*ii*ii");
00201     case  7:  return("*ii*ii*jj");
00202     case  8:  return("*ii*jj*jj");
00203     case  9:  return("*jj*jj*jj"); /* cubiic       order = 3   terms = 10 */
00204     case 10:  return("*ii*ii*ii*ii");
00205     case 11:  return("*ii*ii*ii*jj");
00206     case 12:  return("*ii*ii*jj*jj");
00207     case 13:  return("*ii*jj*jj*jj");
00208     case 14:  return("*jj*jj*jj*jj"); /* quartiic     order = 4   terms = 15 */
00209     case 15:  return("*ii*ii*ii*ii*ii");
00210     case 16:  return("*ii*ii*ii*ii*jj");
00211     case 17:  return("*ii*ii*ii*jj*jj");
00212     case 18:  return("*ii*ii*jj*jj*jj");
00213     case 19:  return("*ii*jj*jj*jj*jj");
00214     case 20:  return("*jj*jj*jj*jj*jj"); /* quiintiic     order = 5   terms = 21 */
00215   }
00216   return( "UNKNOWN" ); /* should never happen */
00217 }
00218 static double poly_basis_dx(long n, double x, double y)
00219 {
00220   /* polynomial term for x derivative */
00221   switch(n) {
00222     case  0:  return( 0.0 ); /* constant */
00223     case  1:  return( 1.0 );
00224     case  2:  return( 0.0 ); /* affine      order = 1   terms = 3 */
00225     case  3:  return(  y  ); /* bilinear    order = 1.5 terms = 4 */
00226     case  4:  return(  x  );
00227     case  5:  return( 0.0 ); /* quadratic   order = 2   terms = 6 */
00228     case  6:  return( x*x );
00229     case  7:  return( x*y );
00230     case  8:  return( y*y );
00231     case  9:  return( 0.0 ); /* cubic       order = 3   terms = 10 */
00232     case 10:  return( x*x*x );
00233     case 11:  return( x*x*y );
00234     case 12:  return( x*y*y );
00235     case 13:  return( y*y*y );
00236     case 14:  return( 0.0 ); /* quartic     order = 4   terms = 15 */
00237     case 15:  return( x*x*x*x );
00238     case 16:  return( x*x*x*y );
00239     case 17:  return( x*x*y*y );
00240     case 18:  return( x*y*y*y );
00241     case 19:  return( y*y*y*y );
00242     case 20:  return( 0.0 ); /* quintic     order = 5   terms = 21 */
00243   }
00244   return( 0.0 ); /* should never happen */
00245 }
00246 static double poly_basis_dy(long n, double x, double y)
00247 {
00248   /* polynomial term for y derivative */
00249   switch(n) {
00250     case  0:  return( 0.0 ); /* constant */
00251     case  1:  return( 0.0 );
00252     case  2:  return( 1.0 ); /* affine      order = 1   terms = 3 */
00253     case  3:  return(  x  ); /* bilinear    order = 1.5 terms = 4 */
00254     case  4:  return( 0.0 );
00255     case  5:  return(  y  ); /* quadratic   order = 2   terms = 6 */
00256     default:  return( poly_basis_dx(n-1,x,y) ); /* weird but true */
00257   }
00258   /* NOTE: the only reason that last is not true for 'quadtratic'
00259      is due to the re-arrangement of terms to allow for 'bilinear'
00260   */
00261 }
00262 
00263 /*
00264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00265 %                                                                             %
00266 %                                                                             %
00267 %                                                                             %
00268 +   G e n e r a t e C o e f f i c i e n t s                                   %
00269 %                                                                             %
00270 %                                                                             %
00271 %                                                                             %
00272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00273 %
00274 %  GenerateCoefficients() takes user provided input arguments and generates
00275 %  the coefficients, needed to apply the specific distortion for either
00276 %  distorting images (generally using control points) or generating a color
00277 %  gradient from sparsely separated color points.
00278 %
00279 %  The format of the GenerateCoefficients() method is:
00280 %
00281 %    Image *GenerateCoefficients(const Image *image,DistortImageMethod method,
00282 %        const unsigned long number_arguments,const double *arguments,
00283 %        unsigned long number_values, ExceptionInfo *exception)
00284 %
00285 %  A description of each parameter follows:
00286 %
00287 %    o image: the image to be distorted.
00288 %
00289 %    o method: the method of image distortion/ sparse gradient
00290 %
00291 %    o number_arguments: the number of arguments given.
00292 %
00293 %    o arguments: the arguments for this distortion method.
00294 %
00295 %    o number_values: the style and format of given control points, (caller type)
00296 %         0: 2 dimensional mapping of control points (Distort)
00297 %            Format:  u,v,x,y  where u,v is the 'source' of the
00298 %            the color to be plotted, for DistortImage()
00299 %         N: Interpolation of control points with N values (usally r,g,b)
00300 %            Format: x,y,r,g,b    mapping x,y to color values r,g,b
00301 %            IN future, varible number of values may be given (1 to N)
00302 %
00303 %    o exception: return any errors or warnings in this structure
00304 %
00305 %  Note that the returned array of double values must be freed by the
00306 %  calling method using RelinquishMagickMemory().  This however may change in
00307 %  the future to require a more 'method' specific method.
00308 %
00309 %  Because of this this method should not be classed as stable or used
00310 %  outside other MagickCore library methods.
00311 */
00312 
00313 static double *GenerateCoefficients(const Image *image,
00314   DistortImageMethod *method,const unsigned long number_arguments,
00315   const double *arguments,unsigned long number_values,ExceptionInfo *exception)
00316 {
00317   double
00318     *coeff;
00319 
00320   register unsigned long
00321     i;
00322 
00323   unsigned long
00324     number_coeff, /* number of coefficients to return (array size) */
00325     cp_size,      /* number floating point numbers per control point */
00326     cp_x,cp_y,    /* the x,y indexes for control point */
00327     cp_values;    /* index of values for this control point */
00328     /* number_values   Number of values given per control point */
00329 
00330   if ( number_values == 0 ) {
00331     /* Image distortion using control points (or other distortion)
00332        That is generate a mapping so that   x,y->u,v   given  u,v,x,y
00333     */
00334     number_values = 2;   /* special case: two values of u,v */
00335     cp_values = 0;       /* the values i,j are BEFORE the destination CP x,y */
00336     cp_x = 2;            /* location of x,y in input control values */
00337     cp_y = 3;
00338     /* NOTE: cp_values, also used for later 'reverse map distort' tests */
00339   }
00340   else {
00341     cp_x = 0;            /* location of x,y in input control values */
00342     cp_y = 1;
00343     cp_values = 2;       /* and the other values are after x,y */
00344     /* Typically in this case the values are R,G,B color values */
00345   }
00346   cp_size = number_values+2; /* each CP defintion involves this many numbers */
00347 
00348   /* If not enough control point pairs are found for specific distortions
00349     fall back to Affine distortion (allowing 0 to 3 point pairs)
00350   */
00351   if ( number_arguments < 4*cp_size && 
00352        (  *method == BilinearForwardDistortion
00353        || *method == BilinearReverseDistortion
00354        || *method == PerspectiveDistortion
00355        ) )
00356     *method = AffineDistortion;
00357 
00358   number_coeff=0;
00359   switch (*method) {
00360     case AffineDistortion:
00361     /* also BarycentricColorInterpolate: */
00362       number_coeff=3*number_values;
00363       break;
00364     case PolynomialDistortion:
00365       /* number of coefficents depend on the given polynomal 'order' */
00366       if ( number_arguments <= 1 && (number_arguments-1)%cp_size != 0)
00367       {
00368         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00369                    "InvalidArgument","%s : '%s'","Polynomial",
00370                    "Invalid number of args: order [CPs]...");
00371         return((double *) NULL);
00372       }
00373       i = poly_number_terms(arguments[0]);
00374       number_coeff = 2 + i*number_values;
00375       if ( i == 0 ) {
00376         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00377                    "InvalidArgument","%s : '%s'","Polynomial",
00378                    "Invalid order, should be interger 1 to 5, or 1.5");
00379         return((double *) NULL);
00380       }
00381       if ( number_arguments < 1+i*cp_size ) {
00382         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00383                "InvalidArgument", "%s : 'require at least %ld CPs'",
00384                "Polynomial", i);
00385         return((double *) NULL);
00386       }
00387       break;
00388     case BilinearReverseDistortion:
00389       number_coeff=4*number_values;
00390       break;
00391     /*
00392       The rest are constants as they are only used for image distorts
00393     */
00394     case BilinearForwardDistortion:
00395       number_coeff=10; /* 2*4 coeff plus 2 constants */
00396       cp_x = 0;        /* Reverse src/dest coords for forward mapping */
00397       cp_y = 1;
00398       cp_values = 2;
00399       break;
00400 #if 0
00401     case QuadraterialDistortion:
00402       number_coeff=19; /* BilinearForward + BilinearReverse */
00403 #endif
00404       break;
00405     case ShepardsDistortion:
00406     case VoronoiColorInterpolate:
00407       number_coeff=1;  /* not used, but provide some type of return */
00408       break;
00409     case ArcDistortion:
00410       number_coeff=5;
00411       break;
00412     case ScaleRotateTranslateDistortion:
00413     case AffineProjectionDistortion:
00414       number_coeff=6;
00415       break;
00416     case PolarDistortion:
00417     case DePolarDistortion:
00418       number_coeff=8;
00419       break;
00420     case PerspectiveDistortion:
00421     case PerspectiveProjectionDistortion:
00422       number_coeff=9;
00423       break;
00424     case BarrelDistortion:
00425     case BarrelInverseDistortion:
00426       number_coeff=10;
00427       break;
00428     case UndefinedDistortion:
00429     default:
00430       assert(! "Unknown Method Given"); /* just fail assertion */
00431   }
00432 
00433   /* allocate the array of coefficients needed */
00434   coeff = (double *) AcquireQuantumMemory(number_coeff,sizeof(*coeff));
00435   if (coeff == (double *) NULL) {
00436     (void) ThrowMagickException(exception,GetMagickModule(),
00437                   ResourceLimitError,"MemoryAllocationFailed",
00438                   "%s", "GenerateCoefficients");
00439     return((double *) NULL);
00440   }
00441 
00442   /* zero out coeffiecents array */
00443   for (i=0; i < number_coeff; i++)
00444     coeff[i] = 0.0;
00445 
00446   switch (*method)
00447   {
00448     case AffineDistortion:
00449     {
00450       /* Affine Distortion
00451            v =  c0*x + c1*y + c2
00452          for each 'value' given
00453 
00454          Input Arguments are sets of control points...
00455          For Distort Images    u,v, x,y  ...
00456          For Sparse Gradients  x,y, r,g,b  ...
00457       */
00458       if ( number_arguments%cp_size != 0 ||
00459            number_arguments < cp_size ) {
00460         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00461                "InvalidArgument", "%s : 'require at least %ld CPs'",
00462                "Affine", 1L);
00463         coeff=(double *) RelinquishMagickMemory(coeff);
00464         return((double *) NULL);
00465       }
00466       /* handle special cases of not enough arguments */
00467       if ( number_arguments == cp_size ) {
00468         /* Only 1 CP Set Given */
00469         if ( cp_values == 0 ) {
00470           /* image distortion - translate the image */
00471           coeff[0] = 1.0;
00472           coeff[2] = arguments[0] - arguments[2];
00473           coeff[4] = 1.0;
00474           coeff[5] = arguments[1] - arguments[3];
00475         }
00476         else {
00477           /* sparse gradient - use the values directly */
00478           for (i=0; i<number_values; i++)
00479             coeff[i*3+2] = arguments[cp_values+i];
00480         }
00481       }
00482       else {
00483         /* 2 or more points (usally 3) given.
00484            Solve a least squares simultanious equation for coefficients.
00485         */
00486         double
00487           **matrix,
00488           **vectors,
00489           terms[3];
00490 
00491         MagickBooleanType
00492           status;
00493 
00494         /* create matrix, and a fake vectors matrix */
00495         matrix = AcquireMagickMatrix(3UL,3UL);
00496         vectors = (double **) AcquireQuantumMemory(number_values,sizeof(*vectors));
00497         if (matrix == (double **) NULL || vectors == (double **) NULL)
00498         {
00499           matrix  = RelinquishMagickMatrix(matrix, 3UL);
00500           vectors = (double **) RelinquishMagickMemory(vectors);
00501           coeff   = (double *) RelinquishMagickMemory(coeff);
00502           (void) ThrowMagickException(exception,GetMagickModule(),
00503                   ResourceLimitError,"MemoryAllocationFailed",
00504                   "%s", "DistortCoefficients");
00505           return((double *) NULL);
00506         }
00507         /* fake a number_values x3 vectors matrix from coefficients array */
00508         for (i=0; i < number_values; i++)
00509           vectors[i] = &(coeff[i*3]);
00510         /* Add given control point pairs for least squares solving */
00511         for (i=0; i < number_arguments; i+=cp_size) {
00512           terms[0] = arguments[i+cp_x];  /* x */
00513           terms[1] = arguments[i+cp_y];  /* y */
00514           terms[2] = 1;                  /* 1 */
00515           LeastSquaresAddTerms(matrix,vectors,terms,
00516                    &(arguments[i+cp_values]),3UL,number_values);
00517         }
00518         if ( number_arguments == 2*cp_size ) {
00519           /* Only two pairs were given, but we need 3 to solve the affine.
00520              Fake extra coordinates by rotating p1 around p0 by 90 degrees.
00521                x2 = x0 - (y1-y0)   y2 = y0 + (x1-x0)
00522            */
00523           terms[0] = arguments[cp_x]
00524                    - ( arguments[cp_size+cp_y] - arguments[cp_y] ); /* x2 */
00525           terms[1] = arguments[cp_y] +
00526                    + ( arguments[cp_size+cp_x] - arguments[cp_x] ); /* y2 */
00527           terms[2] = 1;                                             /* 1 */
00528           if ( cp_values == 0 ) {
00529             /* Image Distortion - rotate the u,v coordients too */
00530             double
00531               uv2[2];
00532             uv2[0] = arguments[0] - arguments[5] + arguments[1];   /* u2 */
00533             uv2[1] = arguments[1] + arguments[4] - arguments[0];   /* v2 */
00534             LeastSquaresAddTerms(matrix,vectors,terms,uv2,3UL,2UL);
00535           }
00536           else {
00537             /* Sparse Gradient - use values of p0 for linear gradient */
00538             LeastSquaresAddTerms(matrix,vectors,terms,
00539                   &(arguments[cp_values]),3UL,number_values);
00540           }
00541         }
00542         /* Solve for LeastSquares Coefficients */
00543         status=GaussJordanElimination(matrix,vectors,3UL,number_values);
00544         matrix = RelinquishMagickMatrix(matrix, 3UL);
00545         vectors = (double **) RelinquishMagickMemory(vectors);
00546         if ( status == MagickFalse ) {
00547           coeff = (double *) RelinquishMagickMemory(coeff);
00548           (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00549                       "InvalidArgument","%s : '%s'","Affine",
00550                       "Unsolvable Matrix");
00551           return((double *) NULL);
00552         }
00553       }
00554       return(coeff);
00555     }
00556     case AffineProjectionDistortion:
00557     {
00558       /*
00559         Arguments: Affine Matrix (forward mapping)
00560         Arguments  sx, rx, ry, sy, tx, ty
00561         Where      u = sx*x + ry*y + tx
00562                    v = rx*x + sy*y + ty
00563 
00564         Returns coefficients (in there inverse form) ordered as...
00565              sx ry tx  rx sy ty
00566 
00567         AffineProjection Distortion Notes...
00568            + Will only work with a 2 number_values for Image Distortion
00569            + Can not be used for generating a sparse gradient (interpolation)
00570       */
00571       double inverse[8];
00572       if (number_arguments != 6) {
00573         coeff = (double *) RelinquishMagickMemory(coeff);
00574         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00575                      "InvalidArgument","%s : '%s'","AffineProjection",
00576                      "Needs 6 coeff values");
00577         return((double *) NULL);
00578       }
00579       /* FUTURE: trap test for sx*sy-rx*ry == 0 (determinate = 0, no inverse) */
00580       for(i=0; i<6UL; i++ )
00581         inverse[i] = arguments[i];
00582       AffineArgsToCoefficients(inverse); /* map into coefficents */
00583       InvertAffineCoefficients(inverse, coeff); /* invert */
00584       *method = AffineDistortion;
00585 
00586       return(coeff);
00587     }
00588     case ScaleRotateTranslateDistortion:
00589     {
00590       /* Scale, Rotate and Translate Distortion
00591          An alturnative Affine Distortion
00592          Argument options, by number of arguments given:
00593            7: x,y, sx,sy, a, nx,ny
00594            6: x,y,   s,   a, nx,ny
00595            5: x,y, sx,sy, a
00596            4: x,y,   s,   a
00597            3: x,y,        a
00598            2:        s,   a
00599            1:             a
00600          Where actions are (in order of application)
00601             x,y     'center' of transforms     (default = image center)
00602             sx,sy   scale image by this amount (default = 1)
00603             a       angle of rotation          (argument required)
00604             nx,ny   move 'center' here         (default = x,y or no movement)
00605          And convert to affine mapping coefficients
00606 
00607          ScaleRotateTranslate Distortion Notes...
00608            + Does not use a set of CPs in any normal way
00609            + Will only work with a 2 number_valuesal Image Distortion
00610            + Can not be used for generating a sparse gradient (interpolation)
00611       */
00612       double
00613         cosine, sine,
00614         x,y,sx,sy,a,nx,ny;
00615 
00616       /* set default center, and default scale */
00617       x = nx = (double)(image->columns)/2.0 + (double)image->page.x;
00618       y = ny = (double)(image->rows)/2.0    + (double)image->page.y;
00619       sx = sy = 1.0;
00620       switch ( number_arguments ) {
00621       case 0:
00622         coeff = (double *) RelinquishMagickMemory(coeff);
00623         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00624                      "InvalidArgument","%s : '%s'", "ScaleTranslateRotate",
00625                      "Needs at least 1 argument");
00626         return((double *) NULL);
00627       case 1:
00628         a = arguments[0];
00629         break;
00630       case 2:
00631         sx = sy = arguments[0];
00632         a = arguments[1];
00633         break;
00634       default:
00635         x = nx = arguments[0];
00636         y = ny = arguments[1];
00637         switch ( number_arguments ) {
00638         case 3:
00639           a = arguments[2];
00640           break;
00641         case 4:
00642           sx = sy = arguments[2];
00643           a = arguments[3];
00644           break;
00645         case 5:
00646           sx = arguments[2];
00647           sy = arguments[3];
00648           a = arguments[4];
00649           break;
00650         case 6:
00651           sx = sy = arguments[2];
00652           a = arguments[3];
00653           nx = arguments[4];
00654           ny = arguments[5];
00655           break;
00656         case 7:
00657           sx = arguments[2];
00658           sy = arguments[3];
00659           a = arguments[4];
00660           nx = arguments[5];
00661           ny = arguments[6];
00662           break;
00663         default:
00664           coeff = (double *) RelinquishMagickMemory(coeff);
00665           (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00666                      "InvalidArgument","%s : '%s'", "ScaleTranslateRotate",
00667                      "Too Many Arguments (7 or less)");
00668           return((double *) NULL);
00669         }
00670         break;
00671       }
00672       /* Trap if sx or sy == 0 -- image is scaled out of existance! */
00673       if ( fabs(sx) < MagickEpsilon || fabs(sy) < MagickEpsilon ) {
00674         coeff = (double *) RelinquishMagickMemory(coeff);
00675         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00676                      "InvalidArgument","%s : '%s'", "ScaleTranslateRotate",
00677                      "Zero Scale Given");
00678         return((double *) NULL);
00679       }
00680       /* Save the given arguments as an affine distortion */
00681       a=DegreesToRadians(a); cosine=cos(a); sine=sin(a);
00682 
00683       *method = AffineDistortion;
00684       coeff[0]=cosine/sx;
00685       coeff[1]=sine/sx;
00686       coeff[2]=x-nx*coeff[0]-ny*coeff[1];
00687       coeff[3]=(-sine)/sy;
00688       coeff[4]=cosine/sy;
00689       coeff[5]=y-nx*coeff[3]-ny*coeff[4];
00690       return(coeff);
00691     }
00692     case PerspectiveDistortion:
00693     { /*
00694          Perspective Distortion (a ratio of affine distortions)
00695 
00696                 p(x,y)    c0*x + c1*y + c2
00697             u = ------ = ------------------
00698                 r(x,y)    c6*x + c7*y + 1
00699 
00700                 q(x,y)    c3*x + c4*y + c5
00701             v = ------ = ------------------
00702                 r(x,y)    c6*x + c7*y + 1
00703 
00704            c8 = Sign of 'r', or the denominator affine, for the actual image.
00705                 This determines what part of the distorted image is 'ground'
00706                 side of the horizon, the other part is 'sky' or invalid.
00707                 Valid values are  +1.0  or  -1.0  only.
00708 
00709          Input Arguments are sets of control points...
00710          For Distort Images    u,v, x,y  ...
00711          For Sparse Gradients  x,y, r,g,b  ...
00712 
00713          Perspective Distortion Notes...
00714            + Can be thought of as ratio of  3 affine transformations
00715            + Not separatable: r() or c6 and c7 are used by both equations
00716            + All 8 coefficients must be determined simultaniously
00717            + Will only work with a 2 number_valuesal Image Distortion
00718            + Can not be used for generating a sparse gradient (interpolation)
00719            + It is not linear, but is simple to generate an inverse
00720            + All lines within an image remain lines.
00721            + but distances between points may vary.
00722       */
00723       double
00724         **matrix,
00725         *vectors[1],
00726         terms[8];
00727 
00728       unsigned long
00729         cp_u = cp_values,
00730         cp_v = cp_values+1;
00731 
00732       MagickBooleanType
00733         status;
00734 
00735       if ( number_arguments%cp_size != 0 ||
00736            number_arguments < cp_size*4 ) {
00737         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00738                "InvalidArgument", "%s : 'require at least %ld CPs'",
00739                "Perspective", 4L);
00740         coeff=(double *) RelinquishMagickMemory(coeff);
00741         return((double *) NULL);
00742       }
00743       /* fake 1x8 vectors matrix directly using the coefficients array */
00744       vectors[0] = &(coeff[0]);
00745       /* 8x8 least-squares matrix (zeroed) */
00746       matrix = AcquireMagickMatrix(8UL,8UL);
00747       if (matrix == (double **) NULL) {
00748         (void) ThrowMagickException(exception,GetMagickModule(),
00749                   ResourceLimitError,"MemoryAllocationFailed",
00750                   "%s", "DistortCoefficients");
00751         return((double *) NULL);
00752       }
00753       /* Add control points for least squares solving */
00754       for (i=0; i < number_arguments; i+=4) {
00755         terms[0]=arguments[i+cp_x];            /*   c0*x   */
00756         terms[1]=arguments[i+cp_y];            /*   c1*y   */
00757         terms[2]=1.0;                          /*   c2*1   */
00758         terms[3]=0.0;
00759         terms[4]=0.0;
00760         terms[5]=0.0;
00761         terms[6]=-terms[0]*arguments[i+cp_u];  /* 1/(c6*x) */
00762         terms[7]=-terms[1]*arguments[i+cp_u];  /* 1/(c7*y) */
00763         LeastSquaresAddTerms(matrix,vectors,terms,&(arguments[i+cp_u]),
00764             8UL,1UL);
00765 
00766         terms[0]=0.0;
00767         terms[1]=0.0;
00768         terms[2]=0.0;
00769         terms[3]=arguments[i+cp_x];           /*   c3*x   */
00770         terms[4]=arguments[i+cp_y];           /*   c4*y   */
00771         terms[5]=1.0;                         /*   c5*1   */
00772         terms[6]=-terms[3]*arguments[i+cp_v]; /* 1/(c6*x) */
00773         terms[7]=-terms[4]*arguments[i+cp_v]; /* 1/(c7*y) */
00774         LeastSquaresAddTerms(matrix,vectors,terms,&(arguments[i+cp_v]),
00775             8UL,1UL);
00776       }
00777       /* Solve for LeastSquares Coefficients */
00778       status=GaussJordanElimination(matrix,vectors,8UL,1UL);
00779       matrix = RelinquishMagickMatrix(matrix, 8UL);
00780       if ( status == MagickFalse ) {
00781         coeff = (double *) RelinquishMagickMemory(coeff);
00782         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00783                     "InvalidArgument","%s : '%s'","Perspective",
00784                     "Unsolvable Matrix");
00785         return((double *) NULL);
00786       }
00787       /*
00788         Calculate 9'th coefficient! The ground-sky determination.
00789         What is sign of the 'ground' in r() denominator affine function?
00790         Just use any valid image coordinate (first control point) in
00791         destination for determination of what part of view is 'ground'.
00792       */
00793       coeff[8] = coeff[6]*arguments[cp_x]
00794                       + coeff[7]*arguments[cp_y] + 1.0;
00795       coeff[8] = (coeff[8] < 0.0) ? -1.0 : +1.0;
00796 
00797       return(coeff);
00798     }
00799     case PerspectiveProjectionDistortion:
00800     {
00801       /*
00802         Arguments: Perspective Coefficents (forward mapping)
00803       */
00804       if (number_arguments != 8) {
00805         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00806                      "InvalidArgument","%s : '%s'","PerspectiveProjection",
00807                      "Needs 8 coefficient values");
00808         return((double *) NULL);
00809       }
00810       /* FUTURE: trap test  c0*c4-c3*c1 == 0  (determinate = 0, no inverse) */
00811       InvertPerspectiveCoefficients(arguments, coeff);
00812       /*
00813         Calculate 9'th coefficient! The ground-sky determination.
00814         What is sign of the 'ground' in r() denominator affine function?
00815         Just use any valid image cocodinate in destination for determination.
00816         For a forward mapped perspective the images 0,0 coord will map to
00817         c2,c5 in the distorted image, so set the sign of denominator of that.
00818       */
00819       coeff[8] = coeff[6]*arguments[2]
00820                            + coeff[7]*arguments[5] + 1.0;
00821       coeff[8] = (coeff[8] < 0.0) ? -1.0 : +1.0;
00822       *method = PerspectiveDistortion;
00823 
00824       return(coeff);
00825     }
00826     case BilinearForwardDistortion:
00827     case BilinearReverseDistortion:
00828     {
00829       /* Bilinear Distortion (Forward mapping)
00830             v = c0*x + c1*y + c2*x*y + c3;
00831          for each 'value' given
00832 
00833          This is actually a simple polynomial Distortion!  The difference
00834          however is when we need to reverse the above equation to generate a
00835          BilinearForwardDistortion (see below).
00836 
00837          Input Arguments are sets of control points...
00838          For Distort Images    u,v, x,y  ...
00839          For Sparse Gradients  x,y, r,g,b  ...
00840 
00841       */
00842       double
00843         **matrix,
00844         **vectors,
00845         terms[4];
00846 
00847       MagickBooleanType
00848         status;
00849 
00850       /* check the number of arguments */
00851       if ( number_arguments%cp_size != 0 ||
00852            number_arguments < cp_size*4 ) {
00853         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00854                "InvalidArgument", "%s : 'require at least %ld CPs'",
00855                *method == BilinearForwardDistortion ? "BilinearForward" :
00856                "BilinearReverse", 4L);
00857         coeff=(double *) RelinquishMagickMemory(coeff);
00858         return((double *) NULL);
00859       }
00860       /* create matrix, and a fake vectors matrix */
00861       matrix = AcquireMagickMatrix(4UL,4UL);
00862       vectors = (double **) AcquireQuantumMemory(number_values,sizeof(*vectors));
00863       if (matrix == (double **) NULL || vectors == (double **) NULL)
00864       {
00865         matrix  = RelinquishMagickMatrix(matrix, 4UL);
00866         vectors = (double **) RelinquishMagickMemory(vectors);
00867         coeff   = (double *) RelinquishMagickMemory(coeff);
00868         (void) ThrowMagickException(exception,GetMagickModule(),
00869                 ResourceLimitError,"MemoryAllocationFailed",
00870                 "%s", "DistortCoefficients");
00871         return((double *) NULL);
00872       }
00873       /* fake a number_values x4 vectors matrix from coefficients array */
00874       for (i=0; i < number_values; i++)
00875         vectors[i] = &(coeff[i*4]);
00876       /* Add given control point pairs for least squares solving */
00877       for (i=0; i < number_arguments; i+=cp_size) {
00878         terms[0] = arguments[i+cp_x];   /*  x  */
00879         terms[1] = arguments[i+cp_y];   /*  y  */
00880         terms[2] = terms[0]*terms[1];   /* x*y */
00881         terms[3] = 1;                   /*  1  */
00882         LeastSquaresAddTerms(matrix,vectors,terms,
00883              &(arguments[i+cp_values]),4UL,number_values);
00884       }
00885       /* Solve for LeastSquares Coefficients */
00886       status=GaussJordanElimination(matrix,vectors,4UL,number_values);
00887       matrix  = RelinquishMagickMatrix(matrix, 4UL);
00888       vectors = (double **) RelinquishMagickMemory(vectors);
00889       if ( status == MagickFalse ) {
00890         coeff = (double *) RelinquishMagickMemory(coeff);
00891         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00892                      "InvalidArgument","%s : '%s'",
00893                      *method == BilinearForwardDistortion ?
00894                                 "BilinearForward" : "BilinearReverse",
00895                      "Unsolvable Matrix");
00896         return((double *) NULL);
00897       }
00898       if ( *method == BilinearForwardDistortion ) {
00899          /* Bilinear Forward Mapped Distortion
00900 
00901          The above least-squares solved for coefficents but in the forward
00902          direction, due to changes to indexing constants.
00903 
00904             i = c0*x + c1*y + c2*x*y + c3;
00905             j = c4*x + c5*y + c6*x*y + c7;
00906 
00907          where u,v are in the destination image, NOT the source.
00908 
00909          Reverse Pixel mapping however needs to use reverse of these
00910          functions.  It required a full page of algbra to work out the
00911          reversed mapping formula, but resolves down to the following...
00912 
00913             c8 = c0*c5-c1*c4;
00914             c9 = 2*(c2*c5-c1*c6);   // '2*a' in the quadratic formula
00915 
00916             i = i - c3;   j = j - c7;
00917             b = c6*i - c2*j + c8;   // So that   a*y^2 + b*y + c == 0
00918             c = c4*i -  c0*j;       // y = ( -b +- sqrt(bb - 4ac) ) / (2*a)
00919 
00920             r = b*b - c9*(c+c);
00921             if ( c9 != 0 )
00922               y = ( -b + sqrt(r) ) / c9;
00923             else
00924               y = -c/b;
00925 
00926             x = ( i - c1*y) / ( c1 - c2*y );
00927 
00928          NB: if 'r' is negative there is no solution!
00929          NB: the sign of the sqrt() should be negative if image becomes
00930              flipped or flopped, or crosses over itself.
00931          NB: techniqually coefficient c5 is not needed, anymore,
00932              but kept for completness.
00933 
00934          See Anthony Thyssen <A.Thyssen@griffith.edu.au>
00935          or  Fred Weinhaus <fmw@alink.net>  for more details.
00936 
00937          */
00938          coeff[8] = coeff[0]*coeff[5] - coeff[1]*coeff[4];
00939          coeff[9] = 2*(coeff[2]*coeff[5] - coeff[1]*coeff[6]);
00940       }
00941       return(coeff);
00942     }
00943 #if 0
00944     case QuadrilateralDistortion:
00945     {
00946       /* Map a Quadrilateral to a unit square using BilinearReverse
00947          Then map that unit square back to the final Quadrilateral
00948          using BilinearForward.
00949 
00950          Input Arguments are sets of control points...
00951          For Distort Images    u,v, x,y  ...
00952          For Sparse Gradients  x,y, r,g,b  ...
00953 
00954       */
00955       /* UNDER CONSTRUCTION */
00956       return(coeff);
00957     }
00958 #endif
00959 
00960     case PolynomialDistortion:
00961     {
00962       /* Polynomial Distortion
00963 
00964          First two coefficents are used to hole global polynomal information
00965            c0 = Order of the polynimial being created
00966            c1 = number_of_terms in one polynomial equation
00967 
00968          Rest of the coefficients map to the equations....
00969             v = c0 + c1*x + c2*y + c3*x*y + c4*x^2 + c5*y^2 + c6*x^3 + ...
00970          for each 'value' (number_values of them) given.
00971          As such total coefficients =  2 + number_terms * number_values
00972 
00973          Input Arguments are sets of control points...
00974          For Distort Images    order  [u,v, x,y] ...
00975          For Sparse Gradients  order  [x,y, r,g,b] ...
00976 
00977          Polynomial Distortion Notes...
00978            + UNDER DEVELOPMENT -- Do not expect this to remain as is.
00979            + Currently polynomial is a reversed mapped distortion.
00980            + Order 1.5 is fudged to map into a bilinear distortion.
00981              though it is not the same order as that distortion.
00982       */
00983       double
00984         **matrix,
00985         **vectors,
00986         *terms;
00987 
00988       unsigned long
00989         nterms;   /* number of polynomial terms per number_values */
00990 
00991       register long
00992         j;
00993 
00994       MagickBooleanType
00995         status;
00996 
00997       /* first two coefficients hold polynomial order information */
00998       coeff[0] = arguments[0];
00999       coeff[1] = (double) poly_number_terms(arguments[0]);
01000       nterms = (unsigned long) coeff[1];
01001 
01002       /* create matrix, a fake vectors matrix, and least sqs terms */
01003       matrix = AcquireMagickMatrix(nterms,nterms);
01004       vectors = (double **) AcquireQuantumMemory(number_values,sizeof(*vectors));
01005       terms = (double *) AcquireQuantumMemory(nterms, sizeof(*terms));
01006       if (matrix  == (double **) NULL ||
01007           vectors == (double **) NULL ||
01008           terms   == (double *) NULL )
01009       {
01010         matrix  = RelinquishMagickMatrix(matrix, nterms);
01011         vectors = (double **) RelinquishMagickMemory(vectors);
01012         terms   = (double *) RelinquishMagickMemory(terms);
01013         coeff   = (double *) RelinquishMagickMemory(coeff);
01014         (void) ThrowMagickException(exception,GetMagickModule(),
01015                 ResourceLimitError,"MemoryAllocationFailed",
01016                 "%s", "DistortCoefficients");
01017         return((double *) NULL);
01018       }
01019       /* fake a number_values x3 vectors matrix from coefficients array */
01020       for (i=0; i < number_values; i++)
01021         vectors[i] = &(coeff[2+i*nterms]);
01022       /* Add given control point pairs for least squares solving */
01023       for (i=1; i < number_arguments; i+=cp_size) { /* NB: start = 1 not 0 */
01024         for (j=0; j < (long) nterms; j++)
01025           terms[j] = poly_basis_fn(j,arguments[i+cp_x],arguments[i+cp_y]);
01026         LeastSquaresAddTerms(matrix,vectors,terms,
01027              &(arguments[i+cp_values]),nterms,number_values);
01028       }
01029       terms = (double *) RelinquishMagickMemory(terms);
01030       /* Solve for LeastSquares Coefficients */
01031       status=GaussJordanElimination(matrix,vectors,nterms,number_values);
01032       matrix  = RelinquishMagickMatrix(matrix, nterms);
01033       vectors = (double **) RelinquishMagickMemory(vectors);
01034       if ( status == MagickFalse ) {
01035         coeff = (double *) RelinquishMagickMemory(coeff);
01036         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01037                      "InvalidArgument","%s : '%s'","Polynomial",
01038                      "Unsolvable Matrix");
01039         return((double *) NULL);
01040       }
01041       return(coeff);
01042     }
01043     case ArcDistortion:
01044     {
01045       /* Arc Distortion
01046          Args: arc_width  rotate  top_edge_radius  bottom_edge_radius
01047          All but first argument are optional
01048             arc_width      The angle over which to arc the image side-to-side
01049             rotate         Angle to rotate image from vertical center
01050             top_radius     Set top edge of source image at this radius
01051             bottom_radius  Set bootom edge to this radius (radial scaling)
01052 
01053          By default, if the radii arguments are nor provided the image radius
01054          is calculated so the horizontal center-line is fits the given arc
01055          without scaling.
01056 
01057          The output image size is ALWAYS adjusted to contain the whole image,
01058          and an offset is given to position image relative to the 0,0 point of
01059          the origin, allowing users to use relative positioning onto larger
01060          background (via -flatten).
01061 
01062          The arguments are converted to these coefficients
01063             c0: angle for center of source image
01064             c1: angle scale for mapping to source image
01065             c2: radius for top of source image
01066             c3: radius scale for mapping source image
01067             c4: centerline of arc within source image
01068 
01069          Note the coefficients use a center angle, so asymptotic join is
01070          furthest from both sides of the source image. This also means that
01071          for arc angles greater than 360 the sides of the image will be
01072          trimmed equally.
01073 
01074          Arc Distortion Notes...
01075            + Does not use a set of CPs
01076            + Will only work with Image Distortion
01077            + Can not be used for generating a sparse gradient (interpolation)
01078       */
01079       if ( number_arguments >= 1 && arguments[0] < MagickEpsilon ) {
01080         coeff = (double *) RelinquishMagickMemory(coeff);
01081         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01082                      "InvalidArgument","%s : '%s'", "Arc",
01083                      "Arc Angle Too Small");
01084         return((double *) NULL);
01085       }
01086       if ( number_arguments >= 3 && arguments[2] < MagickEpsilon ) {
01087         coeff = (double *) RelinquishMagickMemory(coeff);
01088         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01089                      "InvalidArgument","%s : '%s'", "Arc",
01090                      "Outer Radius Too Small");
01091         return((double *) NULL);
01092       }
01093       coeff[0] = -MagickPI2;   /* -90, place at top! */
01094       if ( number_arguments >= 1 )
01095         coeff[1] = DegreesToRadians(arguments[0]);
01096       else
01097         coeff[1] = MagickPI2;   /* zero arguments - center is at top */
01098       if ( number_arguments >= 2 )
01099         coeff[0] += DegreesToRadians(arguments[1]);
01100       coeff[0] /= Magick2PI;  /* normalize radians */
01101       coeff[0] -= MagickRound(coeff[0]);
01102       coeff[0] *= Magick2PI;  /* de-normalize back to radians */
01103       coeff[3] = (double)image->rows-1;
01104       coeff[2] = (double)image->columns/coeff[1] + coeff[3]/2.0;
01105       if ( number_arguments >= 3 ) {
01106         if ( number_arguments >= 4 )
01107           coeff[3] = arguments[2] - arguments[3];
01108         else
01109           coeff[3] *= arguments[2]/coeff[2];
01110         coeff[2] = arguments[2];
01111       }
01112       coeff[4] = ((double)image->columns-1.0)/2.0;
01113 
01114       return(coeff);
01115     }
01116     case PolarDistortion:
01117     case DePolarDistortion:
01118     {
01119       /* (De)Polar Distortion   (same set of arguments)
01120          Args:  Rmax, Rmin,  Xcenter,Ycenter,  Afrom,Ato
01121          DePolar can also have the extra arguments of Width, Height
01122 
01123          Coefficients 0 to 5 is the sanatized version first 6 input args
01124          Coefficient 6  is the angle to coord ratio  and visa-versa
01125          Coefficient 7  is the radius to coord ratio and visa-versa
01126 
01127          WARNING: It is posible for  Radius max<min  and/or  Angle from>to
01128       */
01129       if ( number_arguments == 3
01130           || ( number_arguments > 6 && *method == PolarDistortion )
01131           || number_arguments > 8 ) {
01132         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01133                "InvalidArgument", "%s : number of arguments",
01134                *method == PolarDistortion ? "Polar" : "DePolar");
01135         coeff=(double *) RelinquishMagickMemory(coeff);
01136         return((double *) NULL);
01137       }
01138       /* Rmax -  if 0 calculate appropriate value */
01139       if ( number_arguments >= 1 )
01140         coeff[0] = arguments[0];
01141       else
01142         coeff[0] = 0.0;
01143       /* Rmin  - usally 0 */
01144       coeff[1] = number_arguments >= 2 ? arguments[1] : 0.0;
01145       /* Center X,Y */
01146       if ( number_arguments >= 4 ) {
01147         coeff[2] = arguments[2];
01148         coeff[3] = arguments[3];
01149       }
01150       else { /* center of actual image */
01151         coeff[2] = (double)(image->columns)/2.0+image->page.x;
01152         coeff[3] = (double)(image->rows)/2.0+image->page.y;
01153       }
01154       /* Angle from,to - about polar center 0 is downward */
01155       coeff[4] = -MagickPI;
01156       if ( number_arguments >= 5 )
01157         coeff[4] = DegreesToRadians(arguments[4]);
01158       coeff[5] = coeff[4];
01159       if ( number_arguments >= 6 )
01160         coeff[5] = DegreesToRadians(arguments[5]);
01161       if ( fabs(coeff[4]-coeff[5]) < MagickEpsilon )
01162         coeff[5] += Magick2PI; /* same angle is a full circle */
01163       /* if radius 0 or negative,  its a special value... */
01164       if ( coeff[0] < MagickEpsilon ) {
01165         /* Use closest edge  if radius == 0 */
01166         if ( fabs(coeff[0]) < MagickEpsilon ) {
01167           coeff[0]=MagickMin(fabs(coeff[2]-image->page.x),
01168                              fabs(coeff[3]-image->page.y));
01169           coeff[0]=MagickMin(coeff[0],
01170                        fabs(coeff[2]-image->page.x-image->columns));
01171           coeff[0]=MagickMin(coeff[0],
01172                        fabs(coeff[3]-image->page.y-image->rows));
01173         }
01174         /* furthest diagonal if radius == -1 */
01175         if ( fabs(-1.0-coeff[0]) < MagickEpsilon ) {
01176           double rx,ry;
01177           rx = coeff[2]-image->page.x;
01178           ry = coeff[3]-image->page.y;
01179           coeff[0] = rx*rx+ry*ry;
01180           ry = coeff[3]-image->page.y-image->rows;
01181           coeff[0] = MagickMax(coeff[0],rx*rx+ry*ry);
01182           rx = coeff[2]-image->page.x-image->columns;
01183           coeff[0] = MagickMax(coeff[0],rx*rx+ry*ry);
01184           ry = coeff[3]-image->page.y;
01185           coeff[0] = MagickMax(coeff[0],rx*rx+ry*ry);
01186           coeff[0] = sqrt(coeff[0]);
01187         }
01188       }
01189       /* IF Rmax <= 0 or Rmin < 0 OR Rmax < Rmin, THEN error */
01190       if ( coeff[0] < MagickEpsilon || coeff[1] < -MagickEpsilon
01191            || (coeff[0]-coeff[1]) < MagickEpsilon ) {
01192         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01193                "InvalidArgument", "%s : Invalid Radius",
01194                *method == PolarDistortion ? "Polar" : "DePolar");
01195         coeff=(double *) RelinquishMagickMemory(coeff);
01196         return((double *) NULL);
01197       }
01198       /* converstion ratios */
01199       if ( *method == PolarDistortion ) {
01200         coeff[6]=(double) image->columns/(coeff[5]-coeff[4]);
01201         coeff[7]=(double) image->rows/(coeff[0]-coeff[1]);
01202       }
01203       else { /* *method == DePolarDistortion */
01204         coeff[6]=(coeff[5]-coeff[4])/image->columns;
01205         coeff[7]=(coeff[0]-coeff[1])/image->rows;
01206       }
01207       return(coeff);
01208     }
01209     case BarrelDistortion:
01210     case BarrelInverseDistortion:
01211     {
01212       /* Barrel Distortion
01213            Rs=(A*Rd^3 + B*Rd^2 + C*Rd + D)*Rd
01214          BarrelInv Distortion
01215            Rs=Rd/(A*Rd^3 + B*Rd^2 + C*Rd + D)
01216 
01217         Where Rd is the normalized radius from corner to middle of image
01218         Input Arguments are one of the following forms...
01219              A,B,C
01220              A,B,C,D
01221              A,B,C    X,Y
01222              A,B,C,D  X,Y
01223              Ax,Bx,Cx,Dx  Ay,By,Cy,Dy
01224              Ax,Bx,Cx,Dx  Ay,By,Cy,Dy   X,Y
01225 
01226         Returns 10 coefficent values, which are de-normalized (pixel scale)
01227           Ax, Bx, Cx, Dx,   Ay, By, Cy, Dy,    Xc, Yc
01228       */
01229       /* Radius de-normalization scaling factor */
01230       double
01231         rscale = 2.0/MagickMin((double) image->columns,(double) image->rows);
01232 
01233       if ( number_arguments != 4 && number_arguments != 6 &&
01234            number_arguments != 8 && number_arguments != 10 ) {
01235         coeff=(double *) RelinquishMagickMemory(coeff);
01236         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01237                "InvalidArgument", "%s : '%s'", "Barrel(Inv)",
01238                "number of arguments" );
01239         return((double *) NULL);
01240       }
01241       /* A,B,C,D coefficients */
01242       coeff[0] = arguments[0];
01243       coeff[1] = arguments[1];
01244       coeff[2] = arguments[2];
01245       if ( number_arguments == 3 || number_arguments == 5 )
01246         coeff[3] = 1 - arguments[0] - arguments[1] - arguments[2];
01247       else
01248          coeff[3] = arguments[3];
01249       /* de-normalize the X coefficients */
01250       coeff[0] *= pow(rscale,3.0);
01251       coeff[1] *= rscale*rscale;
01252       coeff[2] *= rscale;
01253       /* Y coefficients: as given OR as X coefficients */
01254       if ( number_arguments >= 8 ) {
01255         coeff[4] = arguments[4] * pow(rscale,3.0);
01256         coeff[5] = arguments[5] * rscale*rscale;
01257         coeff[6] = arguments[6] * rscale;
01258         coeff[7] = arguments[7];
01259       }
01260       else {
01261         coeff[4] = coeff[0];
01262         coeff[5] = coeff[1];
01263         coeff[6] = coeff[2];
01264         coeff[7] = coeff[3];
01265       }
01266       /* X,Y Center of Distortion */
01267       coeff[8] = ((double)image->columns-1)/2.0 + image->page.x;
01268       coeff[9] = ((double)image->rows-1)/2.0    + image->page.y;
01269       if ( number_arguments == 5 )  {
01270         coeff[8] = arguments[3];
01271         coeff[9] = arguments[4];
01272       }
01273       if ( number_arguments == 6 ) {
01274         coeff[8] = arguments[4];
01275         coeff[9] = arguments[5];
01276       }
01277       if ( number_arguments == 10 ) {
01278         coeff[8] = arguments[8];
01279         coeff[9] = arguments[9];
01280       }
01281       return(coeff);
01282     }
01283     case ShepardsDistortion:
01284     case VoronoiColorInterpolate:
01285     {
01286       /* Shepards Distortion  input arguments are the coefficents!
01287          Just check the number of arguments is valid!
01288          Args:  u1,v1, x1,y1, ...
01289           OR :  u1,v1, r1,g1,c1, ...
01290       */
01291       if ( number_arguments%cp_size != 0 ||
01292            number_arguments < cp_size ) {
01293         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01294                "InvalidArgument", "%s : 'require at least %ld CPs'",
01295                "Shepards", 1UL);
01296         coeff=(double *) RelinquishMagickMemory(coeff);
01297         return((double *) NULL);
01298       }
01299       return(coeff);
01300     }
01301     default:
01302       break;
01303   }
01304   /* you should never reach this point */
01305   assert(! "No Method Handler"); /* just fail assertion */
01306   return((double *) NULL);
01307 }
01308 
01309 /*
01310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01311 %                                                                             %
01312 %                                                                             %
01313 %                                                                             %
01314 %   D i s t o r t I m a g e                                                   %
01315 %                                                                             %
01316 %                                                                             %
01317 %                                                                             %
01318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01319 %
01320 %  DistortImage() distorts an image using various distortion methods, by
01321 %  mapping color lookups of the source image to a new destination image
01322 %  usally of the same size as the source image, unless 'bestfit' is set to
01323 %  true.
01324 %
01325 %  If 'bestfit' is enabled, and distortion allows it, the destination image is
01326 %  adjusted to ensure the whole source 'image' will just fit within the final
01327 %  destination image, which will be sized and offset accordingly.  Also in
01328 %  many cases the virtual offset of the source image will be taken into
01329 %  account in the mapping.
01330 %
01331 %  If the '-verbose' control option has been set print to standard error the
01332 %  equicelent '-fx' formula with coefficients for the function, if practical.
01333 %
01334 %  The format of the DistortImage() method is:
01335 %
01336 %      Image *DistortImage(const Image *image,const DistortImageMethod method,
01337 %        const unsigned long number_arguments,const double *arguments,
01338 %        MagickBooleanType bestfit, ExceptionInfo *exception)
01339 %
01340 %  A description of each parameter follows:
01341 %
01342 %    o image: the image to be distorted.
01343 %
01344 %    o method: the method of image distortion.
01345 %
01346 %        ArcDistortion always ignores source image offset, and always
01347 %        'bestfit' the destination image with the top left corner offset
01348 %        relative to the polar mapping center.
01349 %
01350 %        Affine, Perspective, and Bilinear, do least squares fitting of the
01351 %        distrotion when more than the minimum number of control point pairs
01352 %        are provided.
01353 %
01354 %        Perspective, and Bilinear, fall back to a Affine distortion when less
01355 %        than 4 control point pairs are provided.  While Affine distortions
01356 %        let you use any number of control point pairs, that is Zero pairs is
01357 %        a No-Op (viewport only) distortion, one pair is a translation and
01358 %        two pairs of control points do a scale-rotate-translate, without any
01359 %        shearing.
01360 %
01361 %    o number_arguments: the number of arguments given.
01362 %
01363 %    o arguments: an array of floating point arguments for this method.
01364 %
01365 %    o bestfit: Attempt to 'bestfit' the size of the resulting image.
01366 %        This also forces the resulting image to be a 'layered' virtual
01367 %        canvas image.  Can be overridden using 'distort:viewport' setting.
01368 %
01369 %    o exception: return any errors or warnings in this structure
01370 %
01371 %  Extra Controls from Image meta-data (artifacts)...
01372 %
01373 %    o "verbose"
01374 %        Output to stderr alternatives, internal coefficents, and FX
01375 %        equivelents for the distortion operation (if feasible).
01376 %        This forms an extra check of the distortion method, and allows users
01377 %        access to the internal constants IM calculates for the distortion.
01378 %
01379 %    o "distort:viewport"
01380 %        Directly set the output image canvas area and offest to use for the
01381 %        resulting image, rather than use the original images canvas, or a
01382 %        calculated 'bestfit' canvas.
01383 %
01384 %    o "distort:scale"
01385 %        Scale the size of the output canvas by this amount to provide a
01386 %        method of Zooming, and for super-sampling the results.
01387 %
01388 %  Other settings that can effect results include
01389 %
01390 %    o 'interpolate' For source image lookups (scale enlargements)
01391 %
01392 %    o 'filter'      Set filter to use for area-resampling (scale shrinking).
01393 %                    Set to 'point' to turn off and use 'interpolate' lookup
01394 %                    instead
01395 %
01396 */
01397 MagickExport Image *DistortImage(const Image *image,DistortImageMethod method,
01398   const unsigned long number_arguments,const double *arguments,
01399   MagickBooleanType bestfit,ExceptionInfo *exception)
01400 {
01401 #define DistortImageTag  "Distort/Image"
01402 
01403   double
01404     *coeff,
01405     output_scaling;
01406 
01407   Image
01408     *distort_image;
01409 
01410   RectangleInfo
01411     geometry;  /* geometry of the distorted space viewport */
01412 
01413   MagickBooleanType
01414     viewport_given;
01415 
01416   assert(image != (Image *) NULL);
01417   assert(image->signature == MagickSignature);
01418   if (image->debug != MagickFalse)
01419     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01420   assert(exception != (ExceptionInfo *) NULL);
01421   assert(exception->signature == MagickSignature);
01422 
01423   /*
01424     Convert input arguments (usally as control points for reverse mapping)
01425     into mapping coefficients to apply the distortion.
01426 
01427     Note that some distortions are mapped to other distortions,
01428     and as such do not require specific code after this point.
01429   */
01430   coeff = GenerateCoefficients(image, &method, number_arguments,
01431       arguments, 0, exception);
01432   if ( coeff == (double *) NULL )
01433     return((Image *) NULL);
01434 
01435   /*
01436     Determine the size and offset for a 'bestfit' destination.
01437     Usally the four corners of the source image is enough.
01438   */
01439 
01440   /* default output image bounds, when no 'bestfit' is requested */
01441   geometry.width=image->columns;
01442   geometry.height=image->rows;
01443   geometry.x=0;
01444   geometry.y=0;
01445 
01446   if ( method == ArcDistortion ) {
01447     /* always use the 'best fit' viewport */
01448     bestfit = MagickTrue;
01449   }
01450 
01451   /* Work out the 'best fit', (required for ArcDistortion) */
01452   if ( bestfit ) {
01453     PointInfo
01454       s,d,min,max;
01455 
01456     s.x=s.y=min.x=max.x=min.y=max.y=0.0;   /* keep compiler happy */
01457 
01458 /* defines to figure out the bounds of the distorted image */
01459 #define InitalBounds(p) \
01460 { \
01461   /* printf("%lg,%lg -> %lg,%lg\n", s.x,s.y, d.x,d.y); */ \
01462   min.x = max.x = p.x; \
01463   min.y = max.y = p.y; \
01464 }
01465 #define ExpandBounds(p) \
01466 { \
01467   /* printf("%lg,%lg -> %lg,%lg\n", s.x,s.y, d.x,d.y); */ \
01468   min.x = MagickMin(min.x,p.x); \
01469   max.x = MagickMax(max.x,p.x); \
01470   min.y = MagickMin(min.y,p.y); \
01471   max.y = MagickMax(max.y,p.y); \
01472 }
01473 
01474     switch (method)
01475     {
01476       case AffineDistortion:
01477       { double inverse[6];
01478         InvertAffineCoefficients(coeff, inverse);
01479         s.x = (double) image->page.x;
01480         s.y = (double) image->page.y;
01481         d.x = inverse[0]*s.x+inverse[1]*s.y+inverse[2];
01482         d.y = inverse[3]*s.x+inverse[4]*s.y+inverse[5];
01483         InitalBounds(d);
01484         s.x = (double) image->page.x+image->columns;
01485         s.y = (double) image->page.y;
01486         d.x = inverse[0]*s.x+inverse[1]*s.y+inverse[2];
01487         d.y = inverse[3]*s.x+inverse[4]*s.y+inverse[5];
01488         ExpandBounds(d);
01489         s.x = (double) image->page.x;
01490         s.y = (double) image->page.y+image->rows;
01491         d.x = inverse[0]*s.x+inverse[1]*s.y+inverse[2];
01492         d.y = inverse[3]*s.x+inverse[4]*s.y+inverse[5];
01493         ExpandBounds(d);
01494         s.x = (double) image->page.x+image->columns;
01495         s.y = (double) image->page.y+image->rows;
01496         d.x = inverse[0]*s.x+inverse[1]*s.y+inverse[2];
01497         d.y = inverse[3]*s.x+inverse[4]*s.y+inverse[5];
01498         ExpandBounds(d);
01499         break;
01500       }
01501       case PerspectiveDistortion:
01502       { double inverse[8], scale;
01503         InvertPerspectiveCoefficients(coeff, inverse);
01504         s.x = (double) image->page.x;
01505         s.y = (double) image->page.y;
01506         scale=inverse[6]*s.x+inverse[7]*s.y+1.0;
01507         scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
01508         d.x = scale*(inverse[0]*s.x+inverse[1]*s.y+inverse[2]);
01509         d.y = scale*(inverse[3]*s.x+inverse[4]*s.y+inverse[5]);
01510         InitalBounds(d);
01511         s.x = (double) image->page.x+image->columns;
01512         s.y = (double) image->page.y;
01513         scale=inverse[6]*s.x+inverse[7]*s.y+1.0;
01514         scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
01515         d.x = scale*(inverse[0]*s.x+inverse[1]*s.y+inverse[2]);
01516         d.y = scale*(inverse[3]*s.x+inverse[4]*s.y+inverse[5]);
01517         ExpandBounds(d);
01518         s.x = (double) image->page.x;
01519         s.y = (double) image->page.y+image->rows;
01520         scale=inverse[6]*s.x+inverse[7]*s.y+1.0;
01521         scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
01522         d.x = scale*(inverse[0]*s.x+inverse[1]*s.y+inverse[2]);
01523         d.y = scale*(inverse[3]*s.x+inverse[4]*s.y+inverse[5]);
01524         ExpandBounds(d);
01525         s.x = (double) image->page.x+image->columns;
01526         s.y = (double) image->page.y+image->rows;
01527         scale=inverse[6]*s.x+inverse[7]*s.y+1.0;
01528         scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
01529         d.x = scale*(inverse[0]*s.x+inverse[1]*s.y+inverse[2]);
01530         d.y = scale*(inverse[3]*s.x+inverse[4]*s.y+inverse[5]);
01531         ExpandBounds(d);
01532         break;
01533       }
01534       case ArcDistortion:
01535       { double a, ca, sa;
01536         /* Forward Map Corners */
01537         a = coeff[0]-coeff[1]/2; ca = cos(a); sa = sin(a);
01538         d.x = coeff[2]*ca;
01539         d.y = coeff[2]*sa;
01540         InitalBounds(d);
01541         d.x = (coeff[2]-coeff[3])*ca;
01542         d.y = (coeff[2]-coeff[3])*sa;
01543         ExpandBounds(d);
01544         a = coeff[0]+coeff[1]/2; ca = cos(a); sa = sin(a);
01545         d.x = coeff[2]*ca;
01546         d.y = coeff[2]*sa;
01547         ExpandBounds(d);
01548         d.x = (coeff[2]-coeff[3])*ca;
01549         d.y = (coeff[2]-coeff[3])*sa;
01550         ExpandBounds(d);
01551         /* Orthogonal points along top of arc */
01552         for( a=ceil((coeff[0]-coeff[1]/2.0)/MagickPI2)*MagickPI2;
01553                a<(coeff[0]+coeff[1]/2.0); a+=MagickPI2 ) {
01554           ca = cos(a); sa = sin(a);
01555           d.x = coeff[2]*ca;
01556           d.y = coeff[2]*sa;
01557           ExpandBounds(d);
01558         }
01559         /*
01560           Convert the angle_to_width and radius_to_height
01561           to appropriate scaling factors, to allow faster processing
01562           in the mapping function.
01563         */
01564         coeff[1] = Magick2PI*image->columns/coeff[1];
01565         coeff[3] = (double)image->rows/coeff[3];
01566         break;
01567       }
01568       case PolarDistortion:
01569       {
01570         if (number_arguments < 2)
01571           coeff[2] = coeff[3] = 0.0;
01572         min.x = coeff[2]-coeff[0];
01573         max.x = coeff[2]+coeff[0];
01574         min.y = coeff[3]-coeff[0];
01575         max.y = coeff[3]+coeff[0];
01576         /* should be about 1.0 if Rmin = 0 */
01577         coeff[7]=(double) geometry.height/(coeff[0]-coeff[1]);
01578         break;
01579       }
01580       case DePolarDistortion:
01581       {
01582         /* direct calculation as it needs to tile correctly
01583          * for reversibility in a DePolar-Polar cycle */
01584         geometry.x = geometry.y = 0;
01585         geometry.height = (unsigned long) ceil(coeff[0]-coeff[1]);
01586         geometry.width = (unsigned long)
01587                   ceil((coeff[0]-coeff[1])*(coeff[5]-coeff[4])*0.5);
01588         break;
01589       }
01590       case ShepardsDistortion:
01591       case BilinearForwardDistortion:
01592       case BilinearReverseDistortion:
01593 #if 0
01594       case QuadrilateralDistortion:
01595 #endif
01596       case PolynomialDistortion:
01597       case BarrelDistortion:
01598       case BarrelInverseDistortion:
01599       default:
01600         /* no bestfit available for this distortion */
01601         bestfit = MagickFalse;
01602         break;
01603     }
01604     /* Set the output image geometry to calculated 'bestfit'
01605        Do not do this for DePolar which needs to be exact for tiling
01606     */
01607     if ( bestfit && method != DePolarDistortion ) {
01608       geometry.x = (long) floor(min.x-0.5);
01609       geometry.y = (long) floor(min.y-0.5);
01610       geometry.width=(unsigned long) ceil(max.x-geometry.x+0.5);
01611       geometry.height=(unsigned long) ceil(max.y-geometry.y+0.5);
01612     }
01613     /* now that we have a new size lets fit distortion to it exactly */
01614     if ( method == DePolarDistortion ) {
01615       coeff[6]=(coeff[5]-coeff[4])/geometry.width; /* changed width */
01616       coeff[7]=(coeff[0]-coeff[1])/geometry.height; /* should be about 1.0 */
01617     }
01618   }
01619 
01620   /* The user provided a 'viewport' expert option which may
01621      overrides some parts of the current output image geometry.
01622      For ArcDistortion, this also overrides its default 'bestfit' setting.
01623   */
01624   { const char *artifact=GetImageArtifact(image,"distort:viewport");
01625     viewport_given = MagickFalse;
01626     if ( artifact != (const char *) NULL ) {
01627       (void) ParseAbsoluteGeometry(artifact,&geometry);
01628       viewport_given = MagickTrue;
01629     }
01630   }
01631 
01632   /* Verbose output */
01633   if ( GetImageArtifact(image,"verbose") != (const char *) NULL ) {
01634     register long
01635        i;
01636     char image_gen[MaxTextExtent];
01637     const char *lookup;
01638 
01639     /* Set destination image size and virtual offset */
01640     if ( bestfit || viewport_given ) {
01641       (void) FormatMagickString(image_gen, MaxTextExtent,"  -size %lux%lu "
01642         "-page %+ld%+ld xc: +insert \\\n",geometry.width,geometry.height,
01643         geometry.x,geometry.y);
01644       lookup="v.p{ xx-v.page.x-.5, yy-v.page.x-.5 }";
01645     }
01646     else {
01647       image_gen[0] = '\0';             /* no destination to generate */
01648       lookup = "p{ xx-page.x-.5, yy-page.x-.5 }"; /* simplify lookup */
01649     }
01650 
01651     switch (method) {
01652       case AffineDistortion:
01653       {
01654         double *inverse;
01655 
01656         inverse = (double *) AcquireQuantumMemory(6,sizeof(*inverse));
01657         if (inverse == (double *) NULL) {
01658           coeff = (double *) RelinquishMagickMemory(coeff);
01659           (void) ThrowMagickException(exception,GetMagickModule(),
01660                   ResourceLimitError,"MemoryAllocationFailed",
01661                   "%s", "DistortImages");
01662           return((Image *) NULL);
01663         }
01664         InvertAffineCoefficients(coeff, inverse);
01665         CoefficientsToAffineArgs(inverse);
01666         fprintf(stderr, "Affine Projection:\n");
01667         fprintf(stderr, "  -distort AffineProjection \\\n      '");
01668         for (i=0; i<5; i++)
01669           fprintf(stderr, "%lf,", inverse[i]);
01670         fprintf(stderr, "%lf'\n", inverse[5]);
01671         inverse = (double *) RelinquishMagickMemory(inverse);
01672 
01673         fprintf(stderr, "Affine Distort, FX Equivelent:\n");
01674         fprintf(stderr, "%s", image_gen);
01675         fprintf(stderr, "  -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n");
01676         fprintf(stderr, "       xx=%+lf*ii %+lf*jj %+lf;\n",
01677             coeff[0], coeff[1], coeff[2]);
01678         fprintf(stderr, "       yy=%+lf*ii %+lf*jj %+lf;\n",
01679             coeff[3], coeff[4], coeff[5]);
01680         fprintf(stderr, "       %s'\n", lookup);
01681 
01682         break;
01683       }
01684 
01685       case PerspectiveDistortion:
01686       {
01687         double *inverse;
01688 
01689         inverse = (double *) AcquireQuantumMemory(8,sizeof(*inverse));
01690         if (inverse == (double *) NULL) {
01691           coeff = (double *) RelinquishMagickMemory(coeff);
01692           (void) ThrowMagickException(exception,GetMagickModule(),
01693                   ResourceLimitError,"MemoryAllocationFailed",
01694                   "%s", "DistortCoefficients");
01695           return((Image *) NULL);
01696         }
01697         InvertPerspectiveCoefficients(coeff, inverse);
01698         fprintf(stderr, "Perspective Projection:\n");
01699         fprintf(stderr, "  -distort PerspectiveProjection \\\n      '");
01700         for (i=0; i<4; i++)
01701           fprintf(stderr, "%lf, ", inverse[i]);
01702         fprintf(stderr, "\n       ");
01703         for (; i<7; i++)
01704           fprintf(stderr, "%lf, ", inverse[i]);
01705         fprintf(stderr, "%lf'\n", inverse[7]);
01706         inverse = (double *) RelinquishMagickMemory(inverse);
01707 
01708         fprintf(stderr, "Perspective Distort, FX Equivelent:\n");
01709         fprintf(stderr, "%s", image_gen);
01710         fprintf(stderr, "  -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n");
01711         fprintf(stderr, "       rr=%+lf*ii %+lf*jj + 1;\n",
01712             coeff[6], coeff[7]);
01713         fprintf(stderr, "       xx=(%+lf*ii %+lf*jj %+lf)/rr;\n",
01714             coeff[0], coeff[1], coeff[2]);
01715         fprintf(stderr, "       yy=(%+lf*ii %+lf*jj %+lf)/rr;\n",
01716             coeff[3], coeff[4], coeff[5]);
01717         fprintf(stderr, "       rr%s0 ? %s : blue'\n",
01718             coeff[8] < 0 ? "<" : ">", lookup);
01719         break;
01720       }
01721 
01722       case BilinearForwardDistortion:
01723         fprintf(stderr, "BilinearForward Mapping Equations:\n");
01724         fprintf(stderr, "%s", image_gen);
01725         fprintf(stderr, "    i = %+lf*x %+lf*y %+lf*x*y %+lf;\n",
01726             coeff[0], coeff[1], coeff[2], coeff[3]);
01727         fprintf(stderr, "    j = %+lf*x %+lf*y %+lf*x*y %+lf;\n",
01728             coeff[4], coeff[5], coeff[6], coeff[7]);
01729 #if 0
01730         /* for debugging */
01731         fprintf(stderr, "   c8 = %+lf  c9 = 2*a = %+lf;\n",
01732             coeff[8], coeff[9]);
01733 #endif
01734         fprintf(stderr, "BilinearForward Distort, FX Equivelent:\n");
01735         fprintf(stderr, "%s", image_gen);
01736         fprintf(stderr, "  -fx 'ii=i+page.x%+lf; jj=j+page.y%+lf;\n",
01737             0.5-coeff[3], 0.5-coeff[7]);
01738         fprintf(stderr, "       bb=%lf*ii %+lf*jj %+lf;\n",
01739             coeff[6], -coeff[2], coeff[8]);
01740         /* Handle Special degenerate (non-quadratic) or trapezoidal case */
01741         if ( coeff[9] != 0 ) {
01742           fprintf(stderr, "       rt=bb*bb %+lf*(%lf*ii%+lf*jj);\n",
01743               -2*coeff[9],  coeff[4], -coeff[0]);
01744           fprintf(stderr, "       yy=( -bb + sqrt(rt) ) / %lf;\n",
01745                coeff[9]);
01746         } else
01747           fprintf(stderr, "       yy=(%lf*ii%+lf*jj)/bb;\n",
01748                 -coeff[4], coeff[0]);
01749         fprintf(stderr, "       xx=(ii %+lf*yy)/(%lf %+lf*yy);\n",
01750              -coeff[1], coeff[0], coeff[2]);
01751         if ( coeff[9] != 0 )
01752           fprintf(stderr, "       (rt < 0 ) ? red : %s'\n", lookup);
01753         else
01754           fprintf(stderr, "       %s'\n", lookup);
01755         break;
01756 
01757       case BilinearReverseDistortion:
01758 #if 0
01759         fprintf(stderr, "Polynomial Projection Distort:\n");
01760         fprintf(stderr, "  -distort PolynomialProjection \\\n");
01761         fprintf(stderr, "      '1.5, %lf, %lf, %lf, %lf,\n",
01762             coeff[3], coeff[0], coeff[1], coeff[2]);
01763         fprintf(stderr, "            %lf, %lf, %lf, %lf'\n",
01764             coeff[7], coeff[4], coeff[5], coeff[6]);
01765 #endif
01766         fprintf(stderr, "BilinearReverse Distort, FX Equivelent:\n");
01767         fprintf(stderr, "%s", image_gen);
01768         fprintf(stderr, "  -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n");
01769         fprintf(stderr, "       xx=%+lf*ii %+lf*jj %+lf*ii*jj %+lf;\n",
01770             coeff[0], coeff[1], coeff[2], coeff[3]);
01771         fprintf(stderr, "       yy=%+lf*ii %+lf*jj %+lf*ii*jj %+lf;\n",
01772             coeff[4], coeff[5], coeff[6], coeff[7]);
01773         fprintf(stderr, "       %s'\n", lookup);
01774         break;
01775 
01776       case PolynomialDistortion:
01777       {
01778         unsigned long nterms = (unsigned long) coeff[1];
01779         fprintf(stderr, "Polynomial (order %lg, terms %lu), FX Equivelent\n",
01780                        coeff[0], nterms);
01781         fprintf(stderr, "%s", image_gen);
01782         fprintf(stderr, "  -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n");
01783         fprintf(stderr, "       xx =");
01784         for (i=0; i<(long) nterms; i++) {
01785           if ( i != 0 && i%4 == 0 ) fprintf(stderr, "\n         ");
01786           fprintf(stderr, " %+lf%s", coeff[2+i],
01787                poly_basis_str(i));
01788         }
01789         fprintf(stderr, ";\n       yy =");
01790         for (i=0; i<(long) nterms; i++) {
01791           if ( i != 0 && i%4 == 0 ) fprintf(stderr, "\n         ");
01792           fprintf(stderr, " %+lf%s", coeff[2+i+nterms],
01793                poly_basis_str(i));
01794         }
01795         fprintf(stderr, ";\n       %s'\n", lookup);
01796         break;
01797       }
01798       case ArcDistortion:
01799       {
01800         fprintf(stderr, "Arc Distort, Internal Coefficients:\n");
01801         for ( i=0; i<5; i++ )
01802           fprintf(stderr, "  c%ld = %+lf\n", i, coeff[i]);
01803         fprintf(stderr, "Arc Distort, FX Equivelent:\n");
01804         fprintf(stderr, "%s", image_gen);
01805         fprintf(stderr, "  -fx 'ii=i+page.x; jj=j+page.y;\n");
01806         fprintf(stderr, "       xx=(atan2(jj,ii)%+lf)/(2*pi);\n",
01807                                   -coeff[0]);
01808         fprintf(stderr, "       xx=xx-round(xx);\n");
01809         fprintf(stderr, "       xx=xx*%lf %+lf;\n",
01810                             coeff[1], coeff[4]);
01811         fprintf(stderr, "       yy=(%lf - hypot(ii,jj)) * %lf;\n",
01812                             coeff[2], coeff[3]);
01813         fprintf(stderr, "       v.p{xx-.5,yy-.5}'\n");
01814         break;
01815       }
01816       case PolarDistortion:
01817       {
01818         fprintf(stderr, "Polar Distort, Internal Coefficents\n");
01819         for ( i=0; i<8; i++ )
01820           fprintf(stderr, "  c%ld = %+lf\n", i, coeff[i]);
01821         fprintf(stderr, "Polar Distort, FX Equivelent:\n");
01822         fprintf(stderr, "%s", image_gen);
01823         fprintf(stderr, "  -fx 'ii=i+page.x%+lf; jj=j+page.y%+lf;\n",
01824                          -coeff[2], -coeff[3]);
01825         fprintf(stderr, "       xx=(atan2(ii,jj)%+lf)/(2*pi);\n",
01826                          -(coeff[4]+coeff[5])/2 );
01827         fprintf(stderr, "       xx=xx-round(xx);\n");
01828         fprintf(stderr, "       xx=xx*2*pi*%lf + v.w/2;\n",
01829                          coeff[6] );
01830         fprintf(stderr, "       yy=(hypot(ii,jj)%+lf)*%lf;\n",
01831                          -coeff[1], coeff[7] );
01832         fprintf(stderr, "       v.p{xx-.5,yy-.5}'\n");
01833         break;
01834       }
01835       case DePolarDistortion:
01836       {
01837         fprintf(stderr, "DePolar Distort, Internal Coefficents\n");
01838         for ( i=0; i<8; i++ )
01839           fprintf(stderr, "  c%ld = %+lf\n", i, coeff[i]);
01840         fprintf(stderr, "DePolar Distort, FX Equivelent:\n");
01841         fprintf(stderr, "%s", image_gen);
01842         fprintf(stderr, "  -fx 'aa=(i+.5)*%lf %+lf;\n", coeff[6], -coeff[4] );
01843         fprintf(stderr, "       rr=(j+.5)*%lf %+lf;\n", coeff[7], +coeff[1] );
01844         fprintf(stderr, "       xx=rr*sin(aa) %+lf;\n", coeff[2] );
01845         fprintf(stderr, "       yy=rr*cos(aa) %+lf;\n", coeff[3] );
01846         fprintf(stderr, "       v.p{xx-.5,yy-.5}'\n");
01847         break;
01848       }
01849       case BarrelDistortion:
01850       case BarrelInverseDistortion:
01851       { double xc,yc;
01852         xc = ((double)image->columns-1.0)/2.0 + image->page.x;
01853         yc = ((double)image->rows-1.0)/2.0    + image->page.y;
01854         fprintf(stderr, "Barrel%s Distort, FX Equivelent:\n",
01855              method == BarrelDistortion ? "" : "Inv");
01856         fprintf(stderr, "%s", image_gen);
01857         if ( fabs(coeff[8]-xc) < 0.1 && fabs(coeff[9]-yc) < 0.1 )
01858           fprintf(stderr, "  -fx 'xc=(w-1)/2;  yc=(h-1)/2;\n");
01859         else
01860           fprintf(stderr, "  -fx 'xc=%lf;  yc=%lf;\n",
01861                coeff[8], coeff[9]);
01862         fprintf(stderr,
01863              "       ii=i-xc;  jj=j-yc;  rr=hypot(ii,jj);\n");
01864         fprintf(stderr, "       ii=ii%s(%lf*rr*rr*rr %+lf*rr*rr %+lf*rr %+lf);\n",
01865              method == BarrelDistortion ? "*" : "/",
01866              coeff[0],coeff[1],coeff[2],coeff[3]);
01867         fprintf(stderr, "       jj=jj%s(%lf*rr*rr*rr %+lf*rr*rr %+lf*rr %+lf);\n",
01868              method == BarrelDistortion ? "*" : "/",
01869              coeff[4],coeff[5],coeff[6],coeff[7]);
01870         fprintf(stderr, "       v.p{fx*ii+xc,fy*jj+yc}'\n");
01871       }
01872       default:
01873         break;
01874     }
01875   }
01876 
01877   /* The user provided a 'scale' expert option will scale the
01878      output image size, by the factor given allowing for super-sampling
01879      of the distorted image space.  Any scaling factors must naturally
01880      be halved as a result.
01881   */
01882   { const char *artifact;
01883     artifact=GetImageArtifact(image,"distort:scale");
01884     output_scaling = 1.0;
01885     if (artifact != (const char *) NULL) {
01886       output_scaling = fabs(atof(artifact));
01887       geometry.width  *= output_scaling;
01888       geometry.height *= output_scaling;
01889       geometry.x      *= output_scaling;
01890       geometry.y      *= output_scaling;
01891       if ( output_scaling < 0.1 ) {
01892         coeff = (double *) RelinquishMagickMemory(coeff);
01893         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01894                 "InvalidArgument","%s", "-set option:distort:scale" );
01895         return((Image *) NULL);
01896       }
01897       output_scaling = 1/output_scaling;
01898     }
01899   }
01900 #define ScaleFilter(F,A,B,C,D) \
01901     ScaleResampleFilter( (F), \
01902       output_scaling*(A), output_scaling*(B), \
01903       output_scaling*(C), output_scaling*(D) )
01904 
01905   /*
01906     Initialize the distort image attributes.
01907   */
01908   distort_image=CloneImage(image,geometry.width,geometry.height,MagickTrue,
01909     exception);
01910   if (distort_image == (Image *) NULL)
01911     return((Image *) NULL);
01912   if (SetImageStorageClass(distort_image,DirectClass) == MagickFalse)
01913     { /* if image is ColorMapped - change it to DirectClass */
01914       InheritException(exception,&distort_image->exception);
01915       distort_image=DestroyImage(distort_image);
01916       return((Image *) NULL);
01917     }
01918   distort_image->page.x=geometry.x;
01919   distort_image->page.y=geometry.y;
01920   if (distort_image->background_color.opacity != OpaqueOpacity)
01921     distort_image->matte=MagickTrue;
01922 
01923   { /* ----- MAIN CODE -----
01924        Sample the source image to each pixel in the distort image.
01925      */
01926     long
01927       j,
01928       progress,
01929       status;
01930 
01931     MagickPixelPacket
01932       zero;
01933 
01934     ResampleFilter
01935       **resample_filter;
01936 
01937     CacheView
01938       *distort_view;
01939 
01940     status=MagickTrue;
01941     progress=0;
01942     GetMagickPixelPacket(distort_image,&zero);
01943     resample_filter=AcquireResampleFilterThreadSet(image,MagickFalse,exception);
01944     distort_view=AcquireCacheView(distort_image);
01945 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01946   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
01947 #endif
01948     for (j=0; j < (long) distort_image->rows; j++)
01949     {
01950       double
01951         validity;  /* how mathematically valid is this the mapping */
01952 
01953       MagickBooleanType
01954         sync;
01955 
01956       MagickPixelPacket
01957         pixel,    /* pixel color to assign to distorted image */
01958         invalid;  /* the color to assign when distort result is invalid */
01959 
01960       PointInfo
01961         d,s;  /* transform destination image x,y  to source image x,y */
01962 
01963       register IndexPacket
01964         *__restrict indexes;
01965 
01966       register long
01967         i,
01968         id;
01969 
01970       register PixelPacket
01971         *__restrict q;
01972 
01973       q=QueueCacheViewAuthenticPixels(distort_view,0,j,distort_image->columns,1,
01974         exception);
01975       if (q == (PixelPacket *) NULL)
01976         {
01977           status=MagickFalse;
01978           continue;
01979         }
01980       indexes=GetCacheViewAuthenticIndexQueue(distort_view);
01981       pixel=zero;
01982 
01983       /* Define constant scaling vectors for Affine Distortions
01984         Other methods are either variable, or use interpolated lookup
01985       */
01986       id=GetOpenMPThreadId();
01987       switch (method)
01988       {
01989         case AffineDistortion:
01990           ScaleFilter( resample_filter[id],
01991             coeff[0], coeff[1],
01992             coeff[3], coeff[4] );
01993           break;
01994         default:
01995           break;
01996       }
01997 
01998       /* Initialize default pixel validity
01999       *    negative:         pixel is invalid  output 'matte_color'
02000       *    0.0 to 1.0:       antialiased, mix with resample output
02001       *    1.0 or greater:   use resampled output.
02002       */
02003       validity = 1.0;
02004 
02005       GetMagickPixelPacket(distort_image,&invalid);
02006       SetMagickPixelPacket(distort_image,&distort_image->matte_color,
02007         (IndexPacket *) NULL, &invalid);
02008       if (distort_image->colorspace == CMYKColorspace)
02009         ConvertRGBToCMYK(&invalid);   /* what about other color spaces? */
02010 
02011       for (i=0; i < (long) distort_image->columns; i++)
02012       {
02013         /* map pixel coordinate to distortion space coordinate */
02014         d.x = (double) (geometry.x+i+0.5)*output_scaling;
02015         d.y = (double) (geometry.y+j+0.5)*output_scaling;
02016         s = d;  /* default is a no-op mapping */
02017         switch (method)
02018         {
02019           case AffineDistortion:
02020           {
02021             s.x=coeff[0]*d.x+coeff[1]*d.y+coeff[2];
02022             s.y=coeff[3]*d.x+coeff[4]*d.y+coeff[5];
02023             /* Affine partial derivitives are constant -- set above */
02024             break;
02025           }
02026           case PerspectiveDistortion:
02027           {
02028             double
02029               p,q,r,abs_r,abs_c6,abs_c7,scale;
02030             /* perspective is a ratio of affines */
02031             p=coeff[0]*d.x+coeff[1]*d.y+coeff[2];
02032             q=coeff[3]*d.x+coeff[4]*d.y+coeff[5];
02033             r=coeff[6]*d.x+coeff[7]*d.y+1.0;
02034             /* Pixel Validity -- is it a 'sky' or 'ground' pixel */
02035             validity = (r*coeff[8] < 0.0) ? 0.0 : 1.0;
02036             /* Determine horizon anti-alias blending */
02037             abs_r = fabs(r)*2;
02038             abs_c6 = fabs(coeff[6]);
02039             abs_c7 = fabs(coeff[7]);
02040             if ( abs_c6 > abs_c7 ) {
02041               if ( abs_r < abs_c6 )
02042                 validity = 0.5 - coeff[8]*r/coeff[6];
02043             }
02044             else if ( abs_r < abs_c7 )
02045               validity = 0.5 - coeff[8]*r/coeff[7];
02046             /* Perspective Sampling Point (if valid) */
02047             if ( validity > 0.0 ) {
02048               /* divide by r affine, for perspective scaling */
02049               scale = 1.0/r;
02050               s.x = p*scale;
02051               s.y = q*scale;
02052               /* Perspective Partial Derivatives or Scaling Vectors */
02053               scale *= scale;
02054               ScaleFilter( resample_filter[id],
02055                 (r*coeff[0] - p*coeff[6])*scale,
02056                 (r*coeff[1] - p*coeff[7])*scale,
02057                 (r*coeff[3] - q*coeff[6])*scale,
02058                 (r*coeff[4] - q*coeff[7])*scale );
02059             }
02060             break;
02061           }
02062           case BilinearReverseDistortion:
02063           {
02064             /* Reversed Mapped is just a simple polynomial */
02065             s.x=coeff[0]*d.x+coeff[1]*d.y+coeff[2]*d.x*d.y+coeff[3];
02066             s.y=coeff[4]*d.x+coeff[5]*d.y
02067                     +coeff[6]*d.x*d.y+coeff[7];
02068             /* Bilinear partial derivitives of scaling vectors */
02069             ScaleFilter( resample_filter[id],
02070                 coeff[0] + coeff[2]*d.y,
02071                 coeff[1] + coeff[2]*d.x,
02072                 coeff[4] + coeff[6]*d.y,
02073                 coeff[5] + coeff[6]*d.x );
02074             break;
02075           }
02076           case BilinearForwardDistortion:
02077           {
02078             /* Forward mapped needs reversed polynomial equations
02079              * which unfortunatally requires a square root!  */
02080             double b,c;
02081             d.x -= coeff[3];  d.y -= coeff[7];
02082             b = coeff[6]*d.x - coeff[2]*d.y + coeff[8];
02083             c = coeff[4]*d.x - coeff[0]*d.y;
02084 
02085             validity = 1.0;
02086             /* Handle Special degenerate (non-quadratic) case */
02087             if ( fabs(coeff[9]) < MagickEpsilon )
02088               s.y =  -c/b;
02089             else {
02090               c = b*b - 2*coeff[9]*c;
02091               if ( c < 0.0 )
02092                 validity = 0.0;
02093               else
02094                 s.y = ( -b + sqrt(c) )/coeff[9];
02095             }
02096             if ( validity > 0.0 )
02097               s.x = ( d.x - coeff[1]*s.y) / ( coeff[0] + coeff[2]*s.y );
02098 
02099             /* NOTE: the sign of the square root should be -ve for parts
02100                      where the source image becomes 'flipped' or 'mirrored'.
02101                FUTURE: Horizon handling
02102                FUTURE: Scaling factors or Deritives (how?)
02103             */
02104             break;
02105           }
02106 #if 0
02107           case QuadrilateralDistortion:
02108             /* Bilinear mapping of any Quadrilateral to any Quadrilateral */
02109             /* UNDER DEVELOPMENT */
02110             break;
02111 #endif
02112           case PolynomialDistortion:
02113           {
02114             /* multi-ordered polynomial */
02115             register long
02116               k;
02117             long
02118               nterms=(long)coeff[1];
02119 
02120             PointInfo
02121               du,dv; /* the du,dv vectors from unit dx,dy -- derivatives */
02122 
02123             s.x=s.y=du.x=du.y=dv.x=dv.y=0.0;
02124             for(k=0; k < nterms; k++) {
02125               s.x  += poly_basis_fn(k,d.x,d.y)*coeff[2+k];
02126               du.x += poly_basis_dx(k,d.x,d.y)*coeff[2+k];
02127               du.y += poly_basis_dy(k,d.x,d.y)*coeff[2+k];
02128               s.y  += poly_basis_fn(k,d.x,d.y)*coeff[2+k+nterms];
02129               dv.x += poly_basis_dx(k,d.x,d.y)*coeff[2+k+nterms];
02130               dv.y += poly_basis_dy(k,d.x,d.y)*coeff[2+k+nterms];
02131             }
02132             ScaleFilter( resample_filter[id], du.x,du.y,dv.x,dv.y );
02133             break;
02134           }
02135           case ArcDistortion:
02136           {
02137             /* what is the angle and radius in the destination image */
02138             s.x  = (atan2(d.y,d.x) - coeff[0])/Magick2PI;
02139             s.x -= MagickRound(s.x);     /* angle */
02140             s.y  = hypot(d.x,d.y);       /* radius */
02141 
02142             /* Arc Distortion Partial Scaling Vectors
02143               Are derived by mapping the perpendicular unit vectors
02144               dR  and  dA*R*2PI  rather than trying to map dx and dy
02145               The results is a very simple orthogonal aligned ellipse.
02146             */
02147             if ( s.y > MagickEpsilon )
02148               ScaleFilter( resample_filter[id],
02149                   coeff[1]/(Magick2PI*s.y), 0, 0, coeff[3] );
02150             else
02151               ScaleFilter( resample_filter[id],
02152                   distort_image->columns*2, 0, 0, coeff[3] );
02153 
02154             /* now scale the angle and radius for source image lookup point */
02155             s.x = s.x*coeff[1] + coeff[4] + image->page.x +0.5;
02156             s.y = (coeff[2] - s.y) * coeff[3] + image->page.y;
02157             break;
02158           }
02159           case PolarDistortion:
02160           { /* Rect/Cartesain/Cylinder to Polar View */
02161             d.x -= coeff[2];
02162             d.y -= coeff[3];
02163             s.x  = atan2(d.x,d.y) - (coeff[4]+coeff[5])/2;
02164             s.x /= Magick2PI;
02165             s.x -= MagickRound(s.x);
02166             s.x *= Magick2PI;       /* angle - relative to centerline */
02167             s.y  = hypot(d.x,d.y);  /* radius */
02168 
02169             /* Polar Scaling vectors are based on mapping dR and dA vectors
02170                This results in very simple orthogonal scaling vectors
02171             */
02172             if ( s.y > MagickEpsilon )
02173               ScaleFilter( resample_filter[id],
02174                   coeff[6]/(Magick2PI*s.y), 0, 0, coeff[7] );
02175             else
02176               ScaleFilter( resample_filter[id],
02177                   distort_image->columns*2, 0, 0, coeff[7] );
02178 
02179             /* now finish mapping radius/angle to source x,y coords */
02180             s.x = s.x*coeff[6] + (double)image->columns/2.0 + image->page.x;
02181             s.y = (s.y-coeff[1])*coeff[7] + image->page.y;
02182             break;
02183           }
02184           case DePolarDistortion:
02185           { /* Polar to Cylindical  */
02186             /* ignore all destination virtual offsets */
02187             d.x = ((double)i+0.5)*output_scaling*coeff[6]-coeff[4];
02188             d.y = ((double)j+0.5)*output_scaling*coeff[7]+coeff[1];
02189             s.x = d.y*sin(d.x) + coeff[2];
02190             s.y = d.y*cos(d.x) + coeff[3];
02191             /* derivatives are usless - better to use SuperSampling */
02192             break;
02193           }
02194           case BarrelDistortion:
02195           case BarrelInverseDistortion:
02196           {
02197             double r,fx,fy,gx,gy;
02198             /* Radial Polynomial Distortion (de-normalized) */
02199             d.x -= coeff[8];
02200             d.y -= coeff[9];
02201             r = sqrt(d.x*d.x+d.y*d.y);
02202             if ( r > MagickEpsilon ) {
02203               fx = ((coeff[0]*r + coeff[1])*r + coeff[2])*r + coeff[3];
02204               fy = ((coeff[4]*r + coeff[5])*r + coeff[6])*r + coeff[7];
02205               gx = ((3*coeff[0]*r + 2*coeff[1])*r + coeff[2])/r;
02206               gy = ((3*coeff[4]*r + 2*coeff[5])*r + coeff[6])/r;
02207               /* adjust functions and scaling for 'inverse' form */
02208               if ( method == BarrelInverseDistortion ) {
02209                 fx = 1/fx;  fy = 1/fy;
02210                 gx *= -fx*fx;  gy *= -fy*fy;
02211               }
02212               /* Set source pixel and EWA derivative vectors */
02213               s.x = d.x*fx + coeff[8];
02214               s.y = d.y*fy + coeff[9];
02215               ScaleFilter( resample_filter[id],
02216                   gx*d.x*d.x + fx, gx*d.x*d.y,
02217                   gy*d.x*d.y,      gy*d.y*d.y + fy );
02218             }
02219             else { /* Special handling to avoid divide by zero when r=0 */
02220               s.x=s.y=0.0;
02221               if ( method == BarrelDistortion )
02222                 ScaleFilter( resample_filter[id],
02223                      coeff[3], 0, 0, coeff[7] );
02224               else /* method == BarrelInverseDistortion */
02225                 /* FUTURE, trap for D==0 causing division by zero */
02226                 ScaleFilter( resample_filter[id],
02227                      1.0/coeff[3], 0, 0, 1.0/coeff[7] );
02228             }
02229             break;
02230           }
02231           case ShepardsDistortion:
02232           { /* Shepards Method, or Inverse Weighted Distance for
02233               displacement around the destination image control points
02234               The input arguments are the coefficents to the function.
02235               This is more of a 'displacement' function rather than an
02236               absolute distortion function.
02237             */
02238             unsigned long
02239               i;
02240             double
02241               denominator;
02242 
02243             denominator = s.x = s.y = 0;
02244             for(i=0; i<number_arguments; i+=4) {
02245               double weight =
02246                   ((double)d.x-arguments[i+2])*((double)d.x-arguments[i+2])
02247                 + ((double)d.y-arguments[i+3])*((double)d.y-arguments[i+3]);
02248               if ( weight != 0 )
02249                 weight = 1/weight;
02250               else
02251                 weight = 1;
02252 
02253               s.x += (arguments[ i ]-arguments[i+2])*weight;
02254               s.y += (arguments[i+1]-arguments[i+3])*weight;
02255               denominator += weight;
02256             }
02257             s.x /= denominator;
02258             s.y /= denominator;
02259             s.x += d.x;
02260             s.y += d.y;
02261 
02262             /* We can not determine derivatives using shepards method
02263                only color interpolatation, not area-resampling */
02264             break;
02265           }
02266           default:
02267             break; /* use the default no-op given above */
02268         }
02269         /* map virtual canvas location back to real image coordinate */
02270         if ( bestfit && method != ArcDistortion ) {
02271           s.x -= image->page.x;
02272           s.y -= image->page.y;
02273         }
02274         s.x -= 0.5;
02275         s.y -= 0.5;
02276 
02277         if ( validity <= 0.0 ) {
02278           /* result of distortion is an invalid pixel - don't resample */
02279           SetPixelPacket(distort_image,&invalid,q,indexes);
02280         }
02281         else {
02282           /* resample the source image to find its correct color */
02283           (void) ResamplePixelColor(resample_filter[id],s.x,s.y,&pixel);
02284           /* if validity between 0.0 and 1.0 mix result with invalid pixel */
02285           if ( validity < 1.0 ) {
02286             /* Do a blend of sample color and invalid pixel */
02287             /* should this be a 'Blend', or an 'Over' compose */
02288             MagickPixelCompositeBlend(&pixel,validity,&invalid,(1.0-validity),
02289               &pixel);
02290           }
02291           SetPixelPacket(distort_image,&pixel,q,indexes);
02292         }
02293         q++;
02294         indexes++;
02295       }
02296       sync=SyncCacheViewAuthenticPixels(distort_view,exception);
02297       if (sync == MagickFalse)
02298         status=MagickFalse;
02299       if (image->progress_monitor != (MagickProgressMonitor) NULL)
02300         {
02301           MagickBooleanType
02302             proceed;
02303 
02304 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02305   #pragma omp critical (MagickCore_DistortImage)
02306 #endif
02307           proceed=SetImageProgress(image,DistortImageTag,progress++,
02308             image->rows);
02309           if (proceed == MagickFalse)
02310             status=MagickFalse;
02311         }
02312 #if 0
02313 fprintf(stderr, "\n");
02314 #endif
02315     }
02316     distort_view=DestroyCacheView(distort_view);
02317     resample_filter=DestroyResampleFilterThreadSet(resample_filter);
02318 
02319     if (status == MagickFalse)
02320       distort_image=DestroyImage(distort_image);
02321   }
02322 
02323   /* Arc does not return an offset unless 'bestfit' is in effect
02324      And the user has not provided an overriding 'viewport'.
02325    */
02326   if ( method == ArcDistortion && !bestfit && !viewport_given ) {
02327     distort_image->page.x = 0;
02328     distort_image->page.y = 0;
02329   }
02330   coeff = (double *) RelinquishMagickMemory(coeff);
02331   return(distort_image);
02332 }
02333 
02334 /*
02335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02336 %                                                                             %
02337 %                                                                             %
02338 %                                                                             %
02339 %   S p a r s e C o l o r I m a g e                                           %
02340 %                                                                             %
02341 %                                                                             %
02342 %                                                                             %
02343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02344 %
02345 %  SparseColorImage(), given a set of coordinates, interpolates the colors
02346 %  found at those coordinates, across the whole image, using various methods.
02347 %
02348 %  The format of the SparseColorImage() method is:
02349 %
02350 %      Image *SparseColorImage(const Image *image,const ChannelType channel,
02351 %        SparseColorMethod method,const unsigned long number_arguments,
02352 %        const double *arguments,ExceptionInfo *exception)
02353 %
02354 %  A description of each parameter follows:
02355 %
02356 %    o image: the image to be filled in.
02357 %
02358 %    o channel: Specify which color values (in RGBKA sequence) are being set.
02359 %        This also determines the number of color_values in above.
02360 %
02361 %    o method: the method to fill in the gradient between the control points.
02362 %
02363 %        The methods used for SparseColor() are often simular to methods
02364 %        used for DistortImage(), and even share the same code for determination
02365 %        of the function coefficents, though with more dimensions (or resulting
02366 %        values).
02367 %
02368 %    o number_arguments: the number of arguments given.
02369 %
02370 %    o arguments: array of floating point arguments for this method--
02371 %        x,y,color_values-- with color_values given as normalized values.
02372 %
02373 %    o exception: return any errors or warnings in this structure
02374 %
02375 */
02376 MagickExport Image *SparseColorImage(const Image *image,
02377   const ChannelType channel,SparseColorMethod method,
02378   const unsigned long number_arguments,const double *arguments,
02379   ExceptionInfo *exception)
02380 {
02381 #define SparseColorTag  "Distort/SparseColor"
02382 
02383   DistortImageMethod
02384     *distort_method;
02385 
02386   double
02387     *coeff;
02388 
02389   Image
02390     *sparse_image;
02391 
02392   MagickPixelPacket
02393     zero;
02394 
02395   unsigned long
02396     number_colors;
02397 
02398   assert(image != (Image *) NULL);
02399   assert(image->signature == MagickSignature);
02400   if (image->debug != MagickFalse)
02401     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02402   assert(exception != (ExceptionInfo *) NULL);
02403   assert(exception->signature == MagickSignature);
02404 
02405   /* Determine number of color values needed per control point */
02406   number_colors=0;
02407   if ( channel & RedChannel     ) number_colors++;
02408   if ( channel & GreenChannel   ) number_colors++;
02409   if ( channel & BlueChannel    ) number_colors++;
02410   if ( channel & IndexChannel   ) number_colors++;
02411   if ( channel & OpacityChannel ) number_colors++;
02412 
02413   /*
02414     Convert input arguments into mapping coefficients to apply the distortion.
02415     Note some Methods may fall back to other simpler methods.
02416   */
02417   distort_method=(DistortImageMethod *) &method;
02418   coeff = GenerateCoefficients(image, distort_method, number_arguments,
02419     arguments, number_colors, exception);
02420   if ( coeff == (double *) NULL )
02421     return((Image *) NULL);
02422 
02423   /* Verbose output */
02424   if ( GetImageArtifact(image,"verbose") != (const char *) NULL ) {
02425 
02426     switch (method) {
02427       case BarycentricColorInterpolate:
02428       {
02429         register long x=0;
02430         fprintf(stderr, "Barycentric Sparse Color:\n");
02431         if ( channel & RedChannel )
02432           fprintf(stderr, "  -channel R -fx '%+lf*i %+lf*j %+lf' \\\n",
02433               coeff[x], coeff[x+1], coeff[x+2]),x+=3;
02434         if ( channel & GreenChannel )
02435           fprintf(stderr, "  -channel G -fx '%+lf*i %+lf*j %+lf' \\\n",
02436               coeff[x], coeff[x+1], coeff[x+2]),x+=3;
02437         if ( channel & BlueChannel )
02438           fprintf(stderr, "  -channel B -fx '%+lf*i %+lf*j %+lf' \\\n",
02439               coeff[x], coeff[x+1], coeff[x+2]),x+=3;
02440         if ( channel & IndexChannel )
02441           fprintf(stderr, "  -channel K -fx '%+lf*i %+lf*j %+lf' \\\n",
02442               coeff[x], coeff[x+1], coeff[x+2]),x+=3;
02443         if ( channel & OpacityChannel )
02444           fprintf(stderr, "  -channel A -fx '%+lf*i %+lf*j %+lf' \\\n",
02445               coeff[x], coeff[x+1], coeff[x+2]),x+=3;
02446         break;
02447       }
02448       case BilinearColorInterpolate:
02449       {
02450         register long x=0;
02451         fprintf(stderr, "Bilinear Sparse Color\n");
02452         if ( channel & RedChannel )
02453           fprintf(stderr, "   -channel R -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n",
02454               coeff[ x ], coeff[x+1],
02455               coeff[x+2], coeff[x+3]),x+=4;
02456         if ( channel & GreenChannel )
02457           fprintf(stderr, "   -channel G -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n",
02458               coeff[ x ], coeff[x+1],
02459               coeff[x+2], coeff[x+3]),x+=4;
02460         if ( channel & BlueChannel )
02461           fprintf(stderr, "   -channel B -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n",
02462               coeff[ x ], coeff[x+1],
02463               coeff[x+2], coeff[x+3]),x+=4;
02464         if ( channel & IndexChannel )
02465           fprintf(stderr, "   -channel K -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n",
02466               coeff[ x ], coeff[x+1],
02467               coeff[x+2], coeff[x+3]),x+=4;
02468         if ( channel & OpacityChannel )
02469           fprintf(stderr, "   -channel A -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n",
02470               coeff[ x ], coeff[x+1],
02471               coeff[x+2], coeff[x+3]),x+=4;
02472         break;
02473       }
02474       default:
02475         /* unknown, or which are too complex for FX alturnatives */
02476         break;
02477     }
02478   }
02479 
02480   /* Generate new image for generated interpolated gradient.
02481    * ASIDE: Actually we could have just replaced the colors of the original
02482    * image, but IM core policy, is if storage class could change then clone
02483    * the image.
02484    */
02485 
02486   sparse_image=CloneImage(image,image->columns,image->rows,MagickTrue,
02487     exception);
02488   if (sparse_image == (Image *) NULL)
02489     return((Image *) NULL);
02490   if (SetImageStorageClass(sparse_image,DirectClass) == MagickFalse)
02491     { /* if image is ColorMapped - change it to DirectClass */
02492       InheritException(exception,&image->exception);
02493       sparse_image=DestroyImage(sparse_image);
02494       return((Image *) NULL);
02495     }
02496   { /* ----- MAIN CODE ----- */
02497     long
02498       j,
02499       progress;
02500 
02501     MagickBooleanType
02502       status;
02503 
02504     CacheView
02505       *sparse_view;
02506 
02507     status=MagickTrue;
02508     progress=0;
02509     GetMagickPixelPacket(sparse_image,&zero);
02510     sparse_view=AcquireCacheView(sparse_image);
02511 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02512   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
02513 #endif
02514     for (j=0; j < (long) sparse_image->rows; j++)
02515     {
02516       MagickBooleanType
02517         sync;
02518 
02519       MagickPixelPacket
02520         pixel;    /* pixel to assign to distorted image */
02521 
02522       register IndexPacket
02523         *__restrict indexes;
02524 
02525       register long
02526         i;
02527 
02528       register PixelPacket
02529         *__restrict q;
02530 
02531       q=QueueCacheViewAuthenticPixels(sparse_view,0,j,sparse_image->columns,
02532         1,exception);
02533       if (q == (PixelPacket *) NULL)
02534         {
02535           status=MagickFalse;
02536           continue;
02537         }
02538 /* FUTURE: get pixel from source image - so channel can replace parts */
02539       indexes=GetCacheViewAuthenticIndexQueue(sparse_view);
02540       pixel=zero;
02541       for (i=0; i < (long) sparse_image->columns; i++)
02542       {
02543         switch (method)
02544         {
02545           case BarycentricColorInterpolate:
02546           {
02547             register long x=0;
02548             if ( channel & RedChannel )
02549               pixel.red     = coeff[x]*i +coeff[x+1]*j
02550                               +coeff[x+2], x+=3;
02551             if ( channel & GreenChannel )
02552               pixel.green   = coeff[x]*i +coeff[x+1]*j
02553                               +coeff[x+2], x+=3;
02554             if ( channel & BlueChannel )
02555               pixel.blue    = coeff[x]*i +coeff[x+1]*j
02556                               +coeff[x+2], x+=3;
02557             if ( channel & IndexChannel )
02558               pixel.index   = coeff[x]*i +coeff[x+1]*j
02559                               +coeff[x+2], x+=3;
02560             if ( channel & OpacityChannel )
02561               pixel.opacity = coeff[x]*i +coeff[x+1]*j
02562                               +coeff[x+2], x+=3;
02563             break;
02564           }
02565           case BilinearColorInterpolate:
02566           {
02567             register long x=0;
02568             if ( channel & RedChannel )
02569               pixel.red     = coeff[x]*i     + coeff[x+1]*j +
02570                               coeff[x+2]*i*j + coeff[x+3], x+=4;
02571             if ( channel & GreenChannel )
02572               pixel.green   = coeff[x]*i     + coeff[x+1]*j +
02573                               coeff[x+2]*i*j + coeff[x+3], x+=4;
02574             if ( channel & BlueChannel )
02575               pixel.blue    = coeff[x]*i     + coeff[x+1]*j +
02576                               coeff[x+2]*i*j + coeff[x+3], x+=4;
02577             if ( channel & IndexChannel )
02578               pixel.index   = coeff[x]*i     + coeff[x+1]*j +
02579                               coeff[x+2]*i*j + coeff[x+3], x+=4;
02580             if ( channel & OpacityChannel )
02581               pixel.opacity = coeff[x]*i     + coeff[x+1]*j +
02582                               coeff[x+2]*i*j + coeff[x+3], x+=4;
02583             break;
02584           }
02585           case ShepardsColorInterpolate:
02586           { /* Shepards Method,uses its own input arguments as coefficients.
02587             */
02588             unsigned long
02589               k;
02590             double
02591               denominator;
02592 
02593             if ( channel & RedChannel     ) pixel.red     = 0.0;
02594             if ( channel & GreenChannel   ) pixel.green   = 0.0;
02595             if ( channel & BlueChannel    ) pixel.blue    = 0.0;
02596             if ( channel & IndexChannel   ) pixel.index   = 0.0;
02597             if ( channel & OpacityChannel ) pixel.opacity = 0.0;
02598             denominator = 0.0;
02599             for(k=0; k<number_arguments; k+=2+number_colors) {
02600               register long x=(long) k+2;
02601               double weight =
02602                   ((double)i-arguments[ k ])*((double)i-arguments[ k ])
02603                 + ((double)j-arguments[k+1])*((double)j-arguments[k+1]);
02604               if ( weight != 0 )
02605                 weight = 1/weight;
02606               else
02607                 weight = 1;
02608               if ( channel & RedChannel )
02609                 pixel.red     += arguments[x++]*weight;
02610               if ( channel & GreenChannel )
02611                 pixel.green   += arguments[x++]*weight;
02612               if ( channel & BlueChannel )
02613                 pixel.blue    += arguments[x++]*weight;
02614               if ( channel & IndexChannel )
02615                 pixel.index   += arguments[x++]*weight;
02616               if ( channel & OpacityChannel )
02617                 pixel.opacity += arguments[x++]*weight;
02618               denominator += weight;
02619             }
02620             if ( channel & RedChannel     ) pixel.red     /= denominator;
02621             if ( channel & GreenChannel   ) pixel.green   /= denominator;
02622             if ( channel & BlueChannel    ) pixel.blue    /= denominator;
02623             if ( channel & IndexChannel   ) pixel.index   /= denominator;
02624             if ( channel & OpacityChannel ) pixel.opacity /= denominator;
02625             break;
02626           }
02627           case VoronoiColorInterpolate:
02628           default:
02629           { /* Just use the closest control point you can find! */
02630             unsigned long
02631               k;
02632             double
02633               minimum = MagickHuge;
02634 
02635             for(k=0; k<number_arguments; k+=2+number_colors) {
02636               double distance =
02637                   ((double)i-arguments[ k ])*((double)i-arguments[ k ])
02638                 + ((double)j-arguments[k+1])*((double)j-arguments[k+1]);
02639               if ( distance < minimum ) {
02640                 register long x=(long) k+2;
02641                 if ( channel & RedChannel     ) pixel.red     = arguments[x++];
02642                 if ( channel & GreenChannel   ) pixel.green   = arguments[x++];
02643                 if ( channel & BlueChannel    ) pixel.blue    = arguments[x++];
02644                 if ( channel & IndexChannel   ) pixel.index   = arguments[x++];
02645                 if ( channel & OpacityChannel ) pixel.opacity = arguments[x++];
02646                 minimum = distance;
02647               }
02648             }
02649             break;
02650           }
02651         }
02652         /* set the color directly back into the source image */
02653         if ( channel & RedChannel     ) pixel.red     *= QuantumRange;
02654         if ( channel & GreenChannel   ) pixel.green   *= QuantumRange;
02655         if ( channel & BlueChannel    ) pixel.blue    *= QuantumRange;
02656         if ( channel & IndexChannel   ) pixel.index   *= QuantumRange;
02657         if ( channel & OpacityChannel ) pixel.opacity *= QuantumRange;
02658         SetPixelPacket(sparse_image,&pixel,q,indexes);
02659         q++;
02660         indexes++;
02661       }
02662       sync=SyncCacheViewAuthenticPixels(sparse_view,exception);
02663       if (sync == MagickFalse)
02664         status=MagickFalse;
02665       if (image->progress_monitor != (MagickProgressMonitor) NULL)
02666         {
02667           MagickBooleanType
02668             proceed;
02669 
02670 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02671   #pragma omp critical (MagickCore_SparseColorImage)
02672 #endif
02673           proceed=SetImageProgress(image,SparseColorTag,progress++,image->rows);
02674           if (proceed == MagickFalse)
02675             status=MagickFalse;
02676         }
02677     }
02678     sparse_view=DestroyCacheView(sparse_view);
02679     if (status == MagickFalse)
02680       sparse_image=DestroyImage(sparse_image);
02681   }
02682   coeff = (double *) RelinquishMagickMemory(coeff);
02683   return(sparse_image);
02684 }

Generated on 19 Nov 2009 for MagickCore by  doxygen 1.6.1