root / ImageMagick / branches / ImageMagick-6.3.5 / magick / distort.c

Revision 8056, 35.8 kB (checked in by anthony, 14 months ago)

remove debug prints

Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%               DDDD   IIIII  SSSSS  TTTTT   OOO   RRRR   TTTTT               %
7%               D   D    I    SS       T    O   O  R   R    T                 %
8%               D   D    I     SSS     T    O   O  RRRR     T                 %
9%               D   D    I       SS    T    O   O  R R      T                 %
10%               DDDD   IIIII  SSSSS    T     OOO   R  R     T                 %
11%                                                                             %
12%                                                                             %
13%                     ImageMagick Image Distortion Methods.                   %
14%                                                                             %
15%                              Software Design                                %
16%                                John Cristy                                  %
17%                              Anthony Thyssen                                %
18%                                 June 2007                                   %
19%                                                                             %
20%                                                                             %
21%  Copyright 1999-2007 ImageMagick Studio LLC, a non-profit organization      %
22%  dedicated to making software imaging solutions freely available.           %
23%                                                                             %
24%  You may not use this file except in compliance with the License.  You may  %
25%  obtain a copy of the License at                                            %
26%                                                                             %
27%    http://www.imagemagick.org/script/license.php                            %
28%                                                                             %
29%  Unless required by applicable law or agreed to in writing, software        %
30%  distributed under the License is distributed on an "AS IS" BASIS,          %
31%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
32%  See the License for the specific language governing permissions and        %
33%  limitations under the License.                                             %
34%                                                                             %
35%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36%
37%
38*/
39
40/*
41  Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/cache-view.h"
45#include "magick/colorspace-private.h"
46#include "magick/composite-private.h"
47#include "magick/distort.h"
48#include "magick/exception.h"
49#include "magick/exception-private.h"
50#include "magick/gem.h"
51#include "magick/hashmap.h"
52#include "magick/image.h"
53#include "magick/list.h"
54#include "magick/matrix.h"
55#include "magick/memory_.h"
56#include "magick/pixel.h"
57#include "magick/pixel-private.h"
58#include "magick/resample.h"
59#include "magick/registry.h"
60#include "magick/semaphore.h"
61#include "magick/splay-tree.h"
62#include "magick/string_.h"
63
64/*
65%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66%                                                                             %
67%                                                                             %
68%                                                                             %
69%   D i s t o r t I m a g e                                                   %
70%                                                                             %
71%                                                                             %
72%                                                                             %
73%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74%
75%  DistortImage() distorts an image using various distortion methods, by
76%  mapping color lookups of the source image to a new destination image
77%  usally of the same size as the source image, unless 'bestfit' is set to
78%  true.
79%
80%  If 'bestfit' is enabled, and distortion allows it, the destination image is
81%  adjusted to ensure the whole source 'image' will just fit within the final
82%  destination image, which will be sized and offset accordingly.  Also in
83%  many cases the virtual offset of the source image will be taken into
84%  account in the mapping.
85%
86%  ArcDistortion will always ignore source image offset, and always 'bestfit'
87%  the destination image with the top left corner offset relative to the polar
88%  mapping center.
89%
90%  Bilinear has no simple inverse mapping so will not allow 'bestfit' style
91%  of image distortion.
92%
93%  The format of the DistortImage() method is:
94%
95%      Image *DistortImage(const Image *image,const DistortImageMethod method,
96%        const unsigned long number_arguments,const double *arguments,
97%        const MagickBooleanType bestfit, ExceptionInfo *exception)
98%
99%  A description of each parameter follows:
100%
101%    o image: The image to be distorted.
102%
103%    o method: The method of image distortion.
104%
105%    o number_arguments: The number of arguments given.
106%
107%    o arguments: The arguments for this distortion method.
108%
109%    o bestfit: Attempt to resize destination to fit distorted source.
110%
111%    o exception: Return any errors or warnings in this structure
112%
113*/
114static MagickBooleanType SolveAffineDistortion(
115  const unsigned long number_points,const PointInfo *points,double **matrix,
116  double *vector)
117{
118  /*
119    Given the coordinates of two triangles
120      u0,v0, ... u2,v2,   x3,y3, ... x5,y5
121
122    Solve for the 6 cofficients c0..c6 for a affine distortion:
123      u = c0*x + c2*y + c4
124      v = c1*x + c3*y + c5
125  */
126  if (number_points < 6)
127    return(MagickFalse);
128  matrix[0][0]=points[3].x;
129  matrix[0][2]=points[3].y;
130  matrix[0][4]=1.0;
131  vector[0]=points[0].x;
132
133  matrix[1][1]=points[3].x;
134  matrix[1][3]=points[3].y;
135  matrix[1][5]=1.0;
136  vector[1]=points[0].y;
137
138  matrix[2][0]=points[4].x;
139  matrix[2][2]=points[4].y;
140  matrix[2][4]=1.0;
141  vector[2]=points[1].x;
142
143  matrix[3][1]=points[4].x;
144  matrix[3][3]=points[4].y;
145  matrix[3][5]=1.0;
146  vector[3]=points[1].y;
147
148  matrix[4][0]=points[5].x;
149  matrix[4][2]=points[5].y;
150  matrix[4][4]=1.0;
151  vector[4]=points[2].x;
152
153  matrix[5][1]=points[5].x;
154  matrix[5][3]=points[5].y;
155  matrix[5][5]=1.0;
156  vector[5]=points[2].y;
157  return(GaussJordanElimination(matrix,6,vector));
158}
159
160static void InvertAffineCoefficients(
161  const double *coefficients,double *inverse)
162{
163  double determinant;
164
165  determinant=1.0/(coefficients[0]*coefficients[3]-coefficients[1]*coefficients[2]);
166  inverse[0]=determinant*coefficients[3];
167  inverse[1]=determinant*(-coefficients[1]);
168  inverse[2]=determinant*(-coefficients[2]);
169  inverse[3]=determinant*coefficients[0];
170  inverse[4]=(-coefficients[4])*inverse[0]-coefficients[5]*inverse[2];
171  inverse[5]=(-coefficients[4])*inverse[1]-coefficients[5]*inverse[3];
172}
173
174static MagickBooleanType SolveBilinearDistortion(
175  const unsigned long number_points,const PointInfo *points,double **matrix,
176  double *vector)
177{
178  /*
179    Given the coordinates of two quadrilaterals:
180      u0,v0, ... u3,v3,   x4,y4, ... x7,y7
181
182    Solve for the 8 coeffecients c0..c7 for a bilinear distortion:
183      u = c0*x + c1*y + c2*x*y + c3
184      v = c4*x + c5*y + c6*x*y + c7
185  */
186  if (number_points < 8)
187    return(MagickFalse);
188  matrix[0][0]=points[4].x;
189  matrix[0][1]=points[4].y;
190  matrix[0][2]=points[4].x*points[4].y;
191  matrix[0][3]=1.0;
192  vector[0]=points[0].x;
193  matrix[1][4]=points[4].x;
194  matrix[1][5]=points[4].y;
195  matrix[1][6]=points[4].x*points[4].y;
196  matrix[1][7]=1.0;
197  vector[1]=points[0].y;
198  matrix[2][0]=points[5].x;
199  matrix[2][1]=points[5].y;
200  matrix[2][2]=points[5].x*points[5].y;
201  matrix[2][3]=1.0;
202  matrix[3][4]=points[5].x;
203  matrix[3][5]=points[5].y;
204  matrix[3][6]=points[5].x*points[5].y;
205  matrix[3][7]=1.0;
206  matrix[4][0]=points[6].x;
207  matrix[4][1]=points[6].y;
208  matrix[4][2]=points[6].x*points[6].y;
209  matrix[4][3]=1.0;
210  matrix[5][4]=points[6].x;
211  matrix[5][5]=points[6].y;
212  matrix[5][6]=points[6].x*points[6].y;
213  matrix[5][7]=1.0;
214  matrix[6][0]=points[7].x;
215  matrix[6][1]=points[7].y;
216  matrix[6][2]=points[7].x*points[7].y;
217  matrix[6][3]=1.0;
218  matrix[7][4]=points[7].x;
219  matrix[7][5]=points[7].y;
220  matrix[7][6]=points[7].x*points[7].y;
221  matrix[7][7]=1.0;
222  vector[2]=points[1].x;
223  vector[3]=points[1].y;
224  vector[4]=points[2].x;
225  vector[5]=points[2].y;
226  vector[6]=points[3].x;
227  vector[7]=points[3].y;
228  return(GaussJordanElimination(matrix,8,vector));
229}
230
231static MagickBooleanType SolvePerspectiveDistortion(
232  const unsigned long number_points,const PointInfo *points,double **matrix,
233  double *vector)
234{
235  /*
236    Given the coordinates of two quadrilaterals:
237      u0,v0, ... u3,v3,   x4,y4, ... x7,y7
238
239    Solve for the 8 coefficients c0..c7 for a perspective distortion:
240       u = ( c0*x + c1*y + c2 ) / ( c6*x + c7*y + 1 )
241       v = ( c3*x + c4*y + c5 ) / ( c6*x + c7*y + 1 )
242   */
243  if (number_points < 8)
244    return(MagickFalse);
245  matrix[0][0]=points[4].x;
246  matrix[0][1]=points[4].y;
247  matrix[0][2]=1.0;
248  matrix[0][6]=(-points[4].x*points[0].x);
249  matrix[0][7]=(-points[4].y*points[0].x);
250  matrix[1][3]=points[4].x;
251  matrix[1][4]=points[4].y;
252  matrix[1][5]=1.0;
253  matrix[1][6]=(-points[4].x*points[0].y);
254  matrix[1][7]=(-points[4].y*points[0].y);
255  matrix[2][0]=points[5].x;
256  matrix[2][1]=points[5].y;
257  matrix[2][2]=1.0;
258  matrix[2][6]=(-points[5].x*points[1].x);
259  matrix[2][7]=(-points[5].y*points[1].x);
260  matrix[3][3]=points[5].x;
261  matrix[3][4]=points[5].y;
262  matrix[3][5]=1.0;
263  matrix[3][6]=(-points[5].x*points[1].y);
264  matrix[3][7]=(-points[5].y*points[1].y);
265  matrix[4][0]=points[6].x;
266  matrix[4][1]=points[6].y;
267  matrix[4][2]=1.0;
268  matrix[4][6]=(-points[6].x*points[2].x);
269  matrix[4][7]=(-points[6].y*points[2].x);
270  matrix[5][3]=points[6].x;
271  matrix[5][4]=points[6].y;
272  matrix[5][5]=1.0;
273  matrix[5][6]=(-points[6].x*points[2].y);
274  matrix[5][7]=(-points[6].y*points[2].y);
275  matrix[6][0]=points[7].x;
276  matrix[6][1]=points[7].y;
277  matrix[6][2]=1.0;
278  matrix[6][6]=(-points[7].x*points[3].x);
279  matrix[6][7]=(-points[7].y*points[3].x);
280  matrix[7][3]=points[7].x;
281  matrix[7][4]=points[7].y;
282  matrix[7][5]=1.0;
283  matrix[7][6]=(-points[7].x*points[3].y);
284  matrix[7][7]=(-points[7].y*points[3].y);
285  vector[0]=points[0].x;
286  vector[1]=points[0].y;
287  vector[2]=points[1].x;
288  vector[3]=points[1].y;
289  vector[4]=points[2].x;
290  vector[5]=points[2].y;
291  vector[6]=points[3].x;
292  vector[7]=points[3].y;
293  return(GaussJordanElimination(matrix,8,vector));
294}
295
296static void InvertPerspectiveCoefficients(
297  const double *coefficients,double *inverse)
298{
299  double determinant;
300  /* From "Digital Image Warping" p53 by George Wolberg */
301
302  determinant=1.0/(coefficients[0]*coefficients[4]-coefficients[3]*coefficients[1]);
303  inverse[0]=determinant*(coefficients[4]-coefficients[7]*coefficients[5]);
304  inverse[1]=determinant*(coefficients[7]*coefficients[2]-coefficients[1]);
305  inverse[2]=determinant*(coefficients[1]*coefficients[5]-coefficients[4]*coefficients[2]);
306  inverse[3]=determinant*(coefficients[6]*coefficients[5]-coefficients[3]);
307  inverse[4]=determinant*(coefficients[0]-coefficients[6]*coefficients[2]);
308  inverse[5]=determinant*(coefficients[3]*coefficients[2]-coefficients[0]*coefficients[5]);
309  inverse[6]=determinant*(coefficients[3]*coefficients[7]-coefficients[6]*coefficients[4]);
310  inverse[7]=determinant*(coefficients[6]*coefficients[1]-coefficients[0]*coefficients[7]);
311}
312
313static inline double MagickRound(double x)
314{
315  assert(x >= (1.0*LONG_MIN-0.5));
316  assert(x <= (1.0*LONG_MAX+0.5));
317  if (x >= 0.0)
318    return((double) ((long) (x+0.5)));
319  return((double) ((long) (x-0.5)));
320}
321
322MagickExport Image *DistortImage(Image *image,const DistortImageMethod method,
323  const unsigned long number_arguments,const double *arguments,
324  MagickBooleanType bestfit, ExceptionInfo *exception)
325{
326#define DistortImageTag  "Distort/Image"
327
328  double
329    coefficients[9],
330    validity;
331
332  Image
333    *distort_image;
334
335  register long
336    i,
337    x;
338
339  long
340    j,
341    y;
342
343  PointInfo
344    point;          /* point to sample (center of filtered resample of area) */
345
346  MagickPixelPacket
347    pixel,          /* pixel to assign to distorted image */
348    invalid;  /* the color to assign when distort result is invalid */
349
350  register IndexPacket
351    *indexes;
352
353  register PixelPacket
354    *q;
355
356  ResampleFilter
357    *resample_filter;
358
359  ViewInfo
360    *distort_view;
361
362  MagickBooleanType
363    status;
364
365  RectangleInfo
366    geometry;
367
368  assert(image != (Image *) NULL);
369  assert(image->signature == MagickSignature);
370  if (image->debug != MagickFalse)
371    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
372  assert(exception != (ExceptionInfo *) NULL);
373  assert(exception->signature == MagickSignature);
374  (void) ResetMagickMemory(coefficients,0,sizeof(coefficients));
375
376  /*
377    Convert input arguments into mapping coefficents for distortion
378  */
379  switch (method)
380  {
381    case AffineDistortion:
382    {
383      double
384        *matrix[6];
385
386      PointInfo
387        *points;
388
389      /* Affine Distortion
390
391            u =   c0*x + c2*y + c4
392
393            v =   c1*x + c3*y + c5
394
395         Input Arguments are two sets of control points which are
396         used to generate the above coefficents.  (minimum 3 pairs)
397            u1,v1, x1,y1,  u2,v2, x2,y2,  u3,v3, x3,y3, ...
398      */
399      if (number_arguments != 12)
400        return((Image *) NULL);
401      points=(PointInfo *) AcquireQuantumMemory((number_arguments+1UL)/2UL,
402        sizeof(*points));
403      if (points == (PointInfo *) NULL)
404        ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
405      for (i=0; i < (long) number_arguments; i++)
406        if ((i % 2 ) == 0)
407          points[i/2].x=arguments[i];
408        else
409          points[i/2].y=arguments[i];
410      for (i=0; i < 6; i++)
411      {
412        matrix[i]=(double *) AcquireQuantumMemory(6UL,sizeof(*matrix[i]));
413        if (matrix[i] == (double *) NULL)
414          {
415            for (x=0; x < i; x++)
416              matrix[i]=(double *) RelinquishMagickMemory(matrix[i]);
417            points=(PointInfo *) RelinquishMagickMemory(points);
418            ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
419          }
420        (void) ResetMagickMemory(matrix[i],0,6*sizeof(*matrix[i]));
421      }
422      status=SolveAffineDistortion((number_arguments+1)/2,points,matrix,
423        coefficients);
424      for (i=0; i < 6; i++)
425        matrix[i]=(double *) RelinquishMagickMemory(matrix[i]);
426      points=(PointInfo *) RelinquishMagickMemory(points);
427      break;
428    }
429    case AffineProjectionDistortion:
430    {
431      /*
432        Arguments: Affine Matrix (forward mapping)
433           sx, rx, ry, sy, tx, ty
434      */
435      if (number_arguments != 6)
436        return((Image *) NULL);
437      InvertAffineCoefficients(arguments, coefficients);
438      break;
439    }
440    case BilinearDistortion:
441    {
442      double
443        *matrix[8];
444
445      PointInfo
446        *points;
447
448      /* Bilinear Distortion (reversed)
449
450            u = c0*x + c1*y + c2*x*y + c3;
451
452            v = c4*x + c5*y + c6*x*y + c7;
453
454         Input Arguments are two sets of control points which are
455         used to generate the above coefficents. (minimum 4 pairs)
456      */
457      if (number_arguments != 16)
458        return((Image *) NULL);
459      points=(PointInfo *) AcquireQuantumMemory((number_arguments+1UL)/2UL,
460        sizeof(*points));
461      if (points == (PointInfo *) NULL)
462        ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
463      for (i=0; i < (long) number_arguments; i++)
464        if ((i % 2 ) == 0)
465          points[i/2].x=arguments[i];
466        else
467          points[i/2].y=arguments[i];
468      for (i=0; i < 8; i++)
469      {
470        matrix[i]=(double *) AcquireQuantumMemory(8UL,sizeof(*matrix[i]));
471        if (matrix[i] == (double *) NULL)
472          {
473            for (x=0; x < i; x++)
474              matrix[i]=(double *) RelinquishMagickMemory(matrix[i]);
475            points=(PointInfo *) RelinquishMagickMemory(points);
476            ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
477          }
478        (void) ResetMagickMemory(matrix[i],0,8*sizeof(*matrix[i]));
479      }
480      status=SolveBilinearDistortion((number_arguments+1)/2,points,matrix,
481        coefficients);
482      for (i=0; i < 8; i++)
483        matrix[i]=(double *) RelinquishMagickMemory(matrix[i]);
484      points=(PointInfo *) RelinquishMagickMemory(points);
485      break;
486    }
487    case PerspectiveDistortion:
488    {
489      double
490        *matrix[8];
491
492      PointInfo
493        *points;
494
495      /* Perspective Distortion (a ratio of affine distortions)
496
497                 p     c0*x + c1*y + c2
498            u = --- = ------------------
499                 r     c6*x + c7*y + 1
500
501                 q     c3*x + c4*y + c5
502            v = --- = ------------------
503                 r     c6*x + c7*y + 1
504
505            c8 = sign of 'r' which determines what part of the distorted image
506                 is 'ground' side of the horizon (on which the image sits)
507
508         Input Arguments are two sets of control points which are
509         used to generate the above coefficents. (minimum 4 pairs)
510      */
511      if (number_arguments != 16)
512        return((Image *) NULL);
513      points=(PointInfo *) AcquireQuantumMemory((number_arguments+1UL)/2UL,
514        sizeof(*points));
515      if (points == (PointInfo *) NULL)
516        ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
517      for (i=0; i < (long) number_arguments; i++)
518        if ((i % 2 ) == 0)
519          points[i/2].x=arguments[i];
520        else
521          points[i/2].y=arguments[i];
522      for (i=0; i < 8; i++)
523      {
524        matrix[i]=(double *) AcquireQuantumMemory(8UL,sizeof(*matrix[i]));
525        if (matrix[i] == (double *) NULL)
526          {
527            for (x=0; x < i; x++)
528              matrix[i]=(double *) RelinquishMagickMemory(matrix[i]);
529            points=(PointInfo *) RelinquishMagickMemory(points);
530            ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
531          }
532        (void) ResetMagickMemory(matrix[i],0,8*sizeof(*matrix[i]));
533      }
534      status=SolvePerspectiveDistortion((number_arguments+1)/2,points,matrix,
535        coefficients);
536      for (i=0; i < 8; i++)
537        matrix[i]=(double *) RelinquishMagickMemory(matrix[i]);
538      points=(PointInfo *) RelinquishMagickMemory(points);
539      /*
540        What is the 'ground' of the perspective distortion.
541        Just find the sign of 'r' for any given distorted coordinate.
542      */
543      coefficients[8] = coefficients[6]*arguments[number_arguments-2]
544                  + coefficients[7]*arguments[number_arguments-1] + 1.0;
545      coefficients[8] = (coefficients[8] < 0.0) ? -1.0 : +1.0;
546      break;
547    }
548    case PerspectiveProjectionDistortion:
549    {
550      /*
551        Arguments: Perspective Coefficents (forward mapping)
552      */
553      if (number_arguments != 8)
554        return((Image *) NULL);
555      InvertPerspectiveCoefficients(arguments, coefficients);
556      /*
557        What is the 'ground' of the perspective distortion.
558        For a forward mapped perspective the images 0,0 coord will map to
559          c2,c5  in the distorted image get the sign of 'r' of that.
560      */
561      coefficients[8] = coefficients[6]*arguments[2]
562                  + coefficients[7]*arguments[5] + 1.0;
563      coefficients[8] = (coefficients[8] < 0.0) ? -1.0 : +1.0;
564      break;
565    }
566    case ScaleRotateTranslateDistortion:
567    {
568      double
569        cosine, sine,
570        x,y,sx,sy,a,nx,ny;
571
572      /*
573         Argument options, by number of arguments given:
574           7: x,y, sx,sy, a, nx,ny
575           6: x,y,   s,   a, nx,ny
576           5: x,y, sx,sy, a
577           4: x,y,   s,   a
578           3: x,y,        a
579           2:        s,   a
580           1:             a
581         Where actions are (in order of application)
582            x,y     'center' of transforms     (default = image center)
583            sx,sy   scale image by this amount (default = 1)
584            a       angle of rotation          (argument required)
585            nx,ny   move 'center' here         (default = no movement)
586         And convert to affine mapping coefficients
587      */
588      x = nx = (double)image->rows/2.0;
589      y = ny = (double)image->columns/2.0;
590      if ( bestfit ) {
591        x = nx += (double)image->page.x;
592        y = ny += (double)image->page.y;
593      }
594      sx = sy = 1.0;
595      switch ( number_arguments ) {
596      case 0:
597        return((Image *) NULL);
598      case 1:
599        a = arguments[0];
600        break;
601      case 2:
602        sx = sy = arguments[0];
603        a = arguments[1];
604        break;
605      default:
606        x = nx = arguments[0];
607        y = ny = arguments[1];
608        switch ( number_arguments ) {
609        case 3:
610          a = arguments[2];
611          break;
612        case 4:
613          sx = sy = arguments[2];
614          a = arguments[3];
615          break;
616        case 5:
617          sx = arguments[2];
618          sy = arguments[3];
619          a = arguments[4];
620          break;
621        case 6:
622          sx = sy = arguments[2];
623          a = arguments[3];
624          nx = arguments[4];
625          ny = arguments[5];
626          break;
627        case 7:
628          sx = arguments[2];
629          sy = arguments[3];
630          a = arguments[4];
631          nx = arguments[5];
632          ny = arguments[6];
633          break;
634        default:
635          return((Image *) NULL);
636        }
637        break;
638      }
639      a=DegreesToRadians(a);
640      cosine=cos(a);
641      sine=sin(a);
642      coefficients[0]=cosine/sx;
643      coefficients[1]=(-sine)/sy;
644      coefficients[2]=sine/sx;
645      coefficients[3]=cosine/sy;
646      coefficients[4]=x-nx*coefficients[0]-ny*coefficients[2];
647      coefficients[5]=y-nx*coefficients[1]-ny*coefficients[3];
648      break;
649    }
650    case ArcDistortion:
651    {
652      /* Arc Distortion
653         Args: arc_width  rotate  top_edge_radius  bottom_edge_radius
654         All but first argument are optional
655            arc_width      The angle over which to arc the image side-to-side
656            rotate         Angle to rotate image from vertical center
657            top_radius     Set top edge of source image at this radius
658            bottom_radius  Set bootom edge to this radius (radial scaling)
659
660         By default, if the radii arguments are nor provided the image radius
661         is calculated so the horizontal center-line is fits the given arc
662         without scaling.
663
664         The output image size is ALWAYS adjusted to contain the whole image,
665         and an offset is given to position image relative to the 0,0 point of
666         the origin, allowing users to use relative positioning onto larger
667         background (via -flatten).
668
669         The arguments are converted to these coefficents
670            c0: angle for center of source image
671            c1: angle scale for mapping to source image
672            c2: radius for top of source image
673            c3: radius scale for mapping source image
674            c4: centerline of arc within source image
675
676         Note the coefficents use a center angle, so asymptotic join is
677         furthest from both sides of the source image. This also means that
678         for arc angles greater than 360 the sides of the image will be
679         trimmed equally.
680      */
681      if ( number_arguments >= 1 && arguments[0] < MagickEpsilon )
682        return((Image *) NULL);
683      if ( number_arguments >= 3 && arguments[2] < MagickEpsilon )
684        return((Image *) NULL);
685      coefficients[0] = -MagickPI/2.0;
686      if ( number_arguments >= 1 )
687        coefficients[1] = DegreesToRadians(arguments[0]);
688      else
689        coefficients[1] = MagickPI/2.0;
690      if ( number_arguments >= 2 )
691        coefficients[0] += DegreesToRadians(arguments[1]);
692      coefficients[0] -= MagickRound(coefficients[0]/(2.0*MagickPI))
693                             *2.0*MagickPI;
694      coefficients[3] = 1.0*image->rows-1;
695      coefficients[2] = 1.0*image->columns/coefficients[1] + coefficients[3]/2.0;
696      if ( number_arguments >= 3 ) {
697        if ( number_arguments >= 4 )
698          coefficients[3] = arguments[2] - arguments[3];
699        else
700          coefficients[3] *= arguments[2]/coefficients[2];
701        coefficients[2] = arguments[2];
702      }
703      coefficients[4] = (1.0*image->columns-1.0)/2.0;
704      /* Always work out the 'best fit' for Arc Distort (required) */
705      bestfit = MagickTrue;
706      break;
707    }
708    default:
709      break;
710  }
711
712  /*
713    Determine the size and offset for a 'bestfit' destination.
714    Usally the four corners of the source image is enough.
715  */
716  geometry.width=image->columns;
717  geometry.height=image->rows;
718  geometry.x=image->page.x;
719  geometry.y=image->page.y;
720  point.x=0.0;
721  point.y=0.0;
722
723  if ( bestfit ) {
724    double
725      min_x,max_x,min_y,max_y;
726
727/* defines to figure out the bounds of the distorted image */
728#define InitalBounds(px,py) \
729{ \
730  min_x = max_x = (px); \
731  min_y = max_y = (py); \
732}
733#define ExpandBounds(px,py) \
734{ \
735  if ( (px) < min_x )  min_x = (px); \
736  if ( (px) > max_x )  max_x = (px); \
737  if ( (py) < min_y )  min_y = (py); \
738  if ( (py) > max_y )  max_y = (py); \
739}
740
741    switch (method)
742    {
743      case AffineDistortion:
744      case AffineProjectionDistortion:
745      case ScaleRotateTranslateDistortion:
746      { double inverse[6];
747        InvertAffineCoefficients(coefficients, inverse);
748        x = geometry.x;  y = geometry.y;
749        point.x=inverse[0]*x+inverse[2]*y+inverse[4];
750        point.y=inverse[1]*x+inverse[3]*y+inverse[5];
751        InitalBounds( point.x, point.y );
752        x = geometry.x+geometry.width-1;  y = geometry.y;
753        point.x=inverse[0]*x+inverse[2]*y+inverse[4];
754        point.y=inverse[1]*x+inverse[3]*y+inverse[5];
755        ExpandBounds( point.x, point.y );
756        x = geometry.x;  y = geometry.y+geometry.height-1;
757        point.x=inverse[0]*x+inverse[2]*y+inverse[4];
758        point.y=inverse[1]*x+inverse[3]*y+inverse[5];
759        ExpandBounds( point.x, point.y );
760        x = geometry.x+geometry.width-1;  y = geometry.y+geometry.height-1;
761        point.x=inverse[0]*x+inverse[2]*y+inverse[4];
762        point.y=inverse[1]*x+inverse[3]*y+inverse[5];
763        ExpandBounds( point.x, point.y );
764        break;
765      }
766      case PerspectiveDistortion:
767      case PerspectiveProjectionDistortion:
768      { double inverse[8], scale;
769        InvertPerspectiveCoefficients(coefficients, inverse);
770        x = geometry.x;  y = geometry.y;
771        scale=inverse[6]*x+inverse[7]*y+1.0;
772        scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
773        point.x=scale*(inverse[0]*x+inverse[1]*y+inverse[2]);
774        point.y=scale*(inverse[3]*x+inverse[4]*y+inverse[5]);
775        InitalBounds( point.x, point.y );
776
777        x = geometry.x+geometry.width-1;  y = geometry.y;
778        scale=inverse[6]*x+inverse[7]*y+1.0;
779        scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
780        point.x=scale*(inverse[0]*x+inverse[1]*y+inverse[2]);
781        point.y=scale*(inverse[3]*x+inverse[4]*y+inverse[5]);
782        ExpandBounds( point.x, point.y );
783
784        x = geometry.x;  y = geometry.y+geometry.height-1;
785        scale=inverse[6]*x+inverse[7]*y+1.0;
786        scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
787        point.x=scale*(inverse[0]*x+inverse[1]*y+inverse[2]);
788        point.y=scale*(inverse[3]*x+inverse[4]*y+inverse[5]);
789        ExpandBounds( point.x, point.y );
790
791        x = geometry.x+geometry.width-1;  y = geometry.y+geometry.height-1;
792        scale=inverse[6]*x+inverse[7]*y+1.0;
793        scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
794        point.x=scale*(inverse[0]*x+inverse[1]*y+inverse[2]);
795        point.y=scale*(inverse[3]*x+inverse[4]*y+inverse[5]);
796        ExpandBounds( point.x, point.y );
797        break;
798      }
799      case ArcDistortion:
800      { double a, ca, sa;
801        /* Forward Map Corners */
802        a = coefficients[0]-coefficients[1]/2; ca = cos(a); sa = sin(a);
803        point.x = coefficients[2]*ca;
804        point.y = coefficients[2]*sa;
805        InitalBounds( point.x, point.y );
806        point.x = (coefficients[2]-coefficients[3])*ca;
807        point.y = (coefficients[2]-coefficients[3])*sa;
808        ExpandBounds( point.x, point.y );
809        a = coefficients[0]+coefficients[1]/2; ca = cos(a); sa = sin(a);
810        point.x = coefficients[2]*ca;
811        point.y = coefficients[2]*sa;
812        ExpandBounds( point.x, point.y );
813        point.x = (coefficients[2]-coefficients[3])*ca;
814        point.y = (coefficients[2]-coefficients[3])*sa;
815        ExpandBounds( point.x, point.y );
816        /* orthogonal points along top of arc */
817        for( a=ceil((coefficients[0]-coefficients[1]/2.0)*2.0/MagickPI)
818                              *MagickPI/2.0;
819               a<(coefficients[0]+coefficients[1]/2.0); a+=MagickPI/2.0 ) {
820          ca = cos(a); sa = sin(a);
821          point.x = coefficients[2]*ca;
822          point.y = coefficients[2]*sa;
823          ExpandBounds( point.x, point.y );
824        }
825        /*
826          Convert the angle_to_width and radius_to_height
827          to appropriate scaling factors, to allow faster processing
828          in the mapping function.
829        */
830        coefficients[1] = 2.0*MagickPI*image->columns/coefficients[1];
831        coefficients[3] = 1.0*image->rows/coefficients[3];
832        break;
833      }
834      case BilinearDistortion:
835      default:
836        /* no bestfit available for this distortion YET */
837        bestfit = MagickFalse;
838    }
839    if ( bestfit ) {
840      geometry.x=(long) floor(min_x-MagickEpsilon);
841      geometry.y=(long) floor(min_y-MagickEpsilon);
842      geometry.width=(unsigned long) ceil(max_x-geometry.x+1+MagickEpsilon);
843      geometry.height=(unsigned long) ceil(max_y-geometry.y+1+MagickEpsilon);
844    }
845  }
846
847  /*
848    Initialize the distort image attributes.
849  */
850  distort_image=CloneImage(image,geometry.width,geometry.height,MagickTrue,
851        exception);
852  if (distort_image == (Image *) NULL)
853    return((Image *) NULL);
854  if (SetImageStorageClass(distort_image,DirectClass) == MagickFalse)
855    {
856      InheritException(exception,&distort_image->exception);
857      distort_image=DestroyImage(distort_image);
858      return((Image *) NULL);
859    }
860  distort_image->page.x=geometry.x;
861  distort_image->page.y=geometry.y;
862  if (distort_image->background_color.opacity != OpaqueOpacity)
863    distort_image->matte=MagickTrue;
864
865  if ( !bestfit ) {
866    geometry.x = geometry.y = 0;
867  }
868
869  /* Open Image views as needed. */
870  resample_filter=AcquireResampleFilter(image,exception);
871  GetMagickPixelPacket(distort_image,&pixel);
872  distort_view=OpenCacheView(distort_image);
873
874  /* Define constant scaling vectors for some distortions */
875  switch (method)
876  {
877    case AffineDistortion:
878    case AffineProjectionDistortion:
879    case ScaleRotateTranslateDistortion:
880      ScaleResampleFilter( resample_filter,
881        coefficients[0], coefficients[2],
882        coefficients[1], coefficients[3] );
883      break;
884    default:
885      ScaleResampleFilter(resample_filter, 1.0, 0.0, 0.0, 1.0);
886      break;
887  }
888
889  /* Initialize default pixel validity
890   *    negative:         pixel is invalid  output 'matte_color'
891   *    0.0 to 1.0:       antialiased, mix with resample output
892   *    1.0 or greater:   use resampled output.
893   */
894  validity = 1.0;
895  GetMagickPixelPacket(distort_image,&invalid);
896  SetMagickPixelPacket(distort_image, &distort_image->matte_color,
897             (IndexPacket *) NULL, &invalid);
898  if (distort_image->colorspace == CMYKColorspace)
899        ConvertRGBToCMYK(&invalid);   /* what about other color spaces? */
900
901  /* Sample the source image to each pixel in the distort image.  */
902  for (y=0; y < (long) distort_image->rows; y++)
903  {
904    j = y+geometry.y;
905    q=SetCacheView(distort_view,0,y,distort_image->columns,1);
906    if (q == (PixelPacket *) NULL)
907      break;
908    indexes=GetIndexes(distort_image);
909    for (x=0; x < (long) distort_image->columns; x++)
910    {
911      i = x+geometry.x;
912      switch (method)
913      {
914        case AffineDistortion:
915        case AffineProjectionDistortion:
916        case ScaleRotateTranslateDistortion:
917        {
918          point.x=coefficients[0]*i+coefficients[2]*j+coefficients[4];
919          point.y=coefficients[1]*i+coefficients[3]*j+coefficients[5];
920          /* Affine partical derivitives are constant -- set above */
921          break;
922        }
923        case BilinearDistortion:
924        {
925          point.x=coefficients[0]*i+coefficients[1]*j+coefficients[2]*i*j+
926            coefficients[3];
927          point.y=coefficients[4]*i+coefficients[5]*j+coefficients[6]*i*j+
928            coefficients[7];
929          /* Bilinear partical derivitives of scaling vectors */
930          ScaleResampleFilter( resample_filter,
931              coefficients[0] + coefficients[2]*j,
932              coefficients[1] + coefficients[2]*i,
933              coefficients[4] + coefficients[6]*j,
934              coefficients[5] + coefficients[6]*i );
935          break;
936        }
937        case PerspectiveDistortion:
938        case PerspectiveProjectionDistortion:
939        {
940          double
941            p,q,r,abs_r,abs_c6,abs_c7,scale;
942          /* perspective is a ratio of affines */
943          p=coefficients[0]*i+coefficients[1]*j+coefficients[2];
944          q=coefficients[3]*i+coefficients[4]*j+coefficients[5];
945          r=coefficients[6]*i+coefficients[7]*j+1.0;
946          /* Pixel Validity -- is it a 'sky' or 'ground' pixel */
947          validity = (r*coefficients[8] < 0.0) ? 0.0 : 1.0;
948          /* Determine horizon anti-aliase blending */
949          abs_r = fabs(r)*2;
950          abs_c6 = fabs(coefficients[6]);
951          abs_c7 = fabs(coefficients[7]);
952          if ( abs_c6 > abs_c7 ) {
953            if ( abs_r < abs_c6 )
954              validity = 0.5 - coefficients[8]*r/coefficients[6];
955          }
956          else if ( abs_r < abs_c7 )
957            validity = .5 - coefficients[8]*r/coefficients[7];
958          /* Perspective Sampling Point (if valid) */
959          if ( validity > 0.0 ) {
960            scale = 1.0/r;
961            point.x = p*scale;
962            point.y = q*scale;
963            /* Perspective Partial Derivatives or Scaling Vectors */
964            scale *= scale;
965            ScaleResampleFilter( resample_filter,
966              (r*coefficients[0] - p*coefficients[6])*scale,
967              (r*coefficients[1] - p*coefficients[7])*scale,
968              (r*coefficients[3] - q*coefficients[6])*scale,
969              (r*coefficients[4] - q*coefficients[7])*scale );
970          }
971          break;
972        }
973        case ArcDistortion:
974        {
975          point.x = (atan2(1.0*j,1.0*i) - coefficients[0])/(2*MagickPI);
976          point.x -= MagickRound(point.x);
977          point.x = point.x*coefficients[1] + coefficients[4];
978          point.y = coefficients[2] - sqrt(1.0*i*i+j*j);
979          point.y *= coefficients[3];
980          /* FUTURE: determine partial derivities / scaling vectors */
981          break;
982        }
983        default:
984        {
985          /*
986            Noop distortion (failsafe).
987          */
988          point.x=(double) x;
989          point.y=(double) y;
990          break;
991        }
992      }
993      if ( bestfit && method != ArcDistortion ) {
994        point.x -= image->page.x;
995        point.y -= image->page.y;
996      }
997
998      if ( validity <= 0.0 ) {
999        /* result of distortion is an invalid pixel - don't resample */
1000        SetPixelPacket(distort_image,&invalid,q,indexes);
1001      }
1002      else {
1003        /* resample the source image to find its correct color */
1004        pixel=ResamplePixelColor(resample_filter,point.x,point.y);
1005        /* if validity between 0.0 and 1.0 mix result with invalid pixel */
1006        if ( validity < 1.0 ) {
1007          /* Do a blend of sample color and invalid pixel */
1008          /* should this be a 'Blend', or an 'Over' compose */
1009          MagickPixelCompositeBlend(&pixel, validity,
1010               &invalid, (1.0-validity), &pixel);
1011        }
1012        SetPixelPacket(distort_image,&pixel,q,indexes);
1013      }
1014      q++;
1015      indexes++;
1016    }
1017    if (SyncImagePixels(distort_image) == MagickFalse)
1018      break;
1019    if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
1020        (QuantumTick(y,image->rows) != MagickFalse