13ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/* 23ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 33ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 43ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 53ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 63ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% DDDD IIIII SSSSS TTTTT OOO RRRR TTTTT % 73ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% D D I SS T O O R R T % 83ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% D D I SSS T O O RRRR T % 93ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% D D I SS T O O R R T % 103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% DDDD IIIII SSSSS T OOO R R T % 113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% MagickCore Image Distortion Methods % 143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Software Design % 16de984cdc3631106b1cbbb8d3972b76a0fc27e8e8cristy% Cristy % 173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Anthony Thyssen % 183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% June 2007 % 193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 217ce65e7125a4e1df1a274ce373c537a9df9c16cdCristy% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % 223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% dedicated to making software imaging solutions freely available. % 233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% You may not use this file except in compliance with the License. You may % 253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% obtain a copy of the License at % 263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% http://www.imagemagick.org/script/license.php % 283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Unless required by applicable law or agreed to in writing, software % 303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% distributed under the License is distributed on an "AS IS" BASIS, % 313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% See the License for the specific language governing permissions and % 333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% limitations under the License. % 343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/ 393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/* 413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Include declarations. 423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/ 434c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/studio.h" 444c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/artifact.h" 454c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/cache.h" 464c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/cache-view.h" 476a2180cee55312a7c0c633670803f9face88a82acristy#include "MagickCore/channel.h" 484c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/colorspace-private.h" 494c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/composite-private.h" 504c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/distort.h" 514c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception.h" 524c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception-private.h" 534c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/gem.h" 544c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image.h" 55abed7e293f2e8a83e8036df7f2a3e1d9859e5fb2dirk#include "MagickCore/linked-list.h" 564c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/list.h" 574c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/matrix.h" 58d1dd6e4fefa0810b9893e6ac9418f79c97c1b39acristy#include "MagickCore/matrix-private.h" 594c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/memory_.h" 604c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor-private.h" 614c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/option.h" 624c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel.h" 634c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel-accessor.h" 6435f1530f0591e7380a976a606080774c28bc4da2cristy#include "MagickCore/pixel-private.h" 654c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/resample.h" 664c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/resample-private.h" 674c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/registry.h" 68ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy#include "MagickCore/resource_.h" 694c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/semaphore.h" 70b9514f21a501293847bd9ccb2de0c3784cc6a250cristy#include "MagickCore/shear.h" 714c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string_.h" 724c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string-private.h" 734c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/thread-private.h" 744c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/token.h" 754c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/transform.h" 763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/* 783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Numerous internal routines for image distortions. 793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/ 803ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic inline void AffineArgsToCoefficients(double *affine) 813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* map external sx,ry,rx,sy,tx,ty to internal c0,c2,c4,c1,c3,c5 */ 833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double tmp[4]; /* note indexes 0 and 5 remain unchanged */ 843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy tmp[0]=affine[1]; tmp[1]=affine[2]; tmp[2]=affine[3]; tmp[3]=affine[4]; 853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy affine[3]=tmp[0]; affine[1]=tmp[1]; affine[4]=tmp[2]; affine[2]=tmp[3]; 863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 8739052fff02d6a281e1837737e345ecfcfe7cf60fcristy 883ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic inline void CoefficientsToAffineArgs(double *coeff) 893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* map internal c0,c1,c2,c3,c4,c5 to external sx,ry,rx,sy,tx,ty */ 913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double tmp[4]; /* note indexes 0 and 5 remain unchanged */ 923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy tmp[0]=coeff[3]; tmp[1]=coeff[1]; tmp[2]=coeff[4]; tmp[3]=coeff[2]; 933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[1]=tmp[0]; coeff[2]=tmp[1]; coeff[3]=tmp[2]; coeff[4]=tmp[3]; 943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 953ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic void InvertAffineCoefficients(const double *coeff,double *inverse) 963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* From "Digital Image Warping" by George Wolberg, page 50 */ 983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double determinant; 993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1003e3ec3afbb0782697f201cbe30a56794c10dc7efcristy determinant=PerceptibleReciprocal(coeff[0]*coeff[4]-coeff[1]*coeff[3]); 1013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse[0]=determinant*coeff[4]; 1023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse[1]=determinant*(-coeff[1]); 1033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse[2]=determinant*(coeff[1]*coeff[5]-coeff[2]*coeff[4]); 1043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse[3]=determinant*(-coeff[3]); 1053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse[4]=determinant*coeff[0]; 1063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse[5]=determinant*(coeff[2]*coeff[3]-coeff[0]*coeff[5]); 1073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 1083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1093ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic void InvertPerspectiveCoefficients(const double *coeff, 1103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double *inverse) 1113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 1123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* From "Digital Image Warping" by George Wolberg, page 53 */ 1133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double determinant; 1143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1153e3ec3afbb0782697f201cbe30a56794c10dc7efcristy determinant=PerceptibleReciprocal(coeff[0]*coeff[4]-coeff[3]*coeff[1]); 1163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse[0]=determinant*(coeff[4]-coeff[7]*coeff[5]); 1173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse[1]=determinant*(coeff[7]*coeff[2]-coeff[1]); 1183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse[2]=determinant*(coeff[1]*coeff[5]-coeff[4]*coeff[2]); 1193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse[3]=determinant*(coeff[6]*coeff[5]-coeff[3]); 1203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse[4]=determinant*(coeff[0]-coeff[6]*coeff[2]); 1213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse[5]=determinant*(coeff[3]*coeff[2]-coeff[0]*coeff[5]); 1223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse[6]=determinant*(coeff[3]*coeff[7]-coeff[6]*coeff[4]); 1233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse[7]=determinant*(coeff[6]*coeff[1]-coeff[0]*coeff[7]); 1243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 1253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1265056b230558c7de0a79d51d82bdc929fef45a225anthony/* 1275056b230558c7de0a79d51d82bdc929fef45a225anthony * Polynomial Term Defining Functions 1285056b230558c7de0a79d51d82bdc929fef45a225anthony * 1295056b230558c7de0a79d51d82bdc929fef45a225anthony * Order must either be an integer, or 1.5 to produce 130972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas * the 2 number_valuesal polynomial function... 131972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas * affine 1 (3) u = c0 + c1*x + c2*y 132972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas * bilinear 1.5 (4) u = '' + c3*x*y 133972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas * quadratic 2 (6) u = '' + c4*x*x + c5*y*y 134972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas * cubic 3 (10) u = '' + c6*x^3 + c7*x*x*y + c8*x*y*y + c9*y^3 135972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas * quartic 4 (15) u = '' + c10*x^4 + ... + c14*y^4 136972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas * quintic 5 (21) u = '' + c15*x^5 + ... + c20*y^5 1375056b230558c7de0a79d51d82bdc929fef45a225anthony * number in parenthesis minimum number of points needed. 1385056b230558c7de0a79d51d82bdc929fef45a225anthony * Anything beyond quintic, has not been implemented until 1390c63ece53c43017de0184b16fe8cb6e5b58ad51bnicolas * a more automated way of determining terms is found. 1405056b230558c7de0a79d51d82bdc929fef45a225anthony 1415056b230558c7de0a79d51d82bdc929fef45a225anthony * Note the slight re-ordering of the terms for a quadratic polynomial 1425056b230558c7de0a79d51d82bdc929fef45a225anthony * which is to allow the use of a bi-linear (order=1.5) polynomial. 1435056b230558c7de0a79d51d82bdc929fef45a225anthony * All the later polynomials are ordered simply from x^N to y^N 1445056b230558c7de0a79d51d82bdc929fef45a225anthony */ 145bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic size_t poly_number_terms(double order) 1463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 1475056b230558c7de0a79d51d82bdc929fef45a225anthony /* Return the number of terms for a 2d polynomial */ 1483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( order < 1 || order > 5 || 1493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ( order != floor(order) && (order-1.5) > MagickEpsilon) ) 1503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return 0; /* invalid polynomial order */ 151bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy return((size_t) floor((order+1)*(order+2)/2)); 1523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 1533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 154bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic double poly_basis_fn(ssize_t n, double x, double y) 1553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 1565056b230558c7de0a79d51d82bdc929fef45a225anthony /* Return the result for this polynomial term */ 1573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy switch(n) { 1583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 0: return( 1.0 ); /* constant */ 1593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 1: return( x ); 160972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas case 2: return( y ); /* affine order = 1 terms = 3 */ 161972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas case 3: return( x*y ); /* bilinear order = 1.5 terms = 4 */ 1623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 4: return( x*x ); 163972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas case 5: return( y*y ); /* quadratic order = 2 terms = 6 */ 1643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 6: return( x*x*x ); 1653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 7: return( x*x*y ); 1663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 8: return( x*y*y ); 167972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas case 9: return( y*y*y ); /* cubic order = 3 terms = 10 */ 1683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 10: return( x*x*x*x ); 1693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 11: return( x*x*x*y ); 1703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 12: return( x*x*y*y ); 1713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 13: return( x*y*y*y ); 1723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 14: return( y*y*y*y ); /* quartic order = 4 terms = 15 */ 1733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 15: return( x*x*x*x*x ); 1743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 16: return( x*x*x*x*y ); 1753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 17: return( x*x*x*y*y ); 1763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 18: return( x*x*y*y*y ); 1773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 19: return( x*y*y*y*y ); 178972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas case 20: return( y*y*y*y*y ); /* quintic order = 5 terms = 21 */ 1793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 1803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return( 0 ); /* should never happen */ 1813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 182bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic const char *poly_basis_str(ssize_t n) 1833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 1843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* return the result for this polynomial term */ 1853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy switch(n) { 1863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 0: return(""); /* constant */ 1873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 1: return("*ii"); 188972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas case 2: return("*jj"); /* affine order = 1 terms = 3 */ 189972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas case 3: return("*ii*jj"); /* bilinear order = 1.5 terms = 4 */ 1903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 4: return("*ii*ii"); 191972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas case 5: return("*jj*jj"); /* quadratic order = 2 terms = 6 */ 1923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 6: return("*ii*ii*ii"); 1933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 7: return("*ii*ii*jj"); 1943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 8: return("*ii*jj*jj"); 195972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas case 9: return("*jj*jj*jj"); /* cubic order = 3 terms = 10 */ 1963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 10: return("*ii*ii*ii*ii"); 1973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 11: return("*ii*ii*ii*jj"); 1983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 12: return("*ii*ii*jj*jj"); 1993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 13: return("*ii*jj*jj*jj"); 200972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas case 14: return("*jj*jj*jj*jj"); /* quartic order = 4 terms = 15 */ 2013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 15: return("*ii*ii*ii*ii*ii"); 2023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 16: return("*ii*ii*ii*ii*jj"); 2033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 17: return("*ii*ii*ii*jj*jj"); 2043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 18: return("*ii*ii*jj*jj*jj"); 2053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 19: return("*ii*jj*jj*jj*jj"); 206972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas case 20: return("*jj*jj*jj*jj*jj"); /* quintic order = 5 terms = 21 */ 2073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 2083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return( "UNKNOWN" ); /* should never happen */ 2093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 210bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic double poly_basis_dx(ssize_t n, double x, double y) 2113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 2123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* polynomial term for x derivative */ 2133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy switch(n) { 2143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 0: return( 0.0 ); /* constant */ 2153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 1: return( 1.0 ); 2163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 2: return( 0.0 ); /* affine order = 1 terms = 3 */ 2173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 3: return( y ); /* bilinear order = 1.5 terms = 4 */ 2183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 4: return( x ); 2193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 5: return( 0.0 ); /* quadratic order = 2 terms = 6 */ 2203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 6: return( x*x ); 2213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 7: return( x*y ); 2223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 8: return( y*y ); 2233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 9: return( 0.0 ); /* cubic order = 3 terms = 10 */ 2243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 10: return( x*x*x ); 2253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 11: return( x*x*y ); 2263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 12: return( x*y*y ); 2273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 13: return( y*y*y ); 2283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 14: return( 0.0 ); /* quartic order = 4 terms = 15 */ 2293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 15: return( x*x*x*x ); 2303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 16: return( x*x*x*y ); 2313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 17: return( x*x*y*y ); 2323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 18: return( x*y*y*y ); 2333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 19: return( y*y*y*y ); 2343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 20: return( 0.0 ); /* quintic order = 5 terms = 21 */ 2353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 2363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return( 0.0 ); /* should never happen */ 2373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 238bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic double poly_basis_dy(ssize_t n, double x, double y) 2393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 2403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* polynomial term for y derivative */ 2413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy switch(n) { 2423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 0: return( 0.0 ); /* constant */ 2433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 1: return( 0.0 ); 2443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 2: return( 1.0 ); /* affine order = 1 terms = 3 */ 2453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 3: return( x ); /* bilinear order = 1.5 terms = 4 */ 2463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 4: return( 0.0 ); 2473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 5: return( y ); /* quadratic order = 2 terms = 6 */ 2483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy default: return( poly_basis_dx(n-1,x,y) ); /* weird but true */ 2493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 250972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas /* NOTE: the only reason that last is not true for 'quadratic' 2513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy is due to the re-arrangement of terms to allow for 'bilinear' 2523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 2533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 2543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 2553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/* 2563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 2583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 2593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 260987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% A f f i n e T r a n s f o r m I m a g e % 261987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% % 262987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% % 263987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% % 264987feef6c1e3d08da3d9458fa5c464a32fc30191cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 265987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 266987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% AffineTransformImage() transforms an image as dictated by the affine matrix. 267987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% It allocates the memory necessary for the new Image structure and returns 268987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% a pointer to the new image. 269987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 270987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% The format of the AffineTransformImage method is: 271987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 272987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% Image *AffineTransformImage(const Image *image, 273987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% AffineMatrix *affine_matrix,ExceptionInfo *exception) 274987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 275987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% A description of each parameter follows: 276987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 277987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% o image: the image. 278987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 279987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% o affine_matrix: the affine matrix. 280987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 281987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% o exception: return any errors or warnings in this structure. 282987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 283987feef6c1e3d08da3d9458fa5c464a32fc30191cristy*/ 284987feef6c1e3d08da3d9458fa5c464a32fc30191cristyMagickExport Image *AffineTransformImage(const Image *image, 285987feef6c1e3d08da3d9458fa5c464a32fc30191cristy const AffineMatrix *affine_matrix,ExceptionInfo *exception) 286987feef6c1e3d08da3d9458fa5c464a32fc30191cristy{ 287987feef6c1e3d08da3d9458fa5c464a32fc30191cristy double 288987feef6c1e3d08da3d9458fa5c464a32fc30191cristy distort[6]; 289987feef6c1e3d08da3d9458fa5c464a32fc30191cristy 290987feef6c1e3d08da3d9458fa5c464a32fc30191cristy Image 291987feef6c1e3d08da3d9458fa5c464a32fc30191cristy *deskew_image; 292987feef6c1e3d08da3d9458fa5c464a32fc30191cristy 293987feef6c1e3d08da3d9458fa5c464a32fc30191cristy /* 294987feef6c1e3d08da3d9458fa5c464a32fc30191cristy Affine transform image. 295987feef6c1e3d08da3d9458fa5c464a32fc30191cristy */ 296e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(image->signature == MagickCoreSignature); 297987feef6c1e3d08da3d9458fa5c464a32fc30191cristy if (image->debug != MagickFalse) 298987feef6c1e3d08da3d9458fa5c464a32fc30191cristy (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 299987feef6c1e3d08da3d9458fa5c464a32fc30191cristy assert(affine_matrix != (AffineMatrix *) NULL); 300987feef6c1e3d08da3d9458fa5c464a32fc30191cristy assert(exception != (ExceptionInfo *) NULL); 301e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(exception->signature == MagickCoreSignature); 302987feef6c1e3d08da3d9458fa5c464a32fc30191cristy distort[0]=affine_matrix->sx; 303987feef6c1e3d08da3d9458fa5c464a32fc30191cristy distort[1]=affine_matrix->rx; 304987feef6c1e3d08da3d9458fa5c464a32fc30191cristy distort[2]=affine_matrix->ry; 305987feef6c1e3d08da3d9458fa5c464a32fc30191cristy distort[3]=affine_matrix->sy; 306987feef6c1e3d08da3d9458fa5c464a32fc30191cristy distort[4]=affine_matrix->tx; 307987feef6c1e3d08da3d9458fa5c464a32fc30191cristy distort[5]=affine_matrix->ty; 308987feef6c1e3d08da3d9458fa5c464a32fc30191cristy deskew_image=DistortImage(image,AffineProjectionDistortion,6,distort, 309987feef6c1e3d08da3d9458fa5c464a32fc30191cristy MagickTrue,exception); 310987feef6c1e3d08da3d9458fa5c464a32fc30191cristy return(deskew_image); 311987feef6c1e3d08da3d9458fa5c464a32fc30191cristy} 312987feef6c1e3d08da3d9458fa5c464a32fc30191cristy 313987feef6c1e3d08da3d9458fa5c464a32fc30191cristy/* 314987feef6c1e3d08da3d9458fa5c464a32fc30191cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 315987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% % 316987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% % 317987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% % 3183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy+ G e n e r a t e C o e f f i c i e n t s % 3193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 3203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 3213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 3223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% GenerateCoefficients() takes user provided input arguments and generates 3253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% the coefficients, needed to apply the specific distortion for either 3263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% distorting images (generally using control points) or generating a color 3273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% gradient from sparsely separated color points. 3283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% The format of the GenerateCoefficients() method is: 3303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 331827944d54938c1f8a74ff53cd35c11801060d995dirk% Image *GenerateCoefficients(const Image *image,DistortMethod method, 332bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy% const size_t number_arguments,const double *arguments, 333bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy% size_t number_values, ExceptionInfo *exception) 3343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% A description of each parameter follows: 3363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o image: the image to be distorted. 3383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o method: the method of image distortion/ sparse gradient 3403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o number_arguments: the number of arguments given. 3423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o arguments: the arguments for this distortion method. 3443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o number_values: the style and format of given control points, (caller type) 3463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 0: 2 dimensional mapping of control points (Distort) 3473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Format: u,v,x,y where u,v is the 'source' of the 3483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% the color to be plotted, for DistortImage() 3493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% N: Interpolation of control points with N values (usally r,g,b) 3503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Format: x,y,r,g,b mapping x,y to color values r,g,b 351972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas% IN future, variable number of values may be given (1 to N) 3523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o exception: return any errors or warnings in this structure 3543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Note that the returned array of double values must be freed by the 3563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% calling method using RelinquishMagickMemory(). This however may change in 3573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% the future to require a more 'method' specific method. 3583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 3593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Because of this this method should not be classed as stable or used 3603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% outside other MagickCore library methods. 3613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/ 3623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 36372844f182b47d17dc2b4e9f1062ba434e5852fd6cristystatic inline double MagickRound(double x) 36472844f182b47d17dc2b4e9f1062ba434e5852fd6cristy{ 36572844f182b47d17dc2b4e9f1062ba434e5852fd6cristy /* 36672844f182b47d17dc2b4e9f1062ba434e5852fd6cristy Round the fraction to nearest integer. 36772844f182b47d17dc2b4e9f1062ba434e5852fd6cristy */ 368ae0a3fcb5e88aba2468892d7710c322885d80fcdcristy if ((x-floor(x)) < (ceil(x)-x)) 36972844f182b47d17dc2b4e9f1062ba434e5852fd6cristy return(floor(x)); 37072844f182b47d17dc2b4e9f1062ba434e5852fd6cristy return(ceil(x)); 37172844f182b47d17dc2b4e9f1062ba434e5852fd6cristy} 37272844f182b47d17dc2b4e9f1062ba434e5852fd6cristy 3733ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic double *GenerateCoefficients(const Image *image, 374827944d54938c1f8a74ff53cd35c11801060d995dirk DistortMethod *method,const size_t number_arguments,const double *arguments, 375827944d54938c1f8a74ff53cd35c11801060d995dirk size_t number_values,ExceptionInfo *exception) 3763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 3773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 3783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *coeff; 3793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 380bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register size_t 3813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy i; 3823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 383bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 3843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy number_coeff, /* number of coefficients to return (array size) */ 3853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy cp_size, /* number floating point numbers per control point */ 3863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy cp_x,cp_y, /* the x,y indexes for control point */ 3873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy cp_values; /* index of values for this control point */ 3883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* number_values Number of values given per control point */ 3893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 3903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_values == 0 ) { 3913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Image distortion using control points (or other distortion) 3923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy That is generate a mapping so that x,y->u,v given u,v,x,y 3933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 3943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy number_values = 2; /* special case: two values of u,v */ 3953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy cp_values = 0; /* the values i,j are BEFORE the destination CP x,y */ 3963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy cp_x = 2; /* location of x,y in input control values */ 3973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy cp_y = 3; 3983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* NOTE: cp_values, also used for later 'reverse map distort' tests */ 3993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 4003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else { 4013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy cp_x = 0; /* location of x,y in input control values */ 4023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy cp_y = 1; 4033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy cp_values = 2; /* and the other values are after x,y */ 4043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Typically in this case the values are R,G,B color values */ 4053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 4063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy cp_size = number_values+2; /* each CP defintion involves this many numbers */ 4073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 4083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* If not enough control point pairs are found for specific distortions 409972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas fall back to Affine distortion (allowing 0 to 3 point pairs) 4103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 4112857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy if ( number_arguments < 4*cp_size && 4123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ( *method == BilinearForwardDistortion 4133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy || *method == BilinearReverseDistortion 4143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy || *method == PerspectiveDistortion 4153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ) ) 4163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *method = AffineDistortion; 4173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 4183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy number_coeff=0; 4193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy switch (*method) { 4203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case AffineDistortion: 4213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* also BarycentricColorInterpolate: */ 4223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy number_coeff=3*number_values; 4233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PolynomialDistortion: 4253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* number of coefficents depend on the given polynomal 'order' */ 4263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy i = poly_number_terms(arguments[0]); 4273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy number_coeff = 2 + i*number_values; 4283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( i == 0 ) { 4293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 4303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy "InvalidArgument","%s : '%s'","Polynomial", 43196b2d38e9e66b8ad2feba7a8a99bad94730efd19anthony "Invalid order, should be interger 1 to 5, or 1.5"); 4323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 4333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 4343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments < 1+i*cp_size ) { 4353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 436e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy "InvalidArgument", "%s : 'require at least %.20g CPs'", 437e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy "Polynomial", (double) i); 4383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 4393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 4403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BilinearReverseDistortion: 4423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy number_coeff=4*number_values; 4433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 4453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy The rest are constants as they are only used for image distorts 4463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 4473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BilinearForwardDistortion: 4485056b230558c7de0a79d51d82bdc929fef45a225anthony number_coeff=10; /* 2*4 coeff plus 2 constants */ 4495056b230558c7de0a79d51d82bdc929fef45a225anthony cp_x = 0; /* Reverse src/dest coords for forward mapping */ 4503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy cp_y = 1; 4513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy cp_values = 2; 4523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4535056b230558c7de0a79d51d82bdc929fef45a225anthony#if 0 4545056b230558c7de0a79d51d82bdc929fef45a225anthony case QuadraterialDistortion: 4555056b230558c7de0a79d51d82bdc929fef45a225anthony number_coeff=19; /* BilinearForward + BilinearReverse */ 4565056b230558c7de0a79d51d82bdc929fef45a225anthony#endif 4575056b230558c7de0a79d51d82bdc929fef45a225anthony break; 4583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case ShepardsDistortion: 45947bb5df69322136901ccab9ad266d21ceff50500anthony number_coeff=1; /* The power factor to use */ 4603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case ArcDistortion: 4623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy number_coeff=5; 4633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case ScaleRotateTranslateDistortion: 4653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case AffineProjectionDistortion: 466e0d9bbde3eb1826c767fee326a5786a9f28a191banthony case Plane2CylinderDistortion: 467e0d9bbde3eb1826c767fee326a5786a9f28a191banthony case Cylinder2PlaneDistortion: 4683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy number_coeff=6; 4693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PolarDistortion: 4713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case DePolarDistortion: 4723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy number_coeff=8; 4733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PerspectiveDistortion: 4753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PerspectiveProjectionDistortion: 4763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy number_coeff=9; 4773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BarrelDistortion: 4793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BarrelInverseDistortion: 4803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy number_coeff=10; 4813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 4823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy default: 483cf96e67439ab38056f2ec693bd0b0392c732cdf9cristy perror("unknown method given"); /* just fail assertion */ 4843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 4853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 4863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* allocate the array of coefficients needed */ 4873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) AcquireQuantumMemory(number_coeff,sizeof(*coeff)); 4883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (coeff == (double *) NULL) { 4893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(), 4903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ResourceLimitError,"MemoryAllocationFailed", 4913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy "%s", "GenerateCoefficients"); 4923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 4933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 4943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 4950c63ece53c43017de0184b16fe8cb6e5b58ad51bnicolas /* zero out coefficients array */ 4963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for (i=0; i < number_coeff; i++) 4973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[i] = 0.0; 4983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 4993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy switch (*method) 5003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 5013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case AffineDistortion: 5023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 5033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Affine Distortion 5043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy v = c0*x + c1*y + c2 5053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for each 'value' given 5063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 5073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Input Arguments are sets of control points... 5083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy For Distort Images u,v, x,y ... 5093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy For Sparse Gradients x,y, r,g,b ... 5103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 5113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments%cp_size != 0 || 5123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy number_arguments < cp_size ) { 5133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 514e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy "InvalidArgument", "%s : 'require at least %.20g CPs'", 515e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy "Affine", 1.0); 5163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff=(double *) RelinquishMagickMemory(coeff); 5173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 5183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 5193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* handle special cases of not enough arguments */ 5203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments == cp_size ) { 5213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Only 1 CP Set Given */ 5223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( cp_values == 0 ) { 5233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* image distortion - translate the image */ 5243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] = 1.0; 5253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[2] = arguments[0] - arguments[2]; 5263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[4] = 1.0; 5273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[5] = arguments[1] - arguments[3]; 5283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 5293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else { 5303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* sparse gradient - use the values directly */ 5313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for (i=0; i<number_values; i++) 5323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[i*3+2] = arguments[cp_values+i]; 5333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 5343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 5353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else { 5363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 2 or more points (usally 3) given. 537972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas Solve a least squares simultaneous equation for coefficients. 5383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 5393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 5403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy **matrix, 5413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy **vectors, 5423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[3]; 5433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 5443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy MagickBooleanType 5453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status; 5463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 5473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* create matrix, and a fake vectors matrix */ 5483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy matrix = AcquireMagickMatrix(3UL,3UL); 5493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy vectors = (double **) AcquireQuantumMemory(number_values,sizeof(*vectors)); 5503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (matrix == (double **) NULL || vectors == (double **) NULL) 5513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 5523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy matrix = RelinquishMagickMatrix(matrix, 3UL); 5533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy vectors = (double **) RelinquishMagickMemory(vectors); 5543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 5553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(), 5563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ResourceLimitError,"MemoryAllocationFailed", 5573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy "%s", "DistortCoefficients"); 5583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 5593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 5603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* fake a number_values x3 vectors matrix from coefficients array */ 5613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for (i=0; i < number_values; i++) 5623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy vectors[i] = &(coeff[i*3]); 5633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Add given control point pairs for least squares solving */ 5643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for (i=0; i < number_arguments; i+=cp_size) { 5653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[0] = arguments[i+cp_x]; /* x */ 5663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[1] = arguments[i+cp_y]; /* y */ 5673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[2] = 1; /* 1 */ 5683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy LeastSquaresAddTerms(matrix,vectors,terms, 5693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy &(arguments[i+cp_values]),3UL,number_values); 5703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 5713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments == 2*cp_size ) { 5723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Only two pairs were given, but we need 3 to solve the affine. 5733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Fake extra coordinates by rotating p1 around p0 by 90 degrees. 5743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy x2 = x0 - (y1-y0) y2 = y0 + (x1-x0) 5753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 5763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[0] = arguments[cp_x] 5773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy - ( arguments[cp_size+cp_y] - arguments[cp_y] ); /* x2 */ 5783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[1] = arguments[cp_y] + 5793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + ( arguments[cp_size+cp_x] - arguments[cp_x] ); /* y2 */ 5803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[2] = 1; /* 1 */ 5813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( cp_values == 0 ) { 5823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Image Distortion - rotate the u,v coordients too */ 5833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 5843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy uv2[2]; 5853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy uv2[0] = arguments[0] - arguments[5] + arguments[1]; /* u2 */ 5863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy uv2[1] = arguments[1] + arguments[4] - arguments[0]; /* v2 */ 5873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy LeastSquaresAddTerms(matrix,vectors,terms,uv2,3UL,2UL); 5883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 5893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else { 5903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Sparse Gradient - use values of p0 for linear gradient */ 5913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy LeastSquaresAddTerms(matrix,vectors,terms, 5923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy &(arguments[cp_values]),3UL,number_values); 5933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 5943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 5953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Solve for LeastSquares Coefficients */ 5963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status=GaussJordanElimination(matrix,vectors,3UL,number_values); 5973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy matrix = RelinquishMagickMatrix(matrix, 3UL); 5983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy vectors = (double **) RelinquishMagickMemory(vectors); 5993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( status == MagickFalse ) { 6003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 6013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 6024cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony "InvalidArgument","%s : 'Unsolvable Matrix'", 603042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method) ); 6043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 6053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 6063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 6073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(coeff); 6083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 6093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case AffineProjectionDistortion: 6103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 6113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 6123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Arguments: Affine Matrix (forward mapping) 6133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Arguments sx, rx, ry, sy, tx, ty 6143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Where u = sx*x + ry*y + tx 6153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy v = rx*x + sy*y + ty 6163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 6173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Returns coefficients (in there inverse form) ordered as... 6183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sx ry tx rx sy ty 6193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 6203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy AffineProjection Distortion Notes... 6213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + Will only work with a 2 number_values for Image Distortion 6223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + Can not be used for generating a sparse gradient (interpolation) 6233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 6243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double inverse[8]; 6253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (number_arguments != 6) { 6263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 6273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 6284cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony "InvalidArgument","%s : 'Needs 6 coeff values'", 629042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method) ); 6303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 6313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 63263c023f25199125f673535000a4507d13a7ecac7nicolas /* FUTURE: trap test for sx*sy-rx*ry == 0 (determinant = 0, no inverse) */ 6333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for(i=0; i<6UL; i++ ) 6343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse[i] = arguments[i]; 6353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy AffineArgsToCoefficients(inverse); /* map into coefficents */ 6363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy InvertAffineCoefficients(inverse, coeff); /* invert */ 6373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *method = AffineDistortion; 6383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 6393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(coeff); 6403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 6413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case ScaleRotateTranslateDistortion: 6423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 6433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Scale, Rotate and Translate Distortion 644972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas An alternative Affine Distortion 6453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Argument options, by number of arguments given: 6463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 7: x,y, sx,sy, a, nx,ny 6473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 6: x,y, s, a, nx,ny 6483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 5: x,y, sx,sy, a 6493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 4: x,y, s, a 6503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 3: x,y, a 6513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 2: s, a 6523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1: a 6533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Where actions are (in order of application) 6543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy x,y 'center' of transforms (default = image center) 6553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sx,sy scale image by this amount (default = 1) 6563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy a angle of rotation (argument required) 6575056b230558c7de0a79d51d82bdc929fef45a225anthony nx,ny move 'center' here (default = x,y or no movement) 6583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy And convert to affine mapping coefficients 6593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 6603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ScaleRotateTranslate Distortion Notes... 6613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + Does not use a set of CPs in any normal way 6623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + Will only work with a 2 number_valuesal Image Distortion 663972a6e66d79b58ffae5d7512b33c05dccc8f537cnicolas + Cannot be used for generating a sparse gradient (interpolation) 6643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 6653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 6663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy cosine, sine, 6673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy x,y,sx,sy,a,nx,ny; 6683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 6693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* set default center, and default scale */ 6703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy x = nx = (double)(image->columns)/2.0 + (double)image->page.x; 6713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy y = ny = (double)(image->rows)/2.0 + (double)image->page.y; 6723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sx = sy = 1.0; 6733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy switch ( number_arguments ) { 6743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 0: 6753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 6763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 6774cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony "InvalidArgument","%s : 'Needs at least 1 argument'", 678042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method) ); 6793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 6803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 1: 6813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy a = arguments[0]; 6823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 6833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 2: 6843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sx = sy = arguments[0]; 6853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy a = arguments[1]; 6863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 6873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy default: 6883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy x = nx = arguments[0]; 6893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy y = ny = arguments[1]; 6903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy switch ( number_arguments ) { 6913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 3: 6923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy a = arguments[2]; 6933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 6943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 4: 6953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sx = sy = arguments[2]; 6963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy a = arguments[3]; 6973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 6983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 5: 6993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sx = arguments[2]; 7003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sy = arguments[3]; 7013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy a = arguments[4]; 7023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 7033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 6: 7043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sx = sy = arguments[2]; 7053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy a = arguments[3]; 7063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy nx = arguments[4]; 7073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ny = arguments[5]; 7083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 7093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case 7: 7103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sx = arguments[2]; 7113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sy = arguments[3]; 7123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy a = arguments[4]; 7133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy nx = arguments[5]; 7143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ny = arguments[6]; 7153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 7163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy default: 7173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 7183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 7194cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony "InvalidArgument","%s : 'Too Many Arguments (7 or less)'", 720042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method) ); 7213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 7223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 7233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 7243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 7253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Trap if sx or sy == 0 -- image is scaled out of existance! */ 7263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( fabs(sx) < MagickEpsilon || fabs(sy) < MagickEpsilon ) { 7273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 7283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 7294cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony "InvalidArgument","%s : 'Zero Scale Given'", 730042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method) ); 7313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 7323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 7333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Save the given arguments as an affine distortion */ 7343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy a=DegreesToRadians(a); cosine=cos(a); sine=sin(a); 7353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 7363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *method = AffineDistortion; 7373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0]=cosine/sx; 7383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[1]=sine/sx; 7393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[2]=x-nx*coeff[0]-ny*coeff[1]; 7403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[3]=(-sine)/sy; 7413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[4]=cosine/sy; 7423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[5]=y-nx*coeff[3]-ny*coeff[4]; 7433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(coeff); 7443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 7453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PerspectiveDistortion: 7463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { /* 7473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Perspective Distortion (a ratio of affine distortions) 7483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 7493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy p(x,y) c0*x + c1*y + c2 7503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy u = ------ = ------------------ 7513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy r(x,y) c6*x + c7*y + 1 7523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 7533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy q(x,y) c3*x + c4*y + c5 7543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy v = ------ = ------------------ 7553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy r(x,y) c6*x + c7*y + 1 7563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 7573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy c8 = Sign of 'r', or the denominator affine, for the actual image. 7583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy This determines what part of the distorted image is 'ground' 7593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy side of the horizon, the other part is 'sky' or invalid. 7603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Valid values are +1.0 or -1.0 only. 7613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 7623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Input Arguments are sets of control points... 7633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy For Distort Images u,v, x,y ... 7643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy For Sparse Gradients x,y, r,g,b ... 7653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 7663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Perspective Distortion Notes... 7673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + Can be thought of as ratio of 3 affine transformations 7683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + Not separatable: r() or c6 and c7 are used by both equations 7693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + All 8 coefficients must be determined simultaniously 7703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + Will only work with a 2 number_valuesal Image Distortion 7713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + Can not be used for generating a sparse gradient (interpolation) 7723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + It is not linear, but is simple to generate an inverse 7733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + All lines within an image remain lines. 7743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + but distances between points may vary. 7753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 7763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 7773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy **matrix, 7783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *vectors[1], 7793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[8]; 7803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 781bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 7823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy cp_u = cp_values, 7833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy cp_v = cp_values+1; 7843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 7853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy MagickBooleanType 7863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status; 7873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 78896b2d38e9e66b8ad2feba7a8a99bad94730efd19anthony if ( number_arguments%cp_size != 0 || 78996b2d38e9e66b8ad2feba7a8a99bad94730efd19anthony number_arguments < cp_size*4 ) { 79096b2d38e9e66b8ad2feba7a8a99bad94730efd19anthony (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 791e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy "InvalidArgument", "%s : 'require at least %.20g CPs'", 792042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method), 4.0); 79396b2d38e9e66b8ad2feba7a8a99bad94730efd19anthony coeff=(double *) RelinquishMagickMemory(coeff); 79496b2d38e9e66b8ad2feba7a8a99bad94730efd19anthony return((double *) NULL); 79596b2d38e9e66b8ad2feba7a8a99bad94730efd19anthony } 7963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* fake 1x8 vectors matrix directly using the coefficients array */ 7973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy vectors[0] = &(coeff[0]); 7983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 8x8 least-squares matrix (zeroed) */ 7993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy matrix = AcquireMagickMatrix(8UL,8UL); 8003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (matrix == (double **) NULL) { 8013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(), 8023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ResourceLimitError,"MemoryAllocationFailed", 8033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy "%s", "DistortCoefficients"); 8043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 8053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 8063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Add control points for least squares solving */ 8073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for (i=0; i < number_arguments; i+=4) { 8083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[0]=arguments[i+cp_x]; /* c0*x */ 8093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[1]=arguments[i+cp_y]; /* c1*y */ 8103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[2]=1.0; /* c2*1 */ 8113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[3]=0.0; 8123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[4]=0.0; 8133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[5]=0.0; 8143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[6]=-terms[0]*arguments[i+cp_u]; /* 1/(c6*x) */ 8153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[7]=-terms[1]*arguments[i+cp_u]; /* 1/(c7*y) */ 8163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy LeastSquaresAddTerms(matrix,vectors,terms,&(arguments[i+cp_u]), 8173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 8UL,1UL); 8183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 8193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[0]=0.0; 8203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[1]=0.0; 8213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[2]=0.0; 8223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[3]=arguments[i+cp_x]; /* c3*x */ 8233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[4]=arguments[i+cp_y]; /* c4*y */ 8243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[5]=1.0; /* c5*1 */ 8253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[6]=-terms[3]*arguments[i+cp_v]; /* 1/(c6*x) */ 8263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[7]=-terms[4]*arguments[i+cp_v]; /* 1/(c7*y) */ 8273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy LeastSquaresAddTerms(matrix,vectors,terms,&(arguments[i+cp_v]), 8283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 8UL,1UL); 8293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 8303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Solve for LeastSquares Coefficients */ 8313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status=GaussJordanElimination(matrix,vectors,8UL,1UL); 8323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy matrix = RelinquishMagickMatrix(matrix, 8UL); 8333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( status == MagickFalse ) { 8343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 8353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 8364cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony "InvalidArgument","%s : 'Unsolvable Matrix'", 837042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method) ); 8383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 8393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 8403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 8413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Calculate 9'th coefficient! The ground-sky determination. 8423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy What is sign of the 'ground' in r() denominator affine function? 8433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Just use any valid image coordinate (first control point) in 8443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy destination for determination of what part of view is 'ground'. 8453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 8463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[8] = coeff[6]*arguments[cp_x] 8473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + coeff[7]*arguments[cp_y] + 1.0; 8483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[8] = (coeff[8] < 0.0) ? -1.0 : +1.0; 8493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 8503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(coeff); 8513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 8523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PerspectiveProjectionDistortion: 8533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 8543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 8553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Arguments: Perspective Coefficents (forward mapping) 8563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 8573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (number_arguments != 8) { 8583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 8594cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony "InvalidArgument", "%s : 'Needs 8 coefficient values'", 860042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method)); 8613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 8623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 8633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* FUTURE: trap test c0*c4-c3*c1 == 0 (determinate = 0, no inverse) */ 8643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy InvertPerspectiveCoefficients(arguments, coeff); 8653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 8663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Calculate 9'th coefficient! The ground-sky determination. 8673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy What is sign of the 'ground' in r() denominator affine function? 8683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Just use any valid image cocodinate in destination for determination. 8693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy For a forward mapped perspective the images 0,0 coord will map to 8703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy c2,c5 in the distorted image, so set the sign of denominator of that. 8713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 8723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[8] = coeff[6]*arguments[2] 8733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + coeff[7]*arguments[5] + 1.0; 8743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[8] = (coeff[8] < 0.0) ? -1.0 : +1.0; 8753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *method = PerspectiveDistortion; 8763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 8773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(coeff); 8783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 8793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BilinearForwardDistortion: 8803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BilinearReverseDistortion: 8813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 8825056b230558c7de0a79d51d82bdc929fef45a225anthony /* Bilinear Distortion (Forward mapping) 8833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy v = c0*x + c1*y + c2*x*y + c3; 8843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for each 'value' given 8853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 8865056b230558c7de0a79d51d82bdc929fef45a225anthony This is actually a simple polynomial Distortion! The difference 8875056b230558c7de0a79d51d82bdc929fef45a225anthony however is when we need to reverse the above equation to generate a 8885056b230558c7de0a79d51d82bdc929fef45a225anthony BilinearForwardDistortion (see below). 8895056b230558c7de0a79d51d82bdc929fef45a225anthony 8903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Input Arguments are sets of control points... 8913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy For Distort Images u,v, x,y ... 8923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy For Sparse Gradients x,y, r,g,b ... 8933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 8943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 8953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 8963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy **matrix, 8973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy **vectors, 8983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[4]; 8993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 9003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy MagickBooleanType 9013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status; 9023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 90396b2d38e9e66b8ad2feba7a8a99bad94730efd19anthony /* check the number of arguments */ 90496b2d38e9e66b8ad2feba7a8a99bad94730efd19anthony if ( number_arguments%cp_size != 0 || 90596b2d38e9e66b8ad2feba7a8a99bad94730efd19anthony number_arguments < cp_size*4 ) { 90696b2d38e9e66b8ad2feba7a8a99bad94730efd19anthony (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 907e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy "InvalidArgument", "%s : 'require at least %.20g CPs'", 908042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method), 4.0); 90996b2d38e9e66b8ad2feba7a8a99bad94730efd19anthony coeff=(double *) RelinquishMagickMemory(coeff); 91096b2d38e9e66b8ad2feba7a8a99bad94730efd19anthony return((double *) NULL); 91196b2d38e9e66b8ad2feba7a8a99bad94730efd19anthony } 9123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* create matrix, and a fake vectors matrix */ 9133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy matrix = AcquireMagickMatrix(4UL,4UL); 9143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy vectors = (double **) AcquireQuantumMemory(number_values,sizeof(*vectors)); 9153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (matrix == (double **) NULL || vectors == (double **) NULL) 9163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 9173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy matrix = RelinquishMagickMatrix(matrix, 4UL); 9183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy vectors = (double **) RelinquishMagickMemory(vectors); 9193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 9203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(), 9213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ResourceLimitError,"MemoryAllocationFailed", 9223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy "%s", "DistortCoefficients"); 9233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 9243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 9253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* fake a number_values x4 vectors matrix from coefficients array */ 9263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for (i=0; i < number_values; i++) 9273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy vectors[i] = &(coeff[i*4]); 9283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Add given control point pairs for least squares solving */ 9293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for (i=0; i < number_arguments; i+=cp_size) { 9303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[0] = arguments[i+cp_x]; /* x */ 9313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[1] = arguments[i+cp_y]; /* y */ 9323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[2] = terms[0]*terms[1]; /* x*y */ 9333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[3] = 1; /* 1 */ 9343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy LeastSquaresAddTerms(matrix,vectors,terms, 9353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy &(arguments[i+cp_values]),4UL,number_values); 9363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 9373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Solve for LeastSquares Coefficients */ 9383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status=GaussJordanElimination(matrix,vectors,4UL,number_values); 9393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy matrix = RelinquishMagickMatrix(matrix, 4UL); 9403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy vectors = (double **) RelinquishMagickMemory(vectors); 9413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( status == MagickFalse ) { 9423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 9433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 9444cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony "InvalidArgument","%s : 'Unsolvable Matrix'", 945042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method) ); 9463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 9473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 9483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( *method == BilinearForwardDistortion ) { 9493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Bilinear Forward Mapped Distortion 9503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 9513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy The above least-squares solved for coefficents but in the forward 9523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy direction, due to changes to indexing constants. 9533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 9543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy i = c0*x + c1*y + c2*x*y + c3; 9553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy j = c4*x + c5*y + c6*x*y + c7; 9563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 9574cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony where i,j are in the destination image, NOT the source. 9583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 9595056b230558c7de0a79d51d82bdc929fef45a225anthony Reverse Pixel mapping however needs to use reverse of these 9605056b230558c7de0a79d51d82bdc929fef45a225anthony functions. It required a full page of algbra to work out the 9615056b230558c7de0a79d51d82bdc929fef45a225anthony reversed mapping formula, but resolves down to the following... 9623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 9633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy c8 = c0*c5-c1*c4; 9645056b230558c7de0a79d51d82bdc929fef45a225anthony c9 = 2*(c2*c5-c1*c6); // '2*a' in the quadratic formula 9653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 9663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy i = i - c3; j = j - c7; 9675056b230558c7de0a79d51d82bdc929fef45a225anthony b = c6*i - c2*j + c8; // So that a*y^2 + b*y + c == 0 9685056b230558c7de0a79d51d82bdc929fef45a225anthony c = c4*i - c0*j; // y = ( -b +- sqrt(bb - 4ac) ) / (2*a) 9695056b230558c7de0a79d51d82bdc929fef45a225anthony 9705056b230558c7de0a79d51d82bdc929fef45a225anthony r = b*b - c9*(c+c); 9715056b230558c7de0a79d51d82bdc929fef45a225anthony if ( c9 != 0 ) 9725056b230558c7de0a79d51d82bdc929fef45a225anthony y = ( -b + sqrt(r) ) / c9; 9735056b230558c7de0a79d51d82bdc929fef45a225anthony else 9745056b230558c7de0a79d51d82bdc929fef45a225anthony y = -c/b; 9753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 9763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy x = ( i - c1*y) / ( c1 - c2*y ); 9773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 9783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy NB: if 'r' is negative there is no solution! 9793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy NB: the sign of the sqrt() should be negative if image becomes 9805056b230558c7de0a79d51d82bdc929fef45a225anthony flipped or flopped, or crosses over itself. 9815056b230558c7de0a79d51d82bdc929fef45a225anthony NB: techniqually coefficient c5 is not needed, anymore, 9825056b230558c7de0a79d51d82bdc929fef45a225anthony but kept for completness. 9833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 9845056b230558c7de0a79d51d82bdc929fef45a225anthony See Anthony Thyssen <A.Thyssen@griffith.edu.au> 9855056b230558c7de0a79d51d82bdc929fef45a225anthony or Fred Weinhaus <fmw@alink.net> for more details. 9863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 9873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 9883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[8] = coeff[0]*coeff[5] - coeff[1]*coeff[4]; 9895056b230558c7de0a79d51d82bdc929fef45a225anthony coeff[9] = 2*(coeff[2]*coeff[5] - coeff[1]*coeff[6]); 9903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 9913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(coeff); 9923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 9935056b230558c7de0a79d51d82bdc929fef45a225anthony#if 0 9945056b230558c7de0a79d51d82bdc929fef45a225anthony case QuadrilateralDistortion: 9955056b230558c7de0a79d51d82bdc929fef45a225anthony { 9965056b230558c7de0a79d51d82bdc929fef45a225anthony /* Map a Quadrilateral to a unit square using BilinearReverse 9975056b230558c7de0a79d51d82bdc929fef45a225anthony Then map that unit square back to the final Quadrilateral 9985056b230558c7de0a79d51d82bdc929fef45a225anthony using BilinearForward. 9995056b230558c7de0a79d51d82bdc929fef45a225anthony 10005056b230558c7de0a79d51d82bdc929fef45a225anthony Input Arguments are sets of control points... 10015056b230558c7de0a79d51d82bdc929fef45a225anthony For Distort Images u,v, x,y ... 10025056b230558c7de0a79d51d82bdc929fef45a225anthony For Sparse Gradients x,y, r,g,b ... 10035056b230558c7de0a79d51d82bdc929fef45a225anthony 10045056b230558c7de0a79d51d82bdc929fef45a225anthony */ 10055056b230558c7de0a79d51d82bdc929fef45a225anthony /* UNDER CONSTRUCTION */ 10065056b230558c7de0a79d51d82bdc929fef45a225anthony return(coeff); 10075056b230558c7de0a79d51d82bdc929fef45a225anthony } 10085056b230558c7de0a79d51d82bdc929fef45a225anthony#endif 10095056b230558c7de0a79d51d82bdc929fef45a225anthony 10103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PolynomialDistortion: 10113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 10123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Polynomial Distortion 10133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 10143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy First two coefficents are used to hole global polynomal information 10153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy c0 = Order of the polynimial being created 10163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy c1 = number_of_terms in one polynomial equation 10173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 10183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Rest of the coefficients map to the equations.... 10193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy v = c0 + c1*x + c2*y + c3*x*y + c4*x^2 + c5*y^2 + c6*x^3 + ... 10203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for each 'value' (number_values of them) given. 10213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy As such total coefficients = 2 + number_terms * number_values 10223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 10233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Input Arguments are sets of control points... 10243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy For Distort Images order [u,v, x,y] ... 10253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy For Sparse Gradients order [x,y, r,g,b] ... 10263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 10273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Polynomial Distortion Notes... 10283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + UNDER DEVELOPMENT -- Do not expect this to remain as is. 10293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + Currently polynomial is a reversed mapped distortion. 10303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + Order 1.5 is fudged to map into a bilinear distortion. 10315056b230558c7de0a79d51d82bdc929fef45a225anthony though it is not the same order as that distortion. 10323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 10333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 10343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy **matrix, 10353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy **vectors, 10363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *terms; 10373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1038bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 10393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy nterms; /* number of polynomial terms per number_values */ 10403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1041bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 10423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy j; 10433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 10443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy MagickBooleanType 10453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status; 10463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 10473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* first two coefficients hold polynomial order information */ 10483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] = arguments[0]; 10493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[1] = (double) poly_number_terms(arguments[0]); 1050bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy nterms = (size_t) coeff[1]; 10513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 10523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* create matrix, a fake vectors matrix, and least sqs terms */ 10533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy matrix = AcquireMagickMatrix(nterms,nterms); 10543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy vectors = (double **) AcquireQuantumMemory(number_values,sizeof(*vectors)); 10553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms = (double *) AcquireQuantumMemory(nterms, sizeof(*terms)); 10563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (matrix == (double **) NULL || 10573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy vectors == (double **) NULL || 10583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms == (double *) NULL ) 10593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 10603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy matrix = RelinquishMagickMatrix(matrix, nterms); 10613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy vectors = (double **) RelinquishMagickMemory(vectors); 10623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms = (double *) RelinquishMagickMemory(terms); 10633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 10643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(), 10653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ResourceLimitError,"MemoryAllocationFailed", 10663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy "%s", "DistortCoefficients"); 10673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 10683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 10693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* fake a number_values x3 vectors matrix from coefficients array */ 10703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for (i=0; i < number_values; i++) 10713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy vectors[i] = &(coeff[2+i*nterms]); 10723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Add given control point pairs for least squares solving */ 107396b2d38e9e66b8ad2feba7a8a99bad94730efd19anthony for (i=1; i < number_arguments; i+=cp_size) { /* NB: start = 1 not 0 */ 1074bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (j=0; j < (ssize_t) nterms; j++) 10753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms[j] = poly_basis_fn(j,arguments[i+cp_x],arguments[i+cp_y]); 10763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy LeastSquaresAddTerms(matrix,vectors,terms, 10773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy &(arguments[i+cp_values]),nterms,number_values); 10783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 10793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy terms = (double *) RelinquishMagickMemory(terms); 10803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Solve for LeastSquares Coefficients */ 10813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status=GaussJordanElimination(matrix,vectors,nterms,number_values); 10823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy matrix = RelinquishMagickMatrix(matrix, nterms); 10833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy vectors = (double **) RelinquishMagickMemory(vectors); 10843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( status == MagickFalse ) { 10853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 10863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 10874cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony "InvalidArgument","%s : 'Unsolvable Matrix'", 1088042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method) ); 10893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 10903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 10913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(coeff); 10923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 10933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case ArcDistortion: 10943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 10953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Arc Distortion 10963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Args: arc_width rotate top_edge_radius bottom_edge_radius 10973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy All but first argument are optional 10983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy arc_width The angle over which to arc the image side-to-side 10993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy rotate Angle to rotate image from vertical center 11003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy top_radius Set top edge of source image at this radius 11013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy bottom_radius Set bootom edge to this radius (radial scaling) 11023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 11033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy By default, if the radii arguments are nor provided the image radius 11043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy is calculated so the horizontal center-line is fits the given arc 11053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy without scaling. 11063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 11073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy The output image size is ALWAYS adjusted to contain the whole image, 11083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy and an offset is given to position image relative to the 0,0 point of 11093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy the origin, allowing users to use relative positioning onto larger 11103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy background (via -flatten). 11113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 11123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy The arguments are converted to these coefficients 11133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy c0: angle for center of source image 11143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy c1: angle scale for mapping to source image 11153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy c2: radius for top of source image 11163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy c3: radius scale for mapping source image 11173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy c4: centerline of arc within source image 11183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 11193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Note the coefficients use a center angle, so asymptotic join is 11203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy furthest from both sides of the source image. This also means that 11213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for arc angles greater than 360 the sides of the image will be 11223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy trimmed equally. 11233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 11243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Arc Distortion Notes... 11253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + Does not use a set of CPs 11263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + Will only work with Image Distortion 11273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + Can not be used for generating a sparse gradient (interpolation) 11283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 11293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments >= 1 && arguments[0] < MagickEpsilon ) { 11303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 11313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 11324cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony "InvalidArgument","%s : 'Arc Angle Too Small'", 1133042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method) ); 11343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 11353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 11363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments >= 3 && arguments[2] < MagickEpsilon ) { 11373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 11383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 11394cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony "InvalidArgument","%s : 'Outer Radius Too Small'", 1140042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method) ); 11413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 11423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 11433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] = -MagickPI2; /* -90, place at top! */ 11443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments >= 1 ) 11453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[1] = DegreesToRadians(arguments[0]); 11463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else 11473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[1] = MagickPI2; /* zero arguments - center is at top */ 11483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments >= 2 ) 11493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] += DegreesToRadians(arguments[1]); 11503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] /= Magick2PI; /* normalize radians */ 11513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] -= MagickRound(coeff[0]); 11523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] *= Magick2PI; /* de-normalize back to radians */ 11533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[3] = (double)image->rows-1; 11543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[2] = (double)image->columns/coeff[1] + coeff[3]/2.0; 11553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments >= 3 ) { 11563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments >= 4 ) 11573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[3] = arguments[2] - arguments[3]; 11583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else 11593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[3] *= arguments[2]/coeff[2]; 11603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[2] = arguments[2]; 11613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 11623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[4] = ((double)image->columns-1.0)/2.0; 11633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 11643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(coeff); 11653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 11663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PolarDistortion: 11673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case DePolarDistortion: 11683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 11693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* (De)Polar Distortion (same set of arguments) 11703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Args: Rmax, Rmin, Xcenter,Ycenter, Afrom,Ato 11713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy DePolar can also have the extra arguments of Width, Height 11723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 11733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Coefficients 0 to 5 is the sanatized version first 6 input args 11743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Coefficient 6 is the angle to coord ratio and visa-versa 11753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Coefficient 7 is the radius to coord ratio and visa-versa 11763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1177dcabf6d5fddb35c0eedd7a7638c102f16838c4e6glennrp WARNING: It is possible for Radius max<min and/or Angle from>to 11783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 11793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments == 3 11803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy || ( number_arguments > 6 && *method == PolarDistortion ) 11813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy || number_arguments > 8 ) { 11824cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony (void) ThrowMagickException(exception,GetMagickModule(), 11834cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony OptionError,"InvalidArgument", "%s : number of arguments", 1184042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method) ); 11853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff=(double *) RelinquishMagickMemory(coeff); 11863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 11873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 11883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Rmax - if 0 calculate appropriate value */ 11893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments >= 1 ) 11903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] = arguments[0]; 11913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else 11923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] = 0.0; 11933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Rmin - usally 0 */ 11943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[1] = number_arguments >= 2 ? arguments[1] : 0.0; 11953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Center X,Y */ 11963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments >= 4 ) { 11973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[2] = arguments[2]; 11983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[3] = arguments[3]; 11993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 12003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else { /* center of actual image */ 12013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[2] = (double)(image->columns)/2.0+image->page.x; 12023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[3] = (double)(image->rows)/2.0+image->page.y; 12033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 12043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Angle from,to - about polar center 0 is downward */ 12053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[4] = -MagickPI; 12063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments >= 5 ) 12073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[4] = DegreesToRadians(arguments[4]); 12083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[5] = coeff[4]; 12093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments >= 6 ) 12103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[5] = DegreesToRadians(arguments[5]); 12113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( fabs(coeff[4]-coeff[5]) < MagickEpsilon ) 12123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[5] += Magick2PI; /* same angle is a full circle */ 12133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* if radius 0 or negative, its a special value... */ 12143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( coeff[0] < MagickEpsilon ) { 12153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Use closest edge if radius == 0 */ 12163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( fabs(coeff[0]) < MagickEpsilon ) { 12173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0]=MagickMin(fabs(coeff[2]-image->page.x), 12183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy fabs(coeff[3]-image->page.y)); 12193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0]=MagickMin(coeff[0], 12203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy fabs(coeff[2]-image->page.x-image->columns)); 12213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0]=MagickMin(coeff[0], 12223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy fabs(coeff[3]-image->page.y-image->rows)); 12233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 12243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* furthest diagonal if radius == -1 */ 12253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( fabs(-1.0-coeff[0]) < MagickEpsilon ) { 12263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double rx,ry; 12273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy rx = coeff[2]-image->page.x; 12283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ry = coeff[3]-image->page.y; 12293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] = rx*rx+ry*ry; 12303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ry = coeff[3]-image->page.y-image->rows; 12313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] = MagickMax(coeff[0],rx*rx+ry*ry); 12323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy rx = coeff[2]-image->page.x-image->columns; 12333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] = MagickMax(coeff[0],rx*rx+ry*ry); 12343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ry = coeff[3]-image->page.y; 12353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] = MagickMax(coeff[0],rx*rx+ry*ry); 12363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] = sqrt(coeff[0]); 12373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 12383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 12393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* IF Rmax <= 0 or Rmin < 0 OR Rmax < Rmin, THEN error */ 12403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( coeff[0] < MagickEpsilon || coeff[1] < -MagickEpsilon 12413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy || (coeff[0]-coeff[1]) < MagickEpsilon ) { 12423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 12434cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony "InvalidArgument", "%s : Invalid Radius", 1244042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method) ); 12453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff=(double *) RelinquishMagickMemory(coeff); 12463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 12473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 12483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* converstion ratios */ 12493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( *method == PolarDistortion ) { 12503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[6]=(double) image->columns/(coeff[5]-coeff[4]); 12513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[7]=(double) image->rows/(coeff[0]-coeff[1]); 12523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 12533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else { /* *method == DePolarDistortion */ 12543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[6]=(coeff[5]-coeff[4])/image->columns; 12553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[7]=(coeff[0]-coeff[1])/image->rows; 12563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 12573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(coeff); 12583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 1259e0d9bbde3eb1826c767fee326a5786a9f28a191banthony case Cylinder2PlaneDistortion: 1260e0d9bbde3eb1826c767fee326a5786a9f28a191banthony case Plane2CylinderDistortion: 1261b9aaf9ed2a83b7d8931306fb3313285098072b25anthony { 1262b9aaf9ed2a83b7d8931306fb3313285098072b25anthony /* 3D Cylinder to/from a Tangential Plane 1263b9aaf9ed2a83b7d8931306fb3313285098072b25anthony 1264b9aaf9ed2a83b7d8931306fb3313285098072b25anthony Projection between a clinder and flat plain from a point on the 1265b9aaf9ed2a83b7d8931306fb3313285098072b25anthony center line of the cylinder. 1266b9aaf9ed2a83b7d8931306fb3313285098072b25anthony 1267b9aaf9ed2a83b7d8931306fb3313285098072b25anthony The two surfaces coincide in 3D space at the given centers of 1268b9aaf9ed2a83b7d8931306fb3313285098072b25anthony distortion (perpendicular to projection point) on both images. 1269b9aaf9ed2a83b7d8931306fb3313285098072b25anthony 1270b9aaf9ed2a83b7d8931306fb3313285098072b25anthony Args: FOV_arc_width 1271b9aaf9ed2a83b7d8931306fb3313285098072b25anthony Coefficents: FOV(radians), Radius, center_x,y, dest_center_x,y 1272b9aaf9ed2a83b7d8931306fb3313285098072b25anthony 1273b9aaf9ed2a83b7d8931306fb3313285098072b25anthony FOV (Field Of View) the angular field of view of the distortion, 1274b9aaf9ed2a83b7d8931306fb3313285098072b25anthony across the width of the image, in degrees. The centers are the 1275b9aaf9ed2a83b7d8931306fb3313285098072b25anthony points of least distortion in the input and resulting images. 1276b9aaf9ed2a83b7d8931306fb3313285098072b25anthony 1277b9aaf9ed2a83b7d8931306fb3313285098072b25anthony These centers are however determined later. 1278b9aaf9ed2a83b7d8931306fb3313285098072b25anthony 1279b9aaf9ed2a83b7d8931306fb3313285098072b25anthony Coeff 0 is the FOV angle of view of image width in radians 1280b9aaf9ed2a83b7d8931306fb3313285098072b25anthony Coeff 1 is calculated radius of cylinder. 1281b9aaf9ed2a83b7d8931306fb3313285098072b25anthony Coeff 2,3 center of distortion of input image 1282b9aaf9ed2a83b7d8931306fb3313285098072b25anthony Coefficents 4,5 Center of Distortion of dest (determined later) 1283b9aaf9ed2a83b7d8931306fb3313285098072b25anthony */ 1284b9aaf9ed2a83b7d8931306fb3313285098072b25anthony if ( arguments[0] < MagickEpsilon || arguments[0] > 160.0 ) { 1285b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 1286b9aaf9ed2a83b7d8931306fb3313285098072b25anthony "InvalidArgument", "%s : Invalid FOV Angle", 1287b9aaf9ed2a83b7d8931306fb3313285098072b25anthony CommandOptionToMnemonic(MagickDistortOptions, *method) ); 1288b9aaf9ed2a83b7d8931306fb3313285098072b25anthony coeff=(double *) RelinquishMagickMemory(coeff); 1289b9aaf9ed2a83b7d8931306fb3313285098072b25anthony return((double *) NULL); 1290b9aaf9ed2a83b7d8931306fb3313285098072b25anthony } 1291b9aaf9ed2a83b7d8931306fb3313285098072b25anthony coeff[0] = DegreesToRadians(arguments[0]); 1292e0d9bbde3eb1826c767fee326a5786a9f28a191banthony if ( *method == Cylinder2PlaneDistortion ) 1293b9aaf9ed2a83b7d8931306fb3313285098072b25anthony /* image is curved around cylinder, so FOV angle (in radians) 1294b9aaf9ed2a83b7d8931306fb3313285098072b25anthony * scales directly to image X coordinate, according to its radius. 1295b9aaf9ed2a83b7d8931306fb3313285098072b25anthony */ 12964c08aed51c5899665ade97263692328eea4af106cristy coeff[1] = (double) image->columns/coeff[0]; 1297b9aaf9ed2a83b7d8931306fb3313285098072b25anthony else 1298b9aaf9ed2a83b7d8931306fb3313285098072b25anthony /* radius is distance away from an image with this angular FOV */ 12994c08aed51c5899665ade97263692328eea4af106cristy coeff[1] = (double) image->columns / ( 2 * tan(coeff[0]/2) ); 1300b9aaf9ed2a83b7d8931306fb3313285098072b25anthony 1301b9aaf9ed2a83b7d8931306fb3313285098072b25anthony coeff[2] = (double)(image->columns)/2.0+image->page.x; 1302b9aaf9ed2a83b7d8931306fb3313285098072b25anthony coeff[3] = (double)(image->rows)/2.0+image->page.y; 1303b9aaf9ed2a83b7d8931306fb3313285098072b25anthony coeff[4] = coeff[2]; 1304b9aaf9ed2a83b7d8931306fb3313285098072b25anthony coeff[5] = coeff[3]; /* assuming image size is the same */ 1305b9aaf9ed2a83b7d8931306fb3313285098072b25anthony return(coeff); 1306b9aaf9ed2a83b7d8931306fb3313285098072b25anthony } 13073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BarrelDistortion: 13083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BarrelInverseDistortion: 13093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 13103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Barrel Distortion 13113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Rs=(A*Rd^3 + B*Rd^2 + C*Rd + D)*Rd 13123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy BarrelInv Distortion 13133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Rs=Rd/(A*Rd^3 + B*Rd^2 + C*Rd + D) 13143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 13153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Where Rd is the normalized radius from corner to middle of image 1316ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony Input Arguments are one of the following forms (number of arguments)... 1317ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony 3: A,B,C 1318ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony 4: A,B,C,D 1319ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony 5: A,B,C X,Y 1320ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony 6: A,B,C,D X,Y 1321ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony 8: Ax,Bx,Cx,Dx Ay,By,Cy,Dy 1322ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony 10: Ax,Bx,Cx,Dx Ay,By,Cy,Dy X,Y 13233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 13243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Returns 10 coefficent values, which are de-normalized (pixel scale) 13253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Ax, Bx, Cx, Dx, Ay, By, Cy, Dy, Xc, Yc 13263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 13273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Radius de-normalization scaling factor */ 13283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 13293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy rscale = 2.0/MagickMin((double) image->columns,(double) image->rows); 13303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1331ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony /* sanity check number of args must = 3,4,5,6,8,10 or error */ 1332607c6f1c496ac78fbb0b66b00f47490b20222e66anthony if ( (number_arguments < 3) || (number_arguments == 7) || 1333607c6f1c496ac78fbb0b66b00f47490b20222e66anthony (number_arguments == 9) || (number_arguments > 10) ) 13342857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy { 13354cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony coeff=(double *) RelinquishMagickMemory(coeff); 13364cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony (void) ThrowMagickException(exception,GetMagickModule(), 13374cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony OptionError,"InvalidArgument", "%s : number of arguments", 1338042ee78fa9004bf1ac6a95f09d9d1faca631dda1cristy CommandOptionToMnemonic(MagickDistortOptions, *method) ); 13394cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony return((double *) NULL); 13402857ffcd46fc4d091060c7e8aa9804f4b4d6efaacristy } 1341ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony /* A,B,C,D coefficients */ 1342ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony coeff[0] = arguments[0]; 1343ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony coeff[1] = arguments[1]; 1344ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony coeff[2] = arguments[2]; 1345ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony if ((number_arguments == 3) || (number_arguments == 5) ) 1346ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony coeff[3] = 1.0 - coeff[0] - coeff[1] - coeff[2]; 1347ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony else 1348ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony coeff[3] = arguments[3]; 1349ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony /* de-normalize the coefficients */ 13503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] *= pow(rscale,3.0); 13513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[1] *= rscale*rscale; 13523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[2] *= rscale; 1353ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony /* Y coefficients: as given OR same as X coefficients */ 13543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments >= 8 ) { 13553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[4] = arguments[4] * pow(rscale,3.0); 13563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[5] = arguments[5] * rscale*rscale; 13573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[6] = arguments[6] * rscale; 13583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[7] = arguments[7]; 13593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 13603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else { 13613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[4] = coeff[0]; 13623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[5] = coeff[1]; 13633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[6] = coeff[2]; 13643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[7] = coeff[3]; 13653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 1366ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony /* X,Y Center of Distortion (image coodinates) */ 13673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments == 5 ) { 13683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[8] = arguments[3]; 13693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[9] = arguments[4]; 13703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 13714cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony else if ( number_arguments == 6 ) { 13723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[8] = arguments[4]; 13733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[9] = arguments[5]; 13743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 13754cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony else if ( number_arguments == 10 ) { 13763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[8] = arguments[8]; 13773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[9] = arguments[9]; 13783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 13794cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony else { 1380ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony /* center of the image provided (image coodinates) */ 1381ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony coeff[8] = (double)image->columns/2.0 + image->page.x; 1382ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony coeff[9] = (double)image->rows/2.0 + image->page.y; 13834cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony } 13843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(coeff); 13853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 13863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case ShepardsDistortion: 13873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 13883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Shepards Distortion input arguments are the coefficents! 13893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Just check the number of arguments is valid! 13903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Args: u1,v1, x1,y1, ... 13913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy OR : u1,v1, r1,g1,c1, ... 13923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 13933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( number_arguments%cp_size != 0 || 13943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy number_arguments < cp_size ) { 13953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 139647bb5df69322136901ccab9ad266d21ceff50500anthony "InvalidArgument", "%s : 'requires CP's (4 numbers each)'", 139747bb5df69322136901ccab9ad266d21ceff50500anthony CommandOptionToMnemonic(MagickDistortOptions, *method)); 13983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff=(double *) RelinquishMagickMemory(coeff); 13993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 14003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 140147bb5df69322136901ccab9ad266d21ceff50500anthony /* User defined weighting power for Shepard's Method */ 140247bb5df69322136901ccab9ad266d21ceff50500anthony { const char *artifact=GetImageArtifact(image,"shepards:power"); 140347bb5df69322136901ccab9ad266d21ceff50500anthony if ( artifact != (const char *) NULL ) { 140447bb5df69322136901ccab9ad266d21ceff50500anthony coeff[0]=StringToDouble(artifact,(char **) NULL) / 2.0; 140547bb5df69322136901ccab9ad266d21ceff50500anthony if ( coeff[0] < MagickEpsilon ) { 140647bb5df69322136901ccab9ad266d21ceff50500anthony (void) ThrowMagickException(exception,GetMagickModule(), 140747bb5df69322136901ccab9ad266d21ceff50500anthony OptionError,"InvalidArgument","%s", "-define shepards:power" ); 140847bb5df69322136901ccab9ad266d21ceff50500anthony coeff=(double *) RelinquishMagickMemory(coeff); 140947bb5df69322136901ccab9ad266d21ceff50500anthony return((double *) NULL); 141047bb5df69322136901ccab9ad266d21ceff50500anthony } 141147bb5df69322136901ccab9ad266d21ceff50500anthony } 141247bb5df69322136901ccab9ad266d21ceff50500anthony else 141347bb5df69322136901ccab9ad266d21ceff50500anthony coeff[0]=1.0; /* Default power of 2 (Inverse Squared) */ 141447bb5df69322136901ccab9ad266d21ceff50500anthony } 14153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(coeff); 14163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 14173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy default: 14183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 14193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 14203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* you should never reach this point */ 1421cf96e67439ab38056f2ec693bd0b0392c732cdf9cristy perror("no method handler"); /* just fail assertion */ 14223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((double *) NULL); 14233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 14243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 14253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/* 14263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 14283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 14293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 14302029ddc50e8860c787be44f997cbb57e457024baanthony+ D i s t o r t R e s i z e I m a g e % 14312029ddc50e8860c787be44f997cbb57e457024baanthony% % 14322029ddc50e8860c787be44f997cbb57e457024baanthony% % 14332029ddc50e8860c787be44f997cbb57e457024baanthony% % 14342029ddc50e8860c787be44f997cbb57e457024baanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14352029ddc50e8860c787be44f997cbb57e457024baanthony% 1436f0a92fd8deb68d411304359906b12679b675691fglennrp% DistortResizeImage() resize image using the equivalent but slower image 14372029ddc50e8860c787be44f997cbb57e457024baanthony% distortion operator. The filter is applied using a EWA cylindrical 14382029ddc50e8860c787be44f997cbb57e457024baanthony% resampling. But like resize the final image size is limited to whole pixels 14392029ddc50e8860c787be44f997cbb57e457024baanthony% with no effects by virtual-pixels on the result. 14402029ddc50e8860c787be44f997cbb57e457024baanthony% 14412029ddc50e8860c787be44f997cbb57e457024baanthony% Note that images containing a transparency channel will be twice as slow to 14422029ddc50e8860c787be44f997cbb57e457024baanthony% resize as images one without transparency. 14432029ddc50e8860c787be44f997cbb57e457024baanthony% 14442029ddc50e8860c787be44f997cbb57e457024baanthony% The format of the DistortResizeImage method is: 14452029ddc50e8860c787be44f997cbb57e457024baanthony% 14468306a8d2a4724da6e922153284f5910e4149b421Cristy% Image *DistortResizeImage(const Image *image,const size_t columns, 14472029ddc50e8860c787be44f997cbb57e457024baanthony% const size_t rows,ExceptionInfo *exception) 14482029ddc50e8860c787be44f997cbb57e457024baanthony% 14492029ddc50e8860c787be44f997cbb57e457024baanthony% A description of each parameter follows: 14502029ddc50e8860c787be44f997cbb57e457024baanthony% 14512029ddc50e8860c787be44f997cbb57e457024baanthony% o image: the image. 14522029ddc50e8860c787be44f997cbb57e457024baanthony% 14532029ddc50e8860c787be44f997cbb57e457024baanthony% o columns: the number of columns in the resized image. 14542029ddc50e8860c787be44f997cbb57e457024baanthony% 14552029ddc50e8860c787be44f997cbb57e457024baanthony% o rows: the number of rows in the resized image. 14562029ddc50e8860c787be44f997cbb57e457024baanthony% 14572029ddc50e8860c787be44f997cbb57e457024baanthony% o exception: return any errors or warnings in this structure. 14582029ddc50e8860c787be44f997cbb57e457024baanthony% 14592029ddc50e8860c787be44f997cbb57e457024baanthony*/ 14602029ddc50e8860c787be44f997cbb57e457024baanthonyMagickExport Image *DistortResizeImage(const Image *image, 14612029ddc50e8860c787be44f997cbb57e457024baanthony const size_t columns,const size_t rows,ExceptionInfo *exception) 14622029ddc50e8860c787be44f997cbb57e457024baanthony{ 14632029ddc50e8860c787be44f997cbb57e457024baanthony#define DistortResizeImageTag "Distort/Image" 14642029ddc50e8860c787be44f997cbb57e457024baanthony 14652029ddc50e8860c787be44f997cbb57e457024baanthony Image 14662029ddc50e8860c787be44f997cbb57e457024baanthony *resize_image, 14672029ddc50e8860c787be44f997cbb57e457024baanthony *tmp_image; 14682029ddc50e8860c787be44f997cbb57e457024baanthony 14692029ddc50e8860c787be44f997cbb57e457024baanthony RectangleInfo 14702029ddc50e8860c787be44f997cbb57e457024baanthony crop_area; 14712029ddc50e8860c787be44f997cbb57e457024baanthony 147247bb5df69322136901ccab9ad266d21ceff50500anthony double 147347bb5df69322136901ccab9ad266d21ceff50500anthony distort_args[12]; 147447bb5df69322136901ccab9ad266d21ceff50500anthony 14752029ddc50e8860c787be44f997cbb57e457024baanthony VirtualPixelMethod 14762029ddc50e8860c787be44f997cbb57e457024baanthony vp_save; 14772029ddc50e8860c787be44f997cbb57e457024baanthony 14782029ddc50e8860c787be44f997cbb57e457024baanthony /* 14792029ddc50e8860c787be44f997cbb57e457024baanthony Distort resize image. 14802029ddc50e8860c787be44f997cbb57e457024baanthony */ 14812029ddc50e8860c787be44f997cbb57e457024baanthony assert(image != (const Image *) NULL); 1482e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(image->signature == MagickCoreSignature); 14832029ddc50e8860c787be44f997cbb57e457024baanthony if (image->debug != MagickFalse) 14842029ddc50e8860c787be44f997cbb57e457024baanthony (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 14852029ddc50e8860c787be44f997cbb57e457024baanthony assert(exception != (ExceptionInfo *) NULL); 1486e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(exception->signature == MagickCoreSignature); 14872029ddc50e8860c787be44f997cbb57e457024baanthony if ((columns == 0) || (rows == 0)) 14882029ddc50e8860c787be44f997cbb57e457024baanthony return((Image *) NULL); 14892029ddc50e8860c787be44f997cbb57e457024baanthony /* Do not short-circuit this resize if final image size is unchanged */ 14902029ddc50e8860c787be44f997cbb57e457024baanthony 14912029ddc50e8860c787be44f997cbb57e457024baanthony (void) ResetMagickMemory(distort_args,0,12*sizeof(double)); 14923fcaccdcc85f3e5c5a2ece7309dfe4792a9b0269cristy distort_args[4]=(double) image->columns; 14933fcaccdcc85f3e5c5a2ece7309dfe4792a9b0269cristy distort_args[6]=(double) columns; 14943fcaccdcc85f3e5c5a2ece7309dfe4792a9b0269cristy distort_args[9]=(double) image->rows; 14953fcaccdcc85f3e5c5a2ece7309dfe4792a9b0269cristy distort_args[11]=(double) rows; 14962029ddc50e8860c787be44f997cbb57e457024baanthony 14972029ddc50e8860c787be44f997cbb57e457024baanthony vp_save=GetImageVirtualPixelMethod(image); 14982029ddc50e8860c787be44f997cbb57e457024baanthony 14992029ddc50e8860c787be44f997cbb57e457024baanthony tmp_image=CloneImage(image,0,0,MagickTrue,exception); 15002029ddc50e8860c787be44f997cbb57e457024baanthony if ( tmp_image == (Image *) NULL ) 15012029ddc50e8860c787be44f997cbb57e457024baanthony return((Image *) NULL); 1502387430f111ba7864990ca03fbc89968e20074ecdcristy (void) SetImageVirtualPixelMethod(tmp_image,TransparentVirtualPixelMethod, 1503387430f111ba7864990ca03fbc89968e20074ecdcristy exception); 15042029ddc50e8860c787be44f997cbb57e457024baanthony 150517f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (image->alpha_trait == UndefinedPixelTrait) 15062029ddc50e8860c787be44f997cbb57e457024baanthony { 15072029ddc50e8860c787be44f997cbb57e457024baanthony /* 15082029ddc50e8860c787be44f997cbb57e457024baanthony Image has not transparency channel, so we free to use it 15092029ddc50e8860c787be44f997cbb57e457024baanthony */ 151063240888c3975789a09c2494a4654b523931df96cristy (void) SetImageAlphaChannel(tmp_image,SetAlphaChannel,exception); 15112029ddc50e8860c787be44f997cbb57e457024baanthony resize_image=DistortImage(tmp_image,AffineDistortion,12,distort_args, 151263240888c3975789a09c2494a4654b523931df96cristy MagickTrue,exception), 15132029ddc50e8860c787be44f997cbb57e457024baanthony 15142029ddc50e8860c787be44f997cbb57e457024baanthony tmp_image=DestroyImage(tmp_image); 15152029ddc50e8860c787be44f997cbb57e457024baanthony if ( resize_image == (Image *) NULL ) 15162029ddc50e8860c787be44f997cbb57e457024baanthony return((Image *) NULL); 15172029ddc50e8860c787be44f997cbb57e457024baanthony 15188306a8d2a4724da6e922153284f5910e4149b421Cristy (void) SetImageAlphaChannel(resize_image,DeactivateAlphaChannel, 15198306a8d2a4724da6e922153284f5910e4149b421Cristy exception); 15202029ddc50e8860c787be44f997cbb57e457024baanthony } 15212029ddc50e8860c787be44f997cbb57e457024baanthony else 15222029ddc50e8860c787be44f997cbb57e457024baanthony { 15232029ddc50e8860c787be44f997cbb57e457024baanthony /* 15242029ddc50e8860c787be44f997cbb57e457024baanthony Image has transparency so handle colors and alpha separatly. 15252029ddc50e8860c787be44f997cbb57e457024baanthony Basically we need to separate Virtual-Pixel alpha in the resized 15262029ddc50e8860c787be44f997cbb57e457024baanthony image, so only the actual original images alpha channel is used. 15272029ddc50e8860c787be44f997cbb57e457024baanthony 1528bd5a96cd2b69f218f85a7adc306296a736f91a56cristy distort alpha channel separately 1529bd5a96cd2b69f218f85a7adc306296a736f91a56cristy */ 15307a4d610ce2d062b39a7aa86c65bfcbf0a9cb29d5anthony Image 15317a4d610ce2d062b39a7aa86c65bfcbf0a9cb29d5anthony *resize_alpha; 15327a4d610ce2d062b39a7aa86c65bfcbf0a9cb29d5anthony 1533c8d636784204aa4d970c212b156bffc387836b93cristy (void) SetImageAlphaChannel(tmp_image,ExtractAlphaChannel,exception); 153463240888c3975789a09c2494a4654b523931df96cristy (void) SetImageAlphaChannel(tmp_image,OpaqueAlphaChannel,exception); 15352029ddc50e8860c787be44f997cbb57e457024baanthony resize_alpha=DistortImage(tmp_image,AffineDistortion,12,distort_args, 15363139dc2f5df8d442e308b381992a0f8579e061e4cristy MagickTrue,exception), 15372029ddc50e8860c787be44f997cbb57e457024baanthony tmp_image=DestroyImage(tmp_image); 15383139dc2f5df8d442e308b381992a0f8579e061e4cristy if (resize_alpha == (Image *) NULL) 15392029ddc50e8860c787be44f997cbb57e457024baanthony return((Image *) NULL); 15402029ddc50e8860c787be44f997cbb57e457024baanthony 15412029ddc50e8860c787be44f997cbb57e457024baanthony /* distort the actual image containing alpha + VP alpha */ 15422029ddc50e8860c787be44f997cbb57e457024baanthony tmp_image=CloneImage(image,0,0,MagickTrue,exception); 15432029ddc50e8860c787be44f997cbb57e457024baanthony if ( tmp_image == (Image *) NULL ) 15442029ddc50e8860c787be44f997cbb57e457024baanthony return((Image *) NULL); 154536421ee45722da418b8ab99d7e6358e4f86b9f1eCristy (void) SetImageVirtualPixelMethod(tmp_image,TransparentVirtualPixelMethod, exception); 15462029ddc50e8860c787be44f997cbb57e457024baanthony resize_image=DistortImage(tmp_image,AffineDistortion,12,distort_args, 15473139dc2f5df8d442e308b381992a0f8579e061e4cristy MagickTrue,exception), 15482029ddc50e8860c787be44f997cbb57e457024baanthony tmp_image=DestroyImage(tmp_image); 15492029ddc50e8860c787be44f997cbb57e457024baanthony if ( resize_image == (Image *) NULL) 15502029ddc50e8860c787be44f997cbb57e457024baanthony { 15512029ddc50e8860c787be44f997cbb57e457024baanthony resize_alpha=DestroyImage(resize_alpha); 15522029ddc50e8860c787be44f997cbb57e457024baanthony return((Image *) NULL); 15532029ddc50e8860c787be44f997cbb57e457024baanthony } 15542029ddc50e8860c787be44f997cbb57e457024baanthony /* replace resize images alpha with the separally distorted alpha */ 15558306a8d2a4724da6e922153284f5910e4149b421Cristy (void) SetImageAlphaChannel(resize_image,OffAlphaChannel,exception); 15568306a8d2a4724da6e922153284f5910e4149b421Cristy (void) SetImageAlphaChannel(resize_alpha,OffAlphaChannel,exception); 1557feb3e9695150978a5d2372d3fe2f60466a7c8066cristy (void) CompositeImage(resize_image,resize_alpha,CopyAlphaCompositeOp, 155839172408bad7ef2ef00a815fa9abf9979e7857cbcristy MagickTrue,0,0,exception); 15592029ddc50e8860c787be44f997cbb57e457024baanthony resize_alpha=DestroyImage(resize_alpha); 15602029ddc50e8860c787be44f997cbb57e457024baanthony } 1561387430f111ba7864990ca03fbc89968e20074ecdcristy (void) SetImageVirtualPixelMethod(resize_image,vp_save,exception); 15622029ddc50e8860c787be44f997cbb57e457024baanthony 15632029ddc50e8860c787be44f997cbb57e457024baanthony /* 15642029ddc50e8860c787be44f997cbb57e457024baanthony Clean up the results of the Distortion 15652029ddc50e8860c787be44f997cbb57e457024baanthony */ 15662029ddc50e8860c787be44f997cbb57e457024baanthony crop_area.width=columns; 15672029ddc50e8860c787be44f997cbb57e457024baanthony crop_area.height=rows; 15682029ddc50e8860c787be44f997cbb57e457024baanthony crop_area.x=0; 15692029ddc50e8860c787be44f997cbb57e457024baanthony crop_area.y=0; 15702029ddc50e8860c787be44f997cbb57e457024baanthony 15712029ddc50e8860c787be44f997cbb57e457024baanthony tmp_image=resize_image; 15722029ddc50e8860c787be44f997cbb57e457024baanthony resize_image=CropImage(tmp_image,&crop_area,exception); 15732029ddc50e8860c787be44f997cbb57e457024baanthony tmp_image=DestroyImage(tmp_image); 15741ca877c27bc1cab1f355b2bf67dffafa97cfc396Cristy if (resize_image != (Image *) NULL) 15751ca877c27bc1cab1f355b2bf67dffafa97cfc396Cristy { 15761ca877c27bc1cab1f355b2bf67dffafa97cfc396Cristy resize_image->alpha_trait=image->alpha_trait; 15771ca877c27bc1cab1f355b2bf67dffafa97cfc396Cristy resize_image->compose=image->compose; 15781ca877c27bc1cab1f355b2bf67dffafa97cfc396Cristy resize_image->page.width=0; 15791ca877c27bc1cab1f355b2bf67dffafa97cfc396Cristy resize_image->page.height=0; 15801ca877c27bc1cab1f355b2bf67dffafa97cfc396Cristy } 15812029ddc50e8860c787be44f997cbb57e457024baanthony return(resize_image); 15822029ddc50e8860c787be44f997cbb57e457024baanthony} 15832029ddc50e8860c787be44f997cbb57e457024baanthony 15842029ddc50e8860c787be44f997cbb57e457024baanthony/* 15852029ddc50e8860c787be44f997cbb57e457024baanthony%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 15862029ddc50e8860c787be44f997cbb57e457024baanthony% % 15872029ddc50e8860c787be44f997cbb57e457024baanthony% % 15882029ddc50e8860c787be44f997cbb57e457024baanthony% % 15893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% D i s t o r t I m a g e % 15903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 15913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 15923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 15933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 15943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 15953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% DistortImage() distorts an image using various distortion methods, by 15963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% mapping color lookups of the source image to a new destination image 15973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% usally of the same size as the source image, unless 'bestfit' is set to 15983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% true. 15993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% If 'bestfit' is enabled, and distortion allows it, the destination image is 16013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% adjusted to ensure the whole source 'image' will just fit within the final 16023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% destination image, which will be sized and offset accordingly. Also in 16033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% many cases the virtual offset of the source image will be taken into 16043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% account in the mapping. 16053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% If the '-verbose' control option has been set print to standard error the 16073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% equicelent '-fx' formula with coefficients for the function, if practical. 16083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% The format of the DistortImage() method is: 16103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 1611827944d54938c1f8a74ff53cd35c11801060d995dirk% Image *DistortImage(const Image *image,const DistortMethod method, 1612bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy% const size_t number_arguments,const double *arguments, 16133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% MagickBooleanType bestfit, ExceptionInfo *exception) 16143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% A description of each parameter follows: 16163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o image: the image to be distorted. 16183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o method: the method of image distortion. 16203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% ArcDistortion always ignores source image offset, and always 16223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 'bestfit' the destination image with the top left corner offset 16233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% relative to the polar mapping center. 16243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Affine, Perspective, and Bilinear, do least squares fitting of the 16263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% distrotion when more than the minimum number of control point pairs 16273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% are provided. 16283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Perspective, and Bilinear, fall back to a Affine distortion when less 16303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% than 4 control point pairs are provided. While Affine distortions 16313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% let you use any number of control point pairs, that is Zero pairs is 16323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% a No-Op (viewport only) distortion, one pair is a translation and 16333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% two pairs of control points do a scale-rotate-translate, without any 16343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% shearing. 16353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o number_arguments: the number of arguments given. 16373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o arguments: an array of floating point arguments for this method. 16393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o bestfit: Attempt to 'bestfit' the size of the resulting image. 16413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% This also forces the resulting image to be a 'layered' virtual 16423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% canvas image. Can be overridden using 'distort:viewport' setting. 16433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o exception: return any errors or warnings in this structure 16453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Extra Controls from Image meta-data (artifacts)... 16473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o "verbose" 16493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Output to stderr alternatives, internal coefficents, and FX 1650f0a92fd8deb68d411304359906b12679b675691fglennrp% equivalents for the distortion operation (if feasible). 16513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% This forms an extra check of the distortion method, and allows users 16523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% access to the internal constants IM calculates for the distortion. 16533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o "distort:viewport" 16553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Directly set the output image canvas area and offest to use for the 16563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% resulting image, rather than use the original images canvas, or a 16573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% calculated 'bestfit' canvas. 16583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o "distort:scale" 16603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Scale the size of the output canvas by this amount to provide a 16613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% method of Zooming, and for super-sampling the results. 16623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Other settings that can effect results include 16643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o 'interpolate' For source image lookups (scale enlargements) 16663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o 'filter' Set filter to use for area-resampling (scale shrinking). 16683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% Set to 'point' to turn off and use 'interpolate' lookup 16693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% instead 16703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 16713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/ 1672827944d54938c1f8a74ff53cd35c11801060d995dirkMagickExport Image *DistortImage(const Image *image, DistortMethod method, 1673bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy const size_t number_arguments,const double *arguments, 16743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy MagickBooleanType bestfit,ExceptionInfo *exception) 16753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 16763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define DistortImageTag "Distort/Image" 16773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 16783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 16793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *coeff, 16803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy output_scaling; 16813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 16823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Image 16833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *distort_image; 16843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 16853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy RectangleInfo 16863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy geometry; /* geometry of the distorted space viewport */ 16873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 16883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy MagickBooleanType 16893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy viewport_given; 16903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 16913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy assert(image != (Image *) NULL); 1692e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(image->signature == MagickCoreSignature); 16933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (image->debug != MagickFalse) 16943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy assert(exception != (ExceptionInfo *) NULL); 1696e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(exception->signature == MagickCoreSignature); 16973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 16982029ddc50e8860c787be44f997cbb57e457024baanthony /* 1699b9aaf9ed2a83b7d8931306fb3313285098072b25anthony Handle Special Compound Distortions 17002029ddc50e8860c787be44f997cbb57e457024baanthony */ 17012029ddc50e8860c787be44f997cbb57e457024baanthony if ( method == ResizeDistortion ) 17022029ddc50e8860c787be44f997cbb57e457024baanthony { 17032029ddc50e8860c787be44f997cbb57e457024baanthony if ( number_arguments != 2 ) 17042029ddc50e8860c787be44f997cbb57e457024baanthony { 17052029ddc50e8860c787be44f997cbb57e457024baanthony (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 17062029ddc50e8860c787be44f997cbb57e457024baanthony "InvalidArgument","%s : '%s'","Resize", 17072029ddc50e8860c787be44f997cbb57e457024baanthony "Invalid number of args: 2 only"); 17082029ddc50e8860c787be44f997cbb57e457024baanthony return((Image *) NULL); 17092029ddc50e8860c787be44f997cbb57e457024baanthony } 17102029ddc50e8860c787be44f997cbb57e457024baanthony distort_image=DistortResizeImage(image,(size_t)arguments[0], 17112029ddc50e8860c787be44f997cbb57e457024baanthony (size_t)arguments[1], exception); 17122029ddc50e8860c787be44f997cbb57e457024baanthony return(distort_image); 17132029ddc50e8860c787be44f997cbb57e457024baanthony } 17142029ddc50e8860c787be44f997cbb57e457024baanthony 17153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 1716b9aaf9ed2a83b7d8931306fb3313285098072b25anthony Convert input arguments (usually as control points for reverse mapping) 17173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy into mapping coefficients to apply the distortion. 17183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 17193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Note that some distortions are mapped to other distortions, 17203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy and as such do not require specific code after this point. 17213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 17223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = GenerateCoefficients(image, &method, number_arguments, 17233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy arguments, 0, exception); 17243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( coeff == (double *) NULL ) 17253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((Image *) NULL); 17263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 17273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 17283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Determine the size and offset for a 'bestfit' destination. 17293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Usally the four corners of the source image is enough. 17303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 17313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 17323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* default output image bounds, when no 'bestfit' is requested */ 17333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy geometry.width=image->columns; 17343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy geometry.height=image->rows; 17353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy geometry.x=0; 17363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy geometry.y=0; 17373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 17383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( method == ArcDistortion ) { 1739b9aaf9ed2a83b7d8931306fb3313285098072b25anthony bestfit = MagickTrue; /* always calculate a 'best fit' viewport */ 17403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 17413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 17423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Work out the 'best fit', (required for ArcDistortion) */ 17433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( bestfit ) { 17443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy PointInfo 1745b9aaf9ed2a83b7d8931306fb3313285098072b25anthony s,d,min,max; /* source, dest coords --mapping--> min, max coords */ 1746b9aaf9ed2a83b7d8931306fb3313285098072b25anthony 1747b9aaf9ed2a83b7d8931306fb3313285098072b25anthony MagickBooleanType 1748b9aaf9ed2a83b7d8931306fb3313285098072b25anthony fix_bounds = MagickTrue; /* enlarge bounds for VP handling */ 17493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 17503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x=s.y=min.x=max.x=min.y=max.y=0.0; /* keep compiler happy */ 17513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 17523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/* defines to figure out the bounds of the distorted image */ 17533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define InitalBounds(p) \ 17543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ \ 17553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* printf("%lg,%lg -> %lg,%lg\n", s.x,s.y, d.x,d.y); */ \ 17563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy min.x = max.x = p.x; \ 17573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy min.y = max.y = p.y; \ 17583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 17593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define ExpandBounds(p) \ 17603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ \ 17613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* printf("%lg,%lg -> %lg,%lg\n", s.x,s.y, d.x,d.y); */ \ 17623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy min.x = MagickMin(min.x,p.x); \ 17633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy max.x = MagickMax(max.x,p.x); \ 17643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy min.y = MagickMin(min.y,p.y); \ 17653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy max.y = MagickMax(max.y,p.y); \ 17663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 17673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 17683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy switch (method) 17693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 17703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case AffineDistortion: 17713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { double inverse[6]; 17723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy InvertAffineCoefficients(coeff, inverse); 17733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x = (double) image->page.x; 17743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y = (double) image->page.y; 17753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x = inverse[0]*s.x+inverse[1]*s.y+inverse[2]; 17763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y = inverse[3]*s.x+inverse[4]*s.y+inverse[5]; 17773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy InitalBounds(d); 17783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x = (double) image->page.x+image->columns; 17793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y = (double) image->page.y; 17803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x = inverse[0]*s.x+inverse[1]*s.y+inverse[2]; 17813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y = inverse[3]*s.x+inverse[4]*s.y+inverse[5]; 17823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ExpandBounds(d); 17833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x = (double) image->page.x; 17843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y = (double) image->page.y+image->rows; 17853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x = inverse[0]*s.x+inverse[1]*s.y+inverse[2]; 17863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y = inverse[3]*s.x+inverse[4]*s.y+inverse[5]; 17873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ExpandBounds(d); 17883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x = (double) image->page.x+image->columns; 17893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y = (double) image->page.y+image->rows; 17903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x = inverse[0]*s.x+inverse[1]*s.y+inverse[2]; 17913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y = inverse[3]*s.x+inverse[4]*s.y+inverse[5]; 17923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ExpandBounds(d); 17933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 17943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 17953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PerspectiveDistortion: 17963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { double inverse[8], scale; 17973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy InvertPerspectiveCoefficients(coeff, inverse); 17983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x = (double) image->page.x; 17993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y = (double) image->page.y; 18003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy scale=inverse[6]*s.x+inverse[7]*s.y+1.0; 18013e3ec3afbb0782697f201cbe30a56794c10dc7efcristy scale=PerceptibleReciprocal(scale); 18023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x = scale*(inverse[0]*s.x+inverse[1]*s.y+inverse[2]); 18033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y = scale*(inverse[3]*s.x+inverse[4]*s.y+inverse[5]); 18043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy InitalBounds(d); 18053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x = (double) image->page.x+image->columns; 18063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y = (double) image->page.y; 18073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy scale=inverse[6]*s.x+inverse[7]*s.y+1.0; 18083e3ec3afbb0782697f201cbe30a56794c10dc7efcristy scale=PerceptibleReciprocal(scale); 18093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x = scale*(inverse[0]*s.x+inverse[1]*s.y+inverse[2]); 18103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y = scale*(inverse[3]*s.x+inverse[4]*s.y+inverse[5]); 18113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ExpandBounds(d); 18123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x = (double) image->page.x; 18133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y = (double) image->page.y+image->rows; 18143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy scale=inverse[6]*s.x+inverse[7]*s.y+1.0; 18153e3ec3afbb0782697f201cbe30a56794c10dc7efcristy scale=PerceptibleReciprocal(scale); 18163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x = scale*(inverse[0]*s.x+inverse[1]*s.y+inverse[2]); 18173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y = scale*(inverse[3]*s.x+inverse[4]*s.y+inverse[5]); 18183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ExpandBounds(d); 18193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x = (double) image->page.x+image->columns; 18203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y = (double) image->page.y+image->rows; 18213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy scale=inverse[6]*s.x+inverse[7]*s.y+1.0; 18223e3ec3afbb0782697f201cbe30a56794c10dc7efcristy scale=PerceptibleReciprocal(scale); 18233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x = scale*(inverse[0]*s.x+inverse[1]*s.y+inverse[2]); 18243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y = scale*(inverse[3]*s.x+inverse[4]*s.y+inverse[5]); 18253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ExpandBounds(d); 18263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 18273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 18283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case ArcDistortion: 18293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { double a, ca, sa; 18303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Forward Map Corners */ 18313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy a = coeff[0]-coeff[1]/2; ca = cos(a); sa = sin(a); 18323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x = coeff[2]*ca; 18333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y = coeff[2]*sa; 18343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy InitalBounds(d); 18353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x = (coeff[2]-coeff[3])*ca; 18363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y = (coeff[2]-coeff[3])*sa; 18373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ExpandBounds(d); 18383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy a = coeff[0]+coeff[1]/2; ca = cos(a); sa = sin(a); 18393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x = coeff[2]*ca; 18403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y = coeff[2]*sa; 18413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ExpandBounds(d); 18423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x = (coeff[2]-coeff[3])*ca; 18433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y = (coeff[2]-coeff[3])*sa; 18443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ExpandBounds(d); 1845cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy /* Orthogonal points along top of arc */ 1846ba978e102735661f7777d22c1674d1d974303072cristy for( a=(double) (ceil((double) ((coeff[0]-coeff[1]/2.0)/MagickPI2))*MagickPI2); 18473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy a<(coeff[0]+coeff[1]/2.0); a+=MagickPI2 ) { 18483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ca = cos(a); sa = sin(a); 18493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x = coeff[2]*ca; 18503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y = coeff[2]*sa; 18513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ExpandBounds(d); 18523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 18533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 18543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Convert the angle_to_width and radius_to_height 18553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy to appropriate scaling factors, to allow faster processing 18563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy in the mapping function. 18573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 1858ba978e102735661f7777d22c1674d1d974303072cristy coeff[1] = (double) (Magick2PI*image->columns/coeff[1]); 18593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[3] = (double)image->rows/coeff[3]; 18603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 18613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 18623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PolarDistortion: 18633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 18643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (number_arguments < 2) 18653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[2] = coeff[3] = 0.0; 18663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy min.x = coeff[2]-coeff[0]; 18673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy max.x = coeff[2]+coeff[0]; 18683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy min.y = coeff[3]-coeff[0]; 18693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy max.y = coeff[3]+coeff[0]; 18703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* should be about 1.0 if Rmin = 0 */ 18713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[7]=(double) geometry.height/(coeff[0]-coeff[1]); 18723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 18733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 18743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case DePolarDistortion: 18753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 18763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* direct calculation as it needs to tile correctly 18773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy * for reversibility in a DePolar-Polar cycle */ 1878b9aaf9ed2a83b7d8931306fb3313285098072b25anthony fix_bounds = MagickFalse; 18793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy geometry.x = geometry.y = 0; 1880bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy geometry.height = (size_t) ceil(coeff[0]-coeff[1]); 1881bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy geometry.width = (size_t) 18823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ceil((coeff[0]-coeff[1])*(coeff[5]-coeff[4])*0.5); 1883b9aaf9ed2a83b7d8931306fb3313285098072b25anthony /* correct scaling factors relative to new size */ 1884b9aaf9ed2a83b7d8931306fb3313285098072b25anthony coeff[6]=(coeff[5]-coeff[4])/geometry.width; /* changed width */ 1885b9aaf9ed2a83b7d8931306fb3313285098072b25anthony coeff[7]=(coeff[0]-coeff[1])/geometry.height; /* should be about 1.0 */ 1886b9aaf9ed2a83b7d8931306fb3313285098072b25anthony break; 1887b9aaf9ed2a83b7d8931306fb3313285098072b25anthony } 1888e0d9bbde3eb1826c767fee326a5786a9f28a191banthony case Cylinder2PlaneDistortion: 1889b9aaf9ed2a83b7d8931306fb3313285098072b25anthony { 1890b9aaf9ed2a83b7d8931306fb3313285098072b25anthony /* direct calculation so center of distortion is either a pixel 1891b9aaf9ed2a83b7d8931306fb3313285098072b25anthony * center, or pixel edge. This allows for reversibility of the 1892b9aaf9ed2a83b7d8931306fb3313285098072b25anthony * distortion */ 1893b9aaf9ed2a83b7d8931306fb3313285098072b25anthony geometry.x = geometry.y = 0; 18944c08aed51c5899665ade97263692328eea4af106cristy geometry.width = (size_t) ceil( 2.0*coeff[1]*tan(coeff[0]/2.0) ); 18954c08aed51c5899665ade97263692328eea4af106cristy geometry.height = (size_t) ceil( 2.0*coeff[3]/cos(coeff[0]/2.0) ); 1896b9aaf9ed2a83b7d8931306fb3313285098072b25anthony /* correct center of distortion relative to new size */ 18974c08aed51c5899665ade97263692328eea4af106cristy coeff[4] = (double) geometry.width/2.0; 18984c08aed51c5899665ade97263692328eea4af106cristy coeff[5] = (double) geometry.height/2.0; 1899b9aaf9ed2a83b7d8931306fb3313285098072b25anthony fix_bounds = MagickFalse; 19003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 19013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 1902e0d9bbde3eb1826c767fee326a5786a9f28a191banthony case Plane2CylinderDistortion: 1903b9aaf9ed2a83b7d8931306fb3313285098072b25anthony { 1904b9aaf9ed2a83b7d8931306fb3313285098072b25anthony /* direct calculation center is either pixel center, or pixel edge 1905b9aaf9ed2a83b7d8931306fb3313285098072b25anthony * so as to allow reversibility of the image distortion */ 1906b9aaf9ed2a83b7d8931306fb3313285098072b25anthony geometry.x = geometry.y = 0; 19074c08aed51c5899665ade97263692328eea4af106cristy geometry.width = (size_t) ceil(coeff[0]*coeff[1]); /* FOV * radius */ 19084c08aed51c5899665ade97263692328eea4af106cristy geometry.height = (size_t) (2*coeff[3]); /* input image height */ 1909b9aaf9ed2a83b7d8931306fb3313285098072b25anthony /* correct center of distortion relative to new size */ 19104c08aed51c5899665ade97263692328eea4af106cristy coeff[4] = (double) geometry.width/2.0; 19114c08aed51c5899665ade97263692328eea4af106cristy coeff[5] = (double) geometry.height/2.0; 1912b9aaf9ed2a83b7d8931306fb3313285098072b25anthony fix_bounds = MagickFalse; 1913b9aaf9ed2a83b7d8931306fb3313285098072b25anthony break; 1914b9aaf9ed2a83b7d8931306fb3313285098072b25anthony } 19153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case ShepardsDistortion: 19163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BilinearForwardDistortion: 19173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BilinearReverseDistortion: 19185056b230558c7de0a79d51d82bdc929fef45a225anthony#if 0 19195056b230558c7de0a79d51d82bdc929fef45a225anthony case QuadrilateralDistortion: 19205056b230558c7de0a79d51d82bdc929fef45a225anthony#endif 19213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PolynomialDistortion: 19223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BarrelDistortion: 19233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BarrelInverseDistortion: 19243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy default: 1925b9aaf9ed2a83b7d8931306fb3313285098072b25anthony /* no calculated bestfit available for these distortions */ 19263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy bestfit = MagickFalse; 1927b9aaf9ed2a83b7d8931306fb3313285098072b25anthony fix_bounds = MagickFalse; 19283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 19293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 19304cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony 19314cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony /* Set the output image geometry to calculated 'bestfit'. 19324cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony Yes this tends to 'over do' the file image size, ON PURPOSE! 19334cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony Do not do this for DePolar which needs to be exact for virtual tiling. 19343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 1935b9aaf9ed2a83b7d8931306fb3313285098072b25anthony if ( fix_bounds ) { 1936bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy geometry.x = (ssize_t) floor(min.x-0.5); 1937bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy geometry.y = (ssize_t) floor(min.y-0.5); 1938bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy geometry.width=(size_t) ceil(max.x-geometry.x+0.5); 1939bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy geometry.height=(size_t) ceil(max.y-geometry.y+0.5); 19403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 19414cf1d89eb32104b1bed4aa71490bc91d4f6c0efeanthony 19424c08aed51c5899665ade97263692328eea4af106cristy } /* end bestfit destination image calculations */ 19433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 19443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* The user provided a 'viewport' expert option which may 19453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy overrides some parts of the current output image geometry. 1946b9aaf9ed2a83b7d8931306fb3313285098072b25anthony This also overrides its default 'bestfit' setting. 19473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 19483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { const char *artifact=GetImageArtifact(image,"distort:viewport"); 19493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy viewport_given = MagickFalse; 19503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( artifact != (const char *) NULL ) { 19519cb63ccb02272521283da6d251068d91196cc5bfanthony MagickStatusType flags=ParseAbsoluteGeometry(artifact,&geometry); 19529cb63ccb02272521283da6d251068d91196cc5bfanthony if (flags==NoValue) 195322de2722b682eb405b60ec6022a7546df994674eanthony (void) ThrowMagickException(exception,GetMagickModule(), 195422de2722b682eb405b60ec6022a7546df994674eanthony OptionWarning,"InvalidSetting","'%s' '%s'", 195522de2722b682eb405b60ec6022a7546df994674eanthony "distort:viewport",artifact); 19569cb63ccb02272521283da6d251068d91196cc5bfanthony else 195722de2722b682eb405b60ec6022a7546df994674eanthony viewport_given = MagickTrue; 19583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 19593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 19603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 19613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Verbose output */ 1962972c2e42a2171341bbf55a48cb36882616a591b1dirk if (IsStringTrue(GetImageArtifact(image,"verbose")) != MagickFalse) { 1963bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 19643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy i; 1965151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy char image_gen[MagickPathExtent]; 19663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy const char *lookup; 19673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 19683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Set destination image size and virtual offset */ 19693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( bestfit || viewport_given ) { 1970151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy (void) FormatLocaleString(image_gen, MagickPathExtent," -size %.20gx%.20g " 197188ef4d9fc7a5b3b5a194b1c5736df5360c830344anthony "-page %+.20g%+.20g xc: +insert \\\n",(double) geometry.width, 1972e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy (double) geometry.height,(double) geometry.x,(double) geometry.y); 1973d2a90402dad613980c957433ecff73d2f4a99f8aanthony lookup="v.p{ xx-v.page.x-.5, yy-v.page.y-.5 }"; 19743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 19753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else { 19763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy image_gen[0] = '\0'; /* no destination to generate */ 1977d2a90402dad613980c957433ecff73d2f4a99f8aanthony lookup = "p{ xx-page.x-.5, yy-page.y-.5 }"; /* simplify lookup */ 19783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 19793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 19803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy switch (method) { 19813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case AffineDistortion: 19823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 19833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double *inverse; 19843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 19853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse = (double *) AcquireQuantumMemory(6,sizeof(*inverse)); 19863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (inverse == (double *) NULL) { 19873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 19883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(), 19893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ResourceLimitError,"MemoryAllocationFailed", 19903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy "%s", "DistortImages"); 19913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((Image *) NULL); 19923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 19933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy InvertAffineCoefficients(coeff, inverse); 19943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy CoefficientsToAffineArgs(inverse); 19955acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Affine Projection:\n"); 19965acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -distort AffineProjection \\\n '"); 19971e604812fad85bb96f757a2393015ae3d061c39acristy for (i=0; i < 5; i++) 19985acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%lf,", inverse[i]); 19995acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%lf'\n", inverse[5]); 20003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse = (double *) RelinquishMagickMemory(inverse); 20013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 20025acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Affine Distort, FX Equivelent:\n"); 20035acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%s", image_gen); 20045acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n"); 20055acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " xx=%+lf*ii %+lf*jj %+lf;\n", 20063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0], coeff[1], coeff[2]); 20075acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " yy=%+lf*ii %+lf*jj %+lf;\n", 20083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[3], coeff[4], coeff[5]); 2009b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " %s' \\\n", lookup); 20103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 20113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 20123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 20133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 20143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PerspectiveDistortion: 20153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 20163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double *inverse; 20173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 20183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse = (double *) AcquireQuantumMemory(8,sizeof(*inverse)); 20193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (inverse == (double *) NULL) { 20203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 20213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(), 20223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ResourceLimitError,"MemoryAllocationFailed", 20233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy "%s", "DistortCoefficients"); 20243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((Image *) NULL); 20253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 20263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy InvertPerspectiveCoefficients(coeff, inverse); 20275acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Perspective Projection:\n"); 20285acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -distort PerspectiveProjection \\\n '"); 20293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for (i=0; i<4; i++) 20305acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%lf, ", inverse[i]); 20315acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "\n "); 20323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for (; i<7; i++) 20335acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%lf, ", inverse[i]); 20345acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%lf'\n", inverse[7]); 20353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy inverse = (double *) RelinquishMagickMemory(inverse); 20363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 20375acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Perspective Distort, FX Equivelent:\n"); 20385acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%s", image_gen); 20395acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n"); 20405acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " rr=%+lf*ii %+lf*jj + 1;\n", 20413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[6], coeff[7]); 20425acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " xx=(%+lf*ii %+lf*jj %+lf)/rr;\n", 20433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0], coeff[1], coeff[2]); 20445acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " yy=(%+lf*ii %+lf*jj %+lf)/rr;\n", 20453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[3], coeff[4], coeff[5]); 2046b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " rr%s0 ? %s : blue' \\\n", 20473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[8] < 0 ? "<" : ">", lookup); 20483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 20493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 20503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 20513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BilinearForwardDistortion: 20525acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "BilinearForward Mapping Equations:\n"); 20535acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%s", image_gen); 20545acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " i = %+lf*x %+lf*y %+lf*x*y %+lf;\n", 20553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0], coeff[1], coeff[2], coeff[3]); 20565acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " j = %+lf*x %+lf*y %+lf*x*y %+lf;\n", 20573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[4], coeff[5], coeff[6], coeff[7]); 20585056b230558c7de0a79d51d82bdc929fef45a225anthony#if 0 20595056b230558c7de0a79d51d82bdc929fef45a225anthony /* for debugging */ 20605acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " c8 = %+lf c9 = 2*a = %+lf;\n", 20615056b230558c7de0a79d51d82bdc929fef45a225anthony coeff[8], coeff[9]); 20625056b230558c7de0a79d51d82bdc929fef45a225anthony#endif 20635acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "BilinearForward Distort, FX Equivelent:\n"); 20645acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%s", image_gen); 20655acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -fx 'ii=i+page.x%+lf; jj=j+page.y%+lf;\n", 20663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 0.5-coeff[3], 0.5-coeff[7]); 20675acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " bb=%lf*ii %+lf*jj %+lf;\n", 20683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[6], -coeff[2], coeff[8]); 20695056b230558c7de0a79d51d82bdc929fef45a225anthony /* Handle Special degenerate (non-quadratic) or trapezoidal case */ 20705056b230558c7de0a79d51d82bdc929fef45a225anthony if ( coeff[9] != 0 ) { 20715acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " rt=bb*bb %+lf*(%lf*ii%+lf*jj);\n", 20725056b230558c7de0a79d51d82bdc929fef45a225anthony -2*coeff[9], coeff[4], -coeff[0]); 20735acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " yy=( -bb + sqrt(rt) ) / %lf;\n", 20745056b230558c7de0a79d51d82bdc929fef45a225anthony coeff[9]); 20755056b230558c7de0a79d51d82bdc929fef45a225anthony } else 20765acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " yy=(%lf*ii%+lf*jj)/bb;\n", 20775056b230558c7de0a79d51d82bdc929fef45a225anthony -coeff[4], coeff[0]); 20785acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " xx=(ii %+lf*yy)/(%lf %+lf*yy);\n", 20793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy -coeff[1], coeff[0], coeff[2]); 20805056b230558c7de0a79d51d82bdc929fef45a225anthony if ( coeff[9] != 0 ) 20815acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " (rt < 0 ) ? red : %s'\n", lookup); 20825056b230558c7de0a79d51d82bdc929fef45a225anthony else 2083b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " %s' \\\n", lookup); 20843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 20853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 20863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BilinearReverseDistortion: 2087fbe952e8ee289004f7021464a37935ee1b97ab2aanthony#if 0 20885acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Polynomial Projection Distort:\n"); 20895acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -distort PolynomialProjection \\\n"); 20905acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " '1.5, %lf, %lf, %lf, %lf,\n", 20915056b230558c7de0a79d51d82bdc929fef45a225anthony coeff[3], coeff[0], coeff[1], coeff[2]); 20925acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " %lf, %lf, %lf, %lf'\n", 20935056b230558c7de0a79d51d82bdc929fef45a225anthony coeff[7], coeff[4], coeff[5], coeff[6]); 2094fbe952e8ee289004f7021464a37935ee1b97ab2aanthony#endif 20955acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "BilinearReverse Distort, FX Equivelent:\n"); 20965acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%s", image_gen); 20975acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n"); 20985acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " xx=%+lf*ii %+lf*jj %+lf*ii*jj %+lf;\n", 20993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0], coeff[1], coeff[2], coeff[3]); 21005acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " yy=%+lf*ii %+lf*jj %+lf*ii*jj %+lf;\n", 21013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[4], coeff[5], coeff[6], coeff[7]); 2102b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " %s' \\\n", lookup); 21033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 21043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 21053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PolynomialDistortion: 21063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 2107bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t nterms = (size_t) coeff[1]; 21085acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Polynomial (order %lg, terms %lu), FX Equivelent\n", 2109f2faecf9facdbbb14fcba373365f9f691a9658e0cristy coeff[0],(unsigned long) nterms); 21105acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%s", image_gen); 21115acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n"); 21125acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " xx ="); 2113bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i<(ssize_t) nterms; i++) { 21145acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy if ( i != 0 && i%4 == 0 ) (void) FormatLocaleFile(stderr, "\n "); 21155acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " %+lf%s", coeff[2+i], 21163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy poly_basis_str(i)); 21173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 21185acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, ";\n yy ="); 2119bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i<(ssize_t) nterms; i++) { 21205acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy if ( i != 0 && i%4 == 0 ) (void) FormatLocaleFile(stderr, "\n "); 21215acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " %+lf%s", coeff[2+i+nterms], 21223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy poly_basis_str(i)); 21233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 2124b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, ";\n %s' \\\n", lookup); 21253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 21263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 21273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case ArcDistortion: 21283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 21295acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Arc Distort, Internal Coefficients:\n"); 21303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for ( i=0; i<5; i++ ) 21315acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " c%.20g = %+lf\n", (double) i, coeff[i]); 21325acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Arc Distort, FX Equivelent:\n"); 21335acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%s", image_gen); 21345acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -fx 'ii=i+page.x; jj=j+page.y;\n"); 21355acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " xx=(atan2(jj,ii)%+lf)/(2*pi);\n", 21363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy -coeff[0]); 21375acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " xx=xx-round(xx);\n"); 21385acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " xx=xx*%lf %+lf;\n", 21393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[1], coeff[4]); 21405acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " yy=(%lf - hypot(ii,jj)) * %lf;\n", 21413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[2], coeff[3]); 2142b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " v.p{xx-.5,yy-.5}' \\\n"); 21433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 21443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 21453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PolarDistortion: 21463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 21475acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Polar Distort, Internal Coefficents\n"); 21483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for ( i=0; i<8; i++ ) 21495acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " c%.20g = %+lf\n", (double) i, coeff[i]); 21505acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Polar Distort, FX Equivelent:\n"); 21515acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%s", image_gen); 21525acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -fx 'ii=i+page.x%+lf; jj=j+page.y%+lf;\n", 21533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy -coeff[2], -coeff[3]); 21545acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " xx=(atan2(ii,jj)%+lf)/(2*pi);\n", 21553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy -(coeff[4]+coeff[5])/2 ); 21565acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " xx=xx-round(xx);\n"); 21575acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " xx=xx*2*pi*%lf + v.w/2;\n", 21583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[6] ); 21595acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " yy=(hypot(ii,jj)%+lf)*%lf;\n", 21603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy -coeff[1], coeff[7] ); 2161b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " v.p{xx-.5,yy-.5}' \\\n"); 21623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 21633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 21643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case DePolarDistortion: 21653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 21665acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "DePolar Distort, Internal Coefficents\n"); 21673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for ( i=0; i<8; i++ ) 21685acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " c%.20g = %+lf\n", (double) i, coeff[i]); 21695acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "DePolar Distort, FX Equivelent:\n"); 21705acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%s", image_gen); 217173144553d112665377fdd6f1ab5e152cff02b956anthony (void) FormatLocaleFile(stderr, " -fx 'aa=(i+.5)*%lf %+lf;\n", coeff[6], +coeff[4] ); 21725acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " rr=(j+.5)*%lf %+lf;\n", coeff[7], +coeff[1] ); 21735acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " xx=rr*sin(aa) %+lf;\n", coeff[2] ); 21745acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " yy=rr*cos(aa) %+lf;\n", coeff[3] ); 2175b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " v.p{xx-.5,yy-.5}' \\\n"); 2176b9aaf9ed2a83b7d8931306fb3313285098072b25anthony break; 2177b9aaf9ed2a83b7d8931306fb3313285098072b25anthony } 2178e0d9bbde3eb1826c767fee326a5786a9f28a191banthony case Cylinder2PlaneDistortion: 2179b9aaf9ed2a83b7d8931306fb3313285098072b25anthony { 2180b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, "Cylinder to Plane Distort, Internal Coefficents\n"); 2181b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " cylinder_radius = %+lf\n", coeff[1]); 2182b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, "Cylinder to Plane Distort, FX Equivelent:\n"); 2183b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, "%s", image_gen); 2184b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " -fx 'ii=i+page.x%+lf+0.5; jj=j+page.y%+lf+0.5;\n", 2185b9aaf9ed2a83b7d8931306fb3313285098072b25anthony -coeff[4], -coeff[5]); 2186b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " aa=atan(ii/%+lf);\n", coeff[1] ); 2187b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " xx=%lf*aa%+lf;\n", 2188b9aaf9ed2a83b7d8931306fb3313285098072b25anthony coeff[1], coeff[2] ); 2189b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " yy=jj*cos(aa)%+lf;\n", coeff[3] ); 2190b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " %s' \\\n", lookup); 2191b9aaf9ed2a83b7d8931306fb3313285098072b25anthony break; 2192b9aaf9ed2a83b7d8931306fb3313285098072b25anthony } 2193e0d9bbde3eb1826c767fee326a5786a9f28a191banthony case Plane2CylinderDistortion: 2194b9aaf9ed2a83b7d8931306fb3313285098072b25anthony { 2195b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, "Plane to Cylinder Distort, Internal Coefficents\n"); 2196b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " cylinder_radius = %+lf\n", coeff[1]); 2197b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, "Plane to Cylinder Distort, FX Equivelent:\n"); 2198b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, "%s", image_gen); 2199b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " -fx 'ii=i+page.x%+lf+0.5; jj=j+page.y%+lf+0.5;\n", 2200b9aaf9ed2a83b7d8931306fb3313285098072b25anthony -coeff[4], -coeff[5]); 2201b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " ii=ii/%+lf;\n", coeff[1] ); 2202b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " xx=%lf*tan(ii)%+lf;\n", 2203b9aaf9ed2a83b7d8931306fb3313285098072b25anthony coeff[1], coeff[2] ); 2204b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " yy=jj/cos(ii)%+lf;\n", 2205b9aaf9ed2a83b7d8931306fb3313285098072b25anthony coeff[3] ); 2206b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " %s' \\\n", lookup); 2207b9aaf9ed2a83b7d8931306fb3313285098072b25anthony break; 22083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 22093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BarrelDistortion: 22103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BarrelInverseDistortion: 22113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { double xc,yc; 2212ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony /* NOTE: This does the barrel roll in pixel coords not image coords 2213ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony ** The internal distortion must do it in image coordinates, 2214ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony ** so that is what the center coeff (8,9) is given in. 2215ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony */ 22163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy xc = ((double)image->columns-1.0)/2.0 + image->page.x; 22173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy yc = ((double)image->rows-1.0)/2.0 + image->page.y; 22185acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Barrel%s Distort, FX Equivelent:\n", 22193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy method == BarrelDistortion ? "" : "Inv"); 22205acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "%s", image_gen); 2221ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony if ( fabs(coeff[8]-xc-0.5) < 0.1 && fabs(coeff[9]-yc-0.5) < 0.1 ) 22225acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -fx 'xc=(w-1)/2; yc=(h-1)/2;\n"); 22233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else 22245acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -fx 'xc=%lf; yc=%lf;\n", 2225ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony coeff[8]-0.5, coeff[9]-0.5); 22265acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, 22273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy " ii=i-xc; jj=j-yc; rr=hypot(ii,jj);\n"); 22285acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " ii=ii%s(%lf*rr*rr*rr %+lf*rr*rr %+lf*rr %+lf);\n", 22293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy method == BarrelDistortion ? "*" : "/", 22303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0],coeff[1],coeff[2],coeff[3]); 22315acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " jj=jj%s(%lf*rr*rr*rr %+lf*rr*rr %+lf*rr %+lf);\n", 22323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy method == BarrelDistortion ? "*" : "/", 22333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[4],coeff[5],coeff[6],coeff[7]); 2234b9aaf9ed2a83b7d8931306fb3313285098072b25anthony (void) FormatLocaleFile(stderr, " v.p{fx*ii+xc,fy*jj+yc}' \\\n"); 22353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 22363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy default: 22373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 22383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 22393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 22403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 22413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* The user provided a 'scale' expert option will scale the 22423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy output image size, by the factor given allowing for super-sampling 22433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy of the distorted image space. Any scaling factors must naturally 22443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy be halved as a result. 22453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 22463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { const char *artifact; 22473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy artifact=GetImageArtifact(image,"distort:scale"); 22483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy output_scaling = 1.0; 22493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (artifact != (const char *) NULL) { 2250dbdd0e35efc03c9bccda644f5407db38b7c17eeccristy output_scaling = fabs(StringToDouble(artifact,(char **) NULL)); 2251003ea07237ca13637960e607f6686bd3cf03ef00cristy geometry.width=(size_t) (output_scaling*geometry.width+0.5); 2252003ea07237ca13637960e607f6686bd3cf03ef00cristy geometry.height=(size_t) (output_scaling*geometry.height+0.5); 2253003ea07237ca13637960e607f6686bd3cf03ef00cristy geometry.x=(ssize_t) (output_scaling*geometry.x+0.5); 2254003ea07237ca13637960e607f6686bd3cf03ef00cristy geometry.y=(ssize_t) (output_scaling*geometry.y+0.5); 22553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( output_scaling < 0.1 ) { 22563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 22573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 22583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy "InvalidArgument","%s", "-set option:distort:scale" ); 22593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((Image *) NULL); 22603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 22613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy output_scaling = 1/output_scaling; 22623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 22633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 22643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define ScaleFilter(F,A,B,C,D) \ 22653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ScaleResampleFilter( (F), \ 22663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy output_scaling*(A), output_scaling*(B), \ 22673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy output_scaling*(C), output_scaling*(D) ) 22683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 22693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 22703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Initialize the distort image attributes. 22713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 22723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy distort_image=CloneImage(image,geometry.width,geometry.height,MagickTrue, 22733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy exception); 22743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (distort_image == (Image *) NULL) 22753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((Image *) NULL); 2276b6d08c51e1666814b156d42aef650f41d33a87baanthony /* if image is ColorMapped - change it to DirectClass */ 2277574cc26500992189f637cd1cdf93d0654e7df7aecristy if (SetImageStorageClass(distort_image,DirectClass,exception) == MagickFalse) 2278b6d08c51e1666814b156d42aef650f41d33a87baanthony { 22793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy distort_image=DestroyImage(distort_image); 22803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((Image *) NULL); 22813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 2282a6400b1cfc3594644a0f02f3d77d920092f078eecristy if ((IsPixelInfoGray(&distort_image->background_color) == MagickFalse) && 2283a6400b1cfc3594644a0f02f3d77d920092f078eecristy (IsGrayColorspace(distort_image->colorspace) != MagickFalse)) 22840c81d063030f7b30a97c7856e95534243cdc9e13cristy (void) SetImageColorspace(distort_image,sRGBColorspace,exception); 228517f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy if (distort_image->background_color.alpha_trait != UndefinedPixelTrait) 22868a46d827a124555f0c48fb2368ec1bba8e079ab6cristy distort_image->alpha_trait=BlendPixelTrait; 22876386b796857c3ef5db3858ebb2d64373273082b1cristy distort_image->page.x=geometry.x; 22886386b796857c3ef5db3858ebb2d64373273082b1cristy distort_image->page.y=geometry.y; 22893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 22903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { /* ----- MAIN CODE ----- 22913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Sample the source image to each pixel in the distort image. 22923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 2293b65a5b83785ab7b6a8f6fc2d47ba5dca776143bbcristy CacheView 2294b65a5b83785ab7b6a8f6fc2d47ba5dca776143bbcristy *distort_view; 2295b65a5b83785ab7b6a8f6fc2d47ba5dca776143bbcristy 22965f959473f334e196c6bf39b740c12cb4963fceebcristy MagickBooleanType 22973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status; 22983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 22995f959473f334e196c6bf39b740c12cb4963fceebcristy MagickOffsetType 23005f959473f334e196c6bf39b740c12cb4963fceebcristy progress; 23015f959473f334e196c6bf39b740c12cb4963fceebcristy 23024c08aed51c5899665ade97263692328eea4af106cristy PixelInfo 23033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy zero; 23043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 23053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ResampleFilter 230605d2ff7ebf21f659f5b11e45afb294e152f4330cdirk **magick_restrict resample_filter; 23073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 23085f959473f334e196c6bf39b740c12cb4963fceebcristy ssize_t 2309cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy j; 23105f959473f334e196c6bf39b740c12cb4963fceebcristy 23113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status=MagickTrue; 23123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy progress=0; 23134c08aed51c5899665ade97263692328eea4af106cristy GetPixelInfo(distort_image,&zero); 2314b2a11ae782e3f5ba1c020d944bc5ff8382d378fecristy resample_filter=AcquireResampleFilterThreadSet(image, 2315b2a11ae782e3f5ba1c020d944bc5ff8382d378fecristy UndefinedVirtualPixelMethod,MagickFalse,exception); 231646ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy distort_view=AcquireAuthenticCacheView(distort_image,exception); 2317b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 2318ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy #pragma omp parallel for schedule(static,4) shared(progress,status) \ 23195e6b259130f9dbe0da4666f734937017babe573acristy magick_threads(image,distort_image,distort_image->rows,1) 23203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif 2321bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (j=0; j < (ssize_t) distort_image->rows; j++) 23223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 23235c9e6f2ec2e7738ede83902931da0f80db60f565cristy const int 23245c9e6f2ec2e7738ede83902931da0f80db60f565cristy id = GetOpenMPThreadId(); 23255c9e6f2ec2e7738ede83902931da0f80db60f565cristy 23263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 23273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy validity; /* how mathematically valid is this the mapping */ 23283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 23293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy MagickBooleanType 23303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sync; 23313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 23324c08aed51c5899665ade97263692328eea4af106cristy PixelInfo 23333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy pixel, /* pixel color to assign to distorted image */ 23343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy invalid; /* the color to assign when distort result is invalid */ 23353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 23363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy PointInfo 2337b2a11ae782e3f5ba1c020d944bc5ff8382d378fecristy d, 2338b2a11ae782e3f5ba1c020d944bc5ff8382d378fecristy s; /* transform destination image x,y to source image x,y */ 23393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 2340bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 2341688cc42ece058cfd749a7e941d3abee7af7cdaa5cristy i; 23423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 23434c08aed51c5899665ade97263692328eea4af106cristy register Quantum 234405d2ff7ebf21f659f5b11e45afb294e152f4330cdirk *magick_restrict q; 23453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 23463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy q=QueueCacheViewAuthenticPixels(distort_view,0,j,distort_image->columns,1, 23473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy exception); 2348acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy if (q == (Quantum *) NULL) 23493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 23503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status=MagickFalse; 23513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy continue; 23523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 23533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy pixel=zero; 23543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 23553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Define constant scaling vectors for Affine Distortions 23563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Other methods are either variable, or use interpolated lookup 23573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 23583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy switch (method) 23593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 23603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case AffineDistortion: 23613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ScaleFilter( resample_filter[id], 23623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0], coeff[1], 23633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[3], coeff[4] ); 23643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 23653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy default: 23663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 23673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 23683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 23693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Initialize default pixel validity 2370b797b2c96f796f4920c9ee807dc5f47e6f160418dirk * negative: pixel is invalid output 'alpha_color' 23713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy * 0.0 to 1.0: antialiased, mix with resample output 23723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy * 1.0 or greater: use resampled output. 23733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 23743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy validity = 1.0; 23753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 2376b797b2c96f796f4920c9ee807dc5f47e6f160418dirk ConformPixelInfo(distort_image,&distort_image->alpha_color,&invalid, 2377bfdd5bc06830778f14dfa0659b389ff630b7fbfedirk exception); 2378bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (i=0; i < (ssize_t) distort_image->columns; i++) 23793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 23803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* map pixel coordinate to distortion space coordinate */ 23813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x = (double) (geometry.x+i+0.5)*output_scaling; 23823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y = (double) (geometry.y+j+0.5)*output_scaling; 23833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s = d; /* default is a no-op mapping */ 23843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy switch (method) 23853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 23863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case AffineDistortion: 23873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 23883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x=coeff[0]*d.x+coeff[1]*d.y+coeff[2]; 23893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y=coeff[3]*d.x+coeff[4]*d.y+coeff[5]; 23903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Affine partial derivitives are constant -- set above */ 23913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 23923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 23933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PerspectiveDistortion: 23943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 23953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 23963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy p,q,r,abs_r,abs_c6,abs_c7,scale; 23973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* perspective is a ratio of affines */ 23983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy p=coeff[0]*d.x+coeff[1]*d.y+coeff[2]; 23993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy q=coeff[3]*d.x+coeff[4]*d.y+coeff[5]; 24003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy r=coeff[6]*d.x+coeff[7]*d.y+1.0; 24013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Pixel Validity -- is it a 'sky' or 'ground' pixel */ 24023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy validity = (r*coeff[8] < 0.0) ? 0.0 : 1.0; 24033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Determine horizon anti-alias blending */ 24043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy abs_r = fabs(r)*2; 24053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy abs_c6 = fabs(coeff[6]); 24063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy abs_c7 = fabs(coeff[7]); 24073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( abs_c6 > abs_c7 ) { 24085c43782df7dd06579c309a16384c1d35657c7891anthony if ( abs_r < abs_c6*output_scaling ) 24095c43782df7dd06579c309a16384c1d35657c7891anthony validity = 0.5 - coeff[8]*r/(coeff[6]*output_scaling); 24103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 24115c43782df7dd06579c309a16384c1d35657c7891anthony else if ( abs_r < abs_c7*output_scaling ) 24125c43782df7dd06579c309a16384c1d35657c7891anthony validity = 0.5 - coeff[8]*r/(coeff[7]*output_scaling); 24133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Perspective Sampling Point (if valid) */ 24143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( validity > 0.0 ) { 24153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* divide by r affine, for perspective scaling */ 24163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy scale = 1.0/r; 24173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x = p*scale; 24183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y = q*scale; 24193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Perspective Partial Derivatives or Scaling Vectors */ 24203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy scale *= scale; 24213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ScaleFilter( resample_filter[id], 24223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (r*coeff[0] - p*coeff[6])*scale, 24233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (r*coeff[1] - p*coeff[7])*scale, 24243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (r*coeff[3] - q*coeff[6])*scale, 24253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (r*coeff[4] - q*coeff[7])*scale ); 24263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 24273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 24283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 24293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BilinearReverseDistortion: 24303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 24315056b230558c7de0a79d51d82bdc929fef45a225anthony /* Reversed Mapped is just a simple polynomial */ 24325056b230558c7de0a79d51d82bdc929fef45a225anthony s.x=coeff[0]*d.x+coeff[1]*d.y+coeff[2]*d.x*d.y+coeff[3]; 24333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y=coeff[4]*d.x+coeff[5]*d.y 24343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy +coeff[6]*d.x*d.y+coeff[7]; 24353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Bilinear partial derivitives of scaling vectors */ 24363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ScaleFilter( resample_filter[id], 24373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[0] + coeff[2]*d.y, 24383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[1] + coeff[2]*d.x, 24393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[4] + coeff[6]*d.y, 24403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[5] + coeff[6]*d.x ); 24413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 24423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 24433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BilinearForwardDistortion: 24443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 24455056b230558c7de0a79d51d82bdc929fef45a225anthony /* Forward mapped needs reversed polynomial equations 24465056b230558c7de0a79d51d82bdc929fef45a225anthony * which unfortunatally requires a square root! */ 24475056b230558c7de0a79d51d82bdc929fef45a225anthony double b,c; 24483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x -= coeff[3]; d.y -= coeff[7]; 24493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy b = coeff[6]*d.x - coeff[2]*d.y + coeff[8]; 24505056b230558c7de0a79d51d82bdc929fef45a225anthony c = coeff[4]*d.x - coeff[0]*d.y; 24515056b230558c7de0a79d51d82bdc929fef45a225anthony 24525056b230558c7de0a79d51d82bdc929fef45a225anthony validity = 1.0; 2453e0d9bbde3eb1826c767fee326a5786a9f28a191banthony /* Handle Special degenerate (non-quadratic) case 2454e0d9bbde3eb1826c767fee326a5786a9f28a191banthony * Currently without horizon anti-alising */ 24555056b230558c7de0a79d51d82bdc929fef45a225anthony if ( fabs(coeff[9]) < MagickEpsilon ) 24565056b230558c7de0a79d51d82bdc929fef45a225anthony s.y = -c/b; 24575056b230558c7de0a79d51d82bdc929fef45a225anthony else { 24585056b230558c7de0a79d51d82bdc929fef45a225anthony c = b*b - 2*coeff[9]*c; 24595056b230558c7de0a79d51d82bdc929fef45a225anthony if ( c < 0.0 ) 24605056b230558c7de0a79d51d82bdc929fef45a225anthony validity = 0.0; 24615056b230558c7de0a79d51d82bdc929fef45a225anthony else 24625056b230558c7de0a79d51d82bdc929fef45a225anthony s.y = ( -b + sqrt(c) )/coeff[9]; 24633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 24645056b230558c7de0a79d51d82bdc929fef45a225anthony if ( validity > 0.0 ) 24655056b230558c7de0a79d51d82bdc929fef45a225anthony s.x = ( d.x - coeff[1]*s.y) / ( coeff[0] + coeff[2]*s.y ); 24665056b230558c7de0a79d51d82bdc929fef45a225anthony 24673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* NOTE: the sign of the square root should be -ve for parts 24685056b230558c7de0a79d51d82bdc929fef45a225anthony where the source image becomes 'flipped' or 'mirrored'. 24695056b230558c7de0a79d51d82bdc929fef45a225anthony FUTURE: Horizon handling 24705056b230558c7de0a79d51d82bdc929fef45a225anthony FUTURE: Scaling factors or Deritives (how?) 24713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 24723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 24733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 24745056b230558c7de0a79d51d82bdc929fef45a225anthony#if 0 247588ef4d9fc7a5b3b5a194b1c5736df5360c830344anthony case BilinearDistortion: 24765056b230558c7de0a79d51d82bdc929fef45a225anthony /* Bilinear mapping of any Quadrilateral to any Quadrilateral */ 24775056b230558c7de0a79d51d82bdc929fef45a225anthony /* UNDER DEVELOPMENT */ 24785056b230558c7de0a79d51d82bdc929fef45a225anthony break; 24795056b230558c7de0a79d51d82bdc929fef45a225anthony#endif 24803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PolynomialDistortion: 24813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 24825056b230558c7de0a79d51d82bdc929fef45a225anthony /* multi-ordered polynomial */ 2483bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 24843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy k; 24859d314ff2c17a77996c05413c2013880387e50f0ecristy 2486bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy ssize_t 2487bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy nterms=(ssize_t)coeff[1]; 24883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 24893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy PointInfo 24903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy du,dv; /* the du,dv vectors from unit dx,dy -- derivatives */ 24913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 24923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x=s.y=du.x=du.y=dv.x=dv.y=0.0; 24933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for(k=0; k < nterms; k++) { 24943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x += poly_basis_fn(k,d.x,d.y)*coeff[2+k]; 24953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy du.x += poly_basis_dx(k,d.x,d.y)*coeff[2+k]; 24963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy du.y += poly_basis_dy(k,d.x,d.y)*coeff[2+k]; 24973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y += poly_basis_fn(k,d.x,d.y)*coeff[2+k+nterms]; 24983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy dv.x += poly_basis_dx(k,d.x,d.y)*coeff[2+k+nterms]; 24993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy dv.y += poly_basis_dy(k,d.x,d.y)*coeff[2+k+nterms]; 25003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 25013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ScaleFilter( resample_filter[id], du.x,du.y,dv.x,dv.y ); 25023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 25033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 25043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case ArcDistortion: 25053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 25063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* what is the angle and radius in the destination image */ 2507ba978e102735661f7777d22c1674d1d974303072cristy s.x = (double) ((atan2(d.y,d.x) - coeff[0])/Magick2PI); 25083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x -= MagickRound(s.x); /* angle */ 25093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y = hypot(d.x,d.y); /* radius */ 25103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 25113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Arc Distortion Partial Scaling Vectors 25123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Are derived by mapping the perpendicular unit vectors 25133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy dR and dA*R*2PI rather than trying to map dx and dy 25143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy The results is a very simple orthogonal aligned ellipse. 25153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 25163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( s.y > MagickEpsilon ) 25173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ScaleFilter( resample_filter[id], 2518ba978e102735661f7777d22c1674d1d974303072cristy (double) (coeff[1]/(Magick2PI*s.y)), 0, 0, coeff[3] ); 25193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else 25203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ScaleFilter( resample_filter[id], 25213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy distort_image->columns*2, 0, 0, coeff[3] ); 25223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 25233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* now scale the angle and radius for source image lookup point */ 25243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x = s.x*coeff[1] + coeff[4] + image->page.x +0.5; 25253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y = (coeff[2] - s.y) * coeff[3] + image->page.y; 25263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 25273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 25283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case PolarDistortion: 2529b9aaf9ed2a83b7d8931306fb3313285098072b25anthony { /* 2D Cartesain to Polar View */ 25303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x -= coeff[2]; 25313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y -= coeff[3]; 25323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x = atan2(d.x,d.y) - (coeff[4]+coeff[5])/2; 25333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x /= Magick2PI; 25343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x -= MagickRound(s.x); 25353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x *= Magick2PI; /* angle - relative to centerline */ 25363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y = hypot(d.x,d.y); /* radius */ 25373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 25383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Polar Scaling vectors are based on mapping dR and dA vectors 25393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy This results in very simple orthogonal scaling vectors 25403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 25413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( s.y > MagickEpsilon ) 25423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ScaleFilter( resample_filter[id], 2543ba978e102735661f7777d22c1674d1d974303072cristy (double) (coeff[6]/(Magick2PI*s.y)), 0, 0, coeff[7] ); 25443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else 25453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ScaleFilter( resample_filter[id], 25463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy distort_image->columns*2, 0, 0, coeff[7] ); 25473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 25483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* now finish mapping radius/angle to source x,y coords */ 25493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x = s.x*coeff[6] + (double)image->columns/2.0 + image->page.x; 25503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y = (s.y-coeff[1])*coeff[7] + image->page.y; 25513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 25523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 25533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case DePolarDistortion: 2554b9aaf9ed2a83b7d8931306fb3313285098072b25anthony { /* @D Polar to Carteasain */ 25553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* ignore all destination virtual offsets */ 255673144553d112665377fdd6f1ab5e152cff02b956anthony d.x = ((double)i+0.5)*output_scaling*coeff[6]+coeff[4]; 25573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y = ((double)j+0.5)*output_scaling*coeff[7]+coeff[1]; 25583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x = d.y*sin(d.x) + coeff[2]; 25593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y = d.y*cos(d.x) + coeff[3]; 25603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* derivatives are usless - better to use SuperSampling */ 25613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 25623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 2563e0d9bbde3eb1826c767fee326a5786a9f28a191banthony case Cylinder2PlaneDistortion: 2564b9aaf9ed2a83b7d8931306fb3313285098072b25anthony { /* 3D Cylinder to Tangential Plane */ 2565f3dac0af657aa837c1bda54d1eafeced62b92e19anthony double ax, cx; 2566f3dac0af657aa837c1bda54d1eafeced62b92e19anthony /* relative to center of distortion */ 2567f3dac0af657aa837c1bda54d1eafeced62b92e19anthony d.x -= coeff[4]; d.y -= coeff[5]; 2568f3dac0af657aa837c1bda54d1eafeced62b92e19anthony d.x /= coeff[1]; /* x' = x/r */ 2569f3dac0af657aa837c1bda54d1eafeced62b92e19anthony ax=atan(d.x); /* aa = atan(x/r) = u/r */ 2570f3dac0af657aa837c1bda54d1eafeced62b92e19anthony cx=cos(ax); /* cx = cos(atan(x/r)) = 1/sqrt(x^2+u^2) */ 2571f3dac0af657aa837c1bda54d1eafeced62b92e19anthony s.x = coeff[1]*ax; /* u = r*atan(x/r) */ 2572f3dac0af657aa837c1bda54d1eafeced62b92e19anthony s.y = d.y*cx; /* v = y*cos(u/r) */ 2573f3dac0af657aa837c1bda54d1eafeced62b92e19anthony /* derivatives... (see personnal notes) */ 2574f3dac0af657aa837c1bda54d1eafeced62b92e19anthony ScaleFilter( resample_filter[id], 2575f3dac0af657aa837c1bda54d1eafeced62b92e19anthony 1.0/(1.0+d.x*d.x), 0.0, -d.x*s.y*cx*cx/coeff[1], s.y/d.y ); 2576f3dac0af657aa837c1bda54d1eafeced62b92e19anthony#if 0 2577f3dac0af657aa837c1bda54d1eafeced62b92e19anthonyif ( i == 0 && j == 0 ) { 2578f3dac0af657aa837c1bda54d1eafeced62b92e19anthony fprintf(stderr, "x=%lf y=%lf u=%lf v=%lf\n", d.x*coeff[1], d.y, s.x, s.y); 2579f3dac0af657aa837c1bda54d1eafeced62b92e19anthony fprintf(stderr, "phi = %lf\n", (double)(ax * 180.0/MagickPI) ); 2580f3dac0af657aa837c1bda54d1eafeced62b92e19anthony fprintf(stderr, "du/dx=%lf du/dx=%lf dv/dx=%lf dv/dy=%lf\n", 2581f3dac0af657aa837c1bda54d1eafeced62b92e19anthony 1.0/(1.0+d.x*d.x), 0.0, -d.x*s.y*cx*cx/coeff[1], s.y/d.y ); 2582f3dac0af657aa837c1bda54d1eafeced62b92e19anthony fflush(stderr); } 2583f3dac0af657aa837c1bda54d1eafeced62b92e19anthony#endif 2584f3dac0af657aa837c1bda54d1eafeced62b92e19anthony /* add center of distortion in source */ 2585f3dac0af657aa837c1bda54d1eafeced62b92e19anthony s.x += coeff[2]; s.y += coeff[3]; 2586b9aaf9ed2a83b7d8931306fb3313285098072b25anthony break; 2587b9aaf9ed2a83b7d8931306fb3313285098072b25anthony } 2588e0d9bbde3eb1826c767fee326a5786a9f28a191banthony case Plane2CylinderDistortion: 2589b9aaf9ed2a83b7d8931306fb3313285098072b25anthony { /* 3D Cylinder to Tangential Plane */ 2590f3dac0af657aa837c1bda54d1eafeced62b92e19anthony /* relative to center of distortion */ 2591f3dac0af657aa837c1bda54d1eafeced62b92e19anthony d.x -= coeff[4]; d.y -= coeff[5]; 2592e0d9bbde3eb1826c767fee326a5786a9f28a191banthony 2593e0d9bbde3eb1826c767fee326a5786a9f28a191banthony /* is pixel valid - horizon of a infinite Virtual-Pixel Plane 2594e0d9bbde3eb1826c767fee326a5786a9f28a191banthony * (see Anthony Thyssen's personal note) */ 25954c08aed51c5899665ade97263692328eea4af106cristy validity = (double) (coeff[1]*MagickPI2 - fabs(d.x))/output_scaling + 0.5; 2596e0d9bbde3eb1826c767fee326a5786a9f28a191banthony 2597e0d9bbde3eb1826c767fee326a5786a9f28a191banthony if ( validity > 0.0 ) { 2598e0d9bbde3eb1826c767fee326a5786a9f28a191banthony double cx,tx; 2599e0d9bbde3eb1826c767fee326a5786a9f28a191banthony d.x /= coeff[1]; /* x'= x/r */ 2600e0d9bbde3eb1826c767fee326a5786a9f28a191banthony cx = 1/cos(d.x); /* cx = 1/cos(x/r) */ 2601e0d9bbde3eb1826c767fee326a5786a9f28a191banthony tx = tan(d.x); /* tx = tan(x/r) */ 2602e0d9bbde3eb1826c767fee326a5786a9f28a191banthony s.x = coeff[1]*tx; /* u = r * tan(x/r) */ 2603e0d9bbde3eb1826c767fee326a5786a9f28a191banthony s.y = d.y*cx; /* v = y / cos(x/r) */ 2604e0d9bbde3eb1826c767fee326a5786a9f28a191banthony /* derivatives... (see Anthony Thyssen's personal notes) */ 2605e0d9bbde3eb1826c767fee326a5786a9f28a191banthony ScaleFilter( resample_filter[id], 2606e0d9bbde3eb1826c767fee326a5786a9f28a191banthony cx*cx, 0.0, s.y*cx/coeff[1], cx ); 260786b99553adc2b1a8bbbe50cac358507bfdde80fcdirk#if 0 26084c08aed51c5899665ade97263692328eea4af106cristy/*if ( i == 0 && j == 0 )*/ 2609d2a90402dad613980c957433ecff73d2f4a99f8aanthonyif ( d.x == 0.5 && d.y == 0.5 ) { 2610f3dac0af657aa837c1bda54d1eafeced62b92e19anthony fprintf(stderr, "x=%lf y=%lf u=%lf v=%lf\n", d.x*coeff[1], d.y, s.x, s.y); 2611e0d9bbde3eb1826c767fee326a5786a9f28a191banthony fprintf(stderr, "radius = %lf phi = %lf validity = %lf\n", 2612e0d9bbde3eb1826c767fee326a5786a9f28a191banthony coeff[1], (double)(d.x * 180.0/MagickPI), validity ); 2613f3dac0af657aa837c1bda54d1eafeced62b92e19anthony fprintf(stderr, "du/dx=%lf du/dx=%lf dv/dx=%lf dv/dy=%lf\n", 2614f3dac0af657aa837c1bda54d1eafeced62b92e19anthony cx*cx, 0.0, s.y*cx/coeff[1], cx); 2615f3dac0af657aa837c1bda54d1eafeced62b92e19anthony fflush(stderr); } 2616f3dac0af657aa837c1bda54d1eafeced62b92e19anthony#endif 2617e0d9bbde3eb1826c767fee326a5786a9f28a191banthony } 2618f3dac0af657aa837c1bda54d1eafeced62b92e19anthony /* add center of distortion in source */ 2619f3dac0af657aa837c1bda54d1eafeced62b92e19anthony s.x += coeff[2]; s.y += coeff[3]; 2620b9aaf9ed2a83b7d8931306fb3313285098072b25anthony break; 2621b9aaf9ed2a83b7d8931306fb3313285098072b25anthony } 26223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BarrelDistortion: 26233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BarrelInverseDistortion: 2624b9aaf9ed2a83b7d8931306fb3313285098072b25anthony { /* Lens Barrel Distionion Correction */ 26253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double r,fx,fy,gx,gy; 26263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Radial Polynomial Distortion (de-normalized) */ 26273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.x -= coeff[8]; 26283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy d.y -= coeff[9]; 26293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy r = sqrt(d.x*d.x+d.y*d.y); 26303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( r > MagickEpsilon ) { 26313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy fx = ((coeff[0]*r + coeff[1])*r + coeff[2])*r + coeff[3]; 26323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy fy = ((coeff[4]*r + coeff[5])*r + coeff[6])*r + coeff[7]; 26333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy gx = ((3*coeff[0]*r + 2*coeff[1])*r + coeff[2])/r; 26343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy gy = ((3*coeff[4]*r + 2*coeff[5])*r + coeff[6])/r; 26353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* adjust functions and scaling for 'inverse' form */ 26363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( method == BarrelInverseDistortion ) { 26373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy fx = 1/fx; fy = 1/fy; 26383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy gx *= -fx*fx; gy *= -fy*fy; 26393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 2640ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony /* Set the source pixel to lookup and EWA derivative vectors */ 26413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x = d.x*fx + coeff[8]; 26423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y = d.y*fy + coeff[9]; 26433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ScaleFilter( resample_filter[id], 26443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy gx*d.x*d.x + fx, gx*d.x*d.y, 26453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy gy*d.x*d.y, gy*d.y*d.y + fy ); 26463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 2647ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony else { 2648ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony /* Special handling to avoid divide by zero when r==0 2649ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony ** 2650ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony ** The source and destination pixels match in this case 2651ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony ** which was set at the top of the loop using s = d; 2652ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony ** otherwise... s.x=coeff[8]; s.y=coeff[9]; 2653ec40aca22bbc75266cdfdc60dd1fc8ebb8174139anthony */ 26543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( method == BarrelDistortion ) 26553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ScaleFilter( resample_filter[id], 26563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[3], 0, 0, coeff[7] ); 26573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else /* method == BarrelInverseDistortion */ 26583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* FUTURE, trap for D==0 causing division by zero */ 26593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ScaleFilter( resample_filter[id], 26603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1.0/coeff[3], 0, 0, 1.0/coeff[7] ); 26613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 26623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 26633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 26643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case ShepardsDistortion: 26653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { /* Shepards Method, or Inverse Weighted Distance for 266647bb5df69322136901ccab9ad266d21ceff50500anthony displacement around the destination image control points 266747bb5df69322136901ccab9ad266d21ceff50500anthony The input arguments are the coefficents to the function. 266847bb5df69322136901ccab9ad266d21ceff50500anthony This is more of a 'displacement' function rather than an 266947bb5df69322136901ccab9ad266d21ceff50500anthony absolute distortion function. 267047bb5df69322136901ccab9ad266d21ceff50500anthony 267147bb5df69322136901ccab9ad266d21ceff50500anthony Note: We can not determine derivatives using shepards method 267247bb5df69322136901ccab9ad266d21ceff50500anthony so only a point sample interpolatation can be used. 26733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 2674bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 26753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy i; 26763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 26773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy denominator; 26783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 26793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy denominator = s.x = s.y = 0; 26803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for(i=0; i<number_arguments; i+=4) { 26813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double weight = 26823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ((double)d.x-arguments[i+2])*((double)d.x-arguments[i+2]) 26833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + ((double)d.y-arguments[i+3])*((double)d.y-arguments[i+3]); 268447bb5df69322136901ccab9ad266d21ceff50500anthony weight = pow(weight,coeff[0]); /* shepards power factor */ 268547bb5df69322136901ccab9ad266d21ceff50500anthony weight = ( weight < 1.0 ) ? 1.0 : 1.0/weight; 26863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 26873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x += (arguments[ i ]-arguments[i+2])*weight; 26883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y += (arguments[i+1]-arguments[i+3])*weight; 26893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy denominator += weight; 26903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 26913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x /= denominator; 26923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y /= denominator; 269347bb5df69322136901ccab9ad266d21ceff50500anthony s.x += d.x; /* make it as relative displacement */ 26943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y += d.y; 26953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 26963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 26973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy default: 26983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; /* use the default no-op given above */ 26993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 27003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* map virtual canvas location back to real image coordinate */ 27013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( bestfit && method != ArcDistortion ) { 27023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x -= image->page.x; 27033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y -= image->page.y; 27043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 27053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.x -= 0.5; 27063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy s.y -= 0.5; 27073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 27083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( validity <= 0.0 ) { 27093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* result of distortion is an invalid pixel - don't resample */ 271011a06d3f2cac0f17af7963e83bc6e9ebd2a377c0cristy SetPixelViaPixelInfo(distort_image,&invalid,q); 27113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 27123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy else { 27133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* resample the source image to find its correct color */ 2714db070957cf6bf959df9283a482377e8854c3d4d2cristy (void) ResamplePixelColor(resample_filter[id],s.x,s.y,&pixel, 2715db070957cf6bf959df9283a482377e8854c3d4d2cristy exception); 27163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* if validity between 0.0 and 1.0 mix result with invalid pixel */ 27173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( validity < 1.0 ) { 27183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Do a blend of sample color and invalid pixel */ 27193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* should this be a 'Blend', or an 'Over' compose */ 27204c08aed51c5899665ade97263692328eea4af106cristy CompositePixelInfoBlend(&pixel,validity,&invalid,(1.0-validity), 27213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy &pixel); 27223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 272311a06d3f2cac0f17af7963e83bc6e9ebd2a377c0cristy SetPixelViaPixelInfo(distort_image,&pixel,q); 27243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 2725ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q+=GetPixelChannels(distort_image); 27263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 27273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sync=SyncCacheViewAuthenticPixels(distort_view,exception); 27283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (sync == MagickFalse) 27293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status=MagickFalse; 27303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (image->progress_monitor != (MagickProgressMonitor) NULL) 27313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 27323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy MagickBooleanType 27333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy proceed; 27343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 2735b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 2736ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy #pragma omp critical (MagickCore_DistortImage) 27373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif 27383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy proceed=SetImageProgress(image,DistortImageTag,progress++, 27393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy image->rows); 27403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (proceed == MagickFalse) 27413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status=MagickFalse; 27423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 27433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 27443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy distort_view=DestroyCacheView(distort_view); 27453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy resample_filter=DestroyResampleFilterThreadSet(resample_filter); 27463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 27473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (status == MagickFalse) 27483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy distort_image=DestroyImage(distort_image); 27493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 27503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 27513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Arc does not return an offset unless 'bestfit' is in effect 27523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy And the user has not provided an overriding 'viewport'. 27533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 27543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( method == ArcDistortion && !bestfit && !viewport_given ) { 27553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy distort_image->page.x = 0; 27563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy distort_image->page.y = 0; 27573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 27583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 27593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(distort_image); 27603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 27613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 27623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/* 27633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 27643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 27653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 27663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 2767987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% R o t a t e I m a g e % 2768987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% % 2769987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% % 2770987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% % 2771987feef6c1e3d08da3d9458fa5c464a32fc30191cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2772987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 2773987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% RotateImage() creates a new image that is a rotated copy of an existing 2774987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% one. Positive angles rotate counter-clockwise (right-hand rule), while 2775987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% negative angles rotate clockwise. Rotated images are usually larger than 2776987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% the originals and have 'empty' triangular corners. X axis. Empty 2777987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% triangles left over from shearing the image are filled with the background 2778987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% color defined by member 'background_color' of the image. RotateImage 2779987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% allocates the memory necessary for the new Image structure and returns a 2780987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% pointer to the new image. 2781987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 2782987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% The format of the RotateImage method is: 2783987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 2784987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% Image *RotateImage(const Image *image,const double degrees, 2785987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% ExceptionInfo *exception) 2786987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 2787987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% A description of each parameter follows. 2788987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 2789987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% o image: the image. 2790987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 2791987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% o degrees: Specifies the number of degrees to rotate the image. 2792987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 2793987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% o exception: return any errors or warnings in this structure. 2794987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% 2795987feef6c1e3d08da3d9458fa5c464a32fc30191cristy*/ 2796987feef6c1e3d08da3d9458fa5c464a32fc30191cristyMagickExport Image *RotateImage(const Image *image,const double degrees, 2797987feef6c1e3d08da3d9458fa5c464a32fc30191cristy ExceptionInfo *exception) 2798987feef6c1e3d08da3d9458fa5c464a32fc30191cristy{ 2799987feef6c1e3d08da3d9458fa5c464a32fc30191cristy Image 2800e724ba5d4a031534c55b2b63cb38b093fae9e2d4cristy *distort_image, 2801987feef6c1e3d08da3d9458fa5c464a32fc30191cristy *rotate_image; 2802987feef6c1e3d08da3d9458fa5c464a32fc30191cristy 2803a19f1d70e9a9f88279c4ecafe6dfafc1f9a09599cristy double 2804987feef6c1e3d08da3d9458fa5c464a32fc30191cristy angle; 2805987feef6c1e3d08da3d9458fa5c464a32fc30191cristy 2806987feef6c1e3d08da3d9458fa5c464a32fc30191cristy PointInfo 2807987feef6c1e3d08da3d9458fa5c464a32fc30191cristy shear; 2808987feef6c1e3d08da3d9458fa5c464a32fc30191cristy 2809987feef6c1e3d08da3d9458fa5c464a32fc30191cristy size_t 2810987feef6c1e3d08da3d9458fa5c464a32fc30191cristy rotations; 2811987feef6c1e3d08da3d9458fa5c464a32fc30191cristy 2812987feef6c1e3d08da3d9458fa5c464a32fc30191cristy /* 2813987feef6c1e3d08da3d9458fa5c464a32fc30191cristy Adjust rotation angle. 2814987feef6c1e3d08da3d9458fa5c464a32fc30191cristy */ 2815987feef6c1e3d08da3d9458fa5c464a32fc30191cristy assert(image != (Image *) NULL); 2816e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(image->signature == MagickCoreSignature); 2817987feef6c1e3d08da3d9458fa5c464a32fc30191cristy if (image->debug != MagickFalse) 2818987feef6c1e3d08da3d9458fa5c464a32fc30191cristy (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 2819987feef6c1e3d08da3d9458fa5c464a32fc30191cristy assert(exception != (ExceptionInfo *) NULL); 2820e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(exception->signature == MagickCoreSignature); 2821987feef6c1e3d08da3d9458fa5c464a32fc30191cristy angle=degrees; 2822987feef6c1e3d08da3d9458fa5c464a32fc30191cristy while (angle < -45.0) 2823987feef6c1e3d08da3d9458fa5c464a32fc30191cristy angle+=360.0; 2824987feef6c1e3d08da3d9458fa5c464a32fc30191cristy for (rotations=0; angle > 45.0; rotations++) 2825987feef6c1e3d08da3d9458fa5c464a32fc30191cristy angle-=90.0; 2826987feef6c1e3d08da3d9458fa5c464a32fc30191cristy rotations%=4; 2827987feef6c1e3d08da3d9458fa5c464a32fc30191cristy shear.x=(-tan((double) DegreesToRadians(angle)/2.0)); 2828987feef6c1e3d08da3d9458fa5c464a32fc30191cristy shear.y=sin((double) DegreesToRadians(angle)); 2829987feef6c1e3d08da3d9458fa5c464a32fc30191cristy if ((fabs(shear.x) < MagickEpsilon) && (fabs(shear.y) < MagickEpsilon)) 2830987feef6c1e3d08da3d9458fa5c464a32fc30191cristy return(IntegralRotateImage(image,rotations,exception)); 2831e724ba5d4a031534c55b2b63cb38b093fae9e2d4cristy distort_image=CloneImage(image,0,0,MagickTrue,exception); 2832e724ba5d4a031534c55b2b63cb38b093fae9e2d4cristy if (distort_image == (Image *) NULL) 2833e724ba5d4a031534c55b2b63cb38b093fae9e2d4cristy return((Image *) NULL); 2834387430f111ba7864990ca03fbc89968e20074ecdcristy (void) SetImageVirtualPixelMethod(distort_image,BackgroundVirtualPixelMethod, 2835387430f111ba7864990ca03fbc89968e20074ecdcristy exception); 2836e724ba5d4a031534c55b2b63cb38b093fae9e2d4cristy rotate_image=DistortImage(distort_image,ScaleRotateTranslateDistortion,1, 2837e724ba5d4a031534c55b2b63cb38b093fae9e2d4cristy °rees,MagickTrue,exception); 2838e724ba5d4a031534c55b2b63cb38b093fae9e2d4cristy distort_image=DestroyImage(distort_image); 2839987feef6c1e3d08da3d9458fa5c464a32fc30191cristy return(rotate_image); 2840987feef6c1e3d08da3d9458fa5c464a32fc30191cristy} 2841987feef6c1e3d08da3d9458fa5c464a32fc30191cristy 2842987feef6c1e3d08da3d9458fa5c464a32fc30191cristy/* 2843987feef6c1e3d08da3d9458fa5c464a32fc30191cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2844987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% % 2845987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% % 2846987feef6c1e3d08da3d9458fa5c464a32fc30191cristy% % 28473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% S p a r s e C o l o r I m a g e % 28483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 28493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 28503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% % 28513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 28523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 28533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% SparseColorImage(), given a set of coordinates, interpolates the colors 28543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% found at those coordinates, across the whole image, using various methods. 28553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 28563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% The format of the SparseColorImage() method is: 28573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 28583884f69ac6f82e16fc379fb6c6521960c19045a2cristy% Image *SparseColorImage(const Image *image, 2859bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy% const SparseColorMethod method,const size_t number_arguments, 28603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% const double *arguments,ExceptionInfo *exception) 28613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 28623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% A description of each parameter follows: 28633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 28643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o image: the image to be filled in. 28653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 28663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o method: the method to fill in the gradient between the control points. 28673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 28683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% The methods used for SparseColor() are often simular to methods 28693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% used for DistortImage(), and even share the same code for determination 28703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% of the function coefficents, though with more dimensions (or resulting 28713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% values). 28723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 28733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o number_arguments: the number of arguments given. 28743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 28753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o arguments: array of floating point arguments for this method-- 28763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% x,y,color_values-- with color_values given as normalized values. 28773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 28783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% o exception: return any errors or warnings in this structure 28793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy% 28803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/ 28813ed852eea50f9d4cd633efb8c2b054b8e33c253cristyMagickExport Image *SparseColorImage(const Image *image, 28823884f69ac6f82e16fc379fb6c6521960c19045a2cristy const SparseColorMethod method,const size_t number_arguments, 28833884f69ac6f82e16fc379fb6c6521960c19045a2cristy const double *arguments,ExceptionInfo *exception) 28843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{ 28853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define SparseColorTag "Distort/SparseColor" 28863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 2887216e87a01399287638cc24e70c8cc8947205004fanthony SparseColorMethod 2888216e87a01399287638cc24e70c8cc8947205004fanthony sparse_method; 28893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 28903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 28913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *coeff; 28923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 28933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Image 28943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy *sparse_image; 28953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 2896bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 28973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy number_colors; 28983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 28993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy assert(image != (Image *) NULL); 2900e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(image->signature == MagickCoreSignature); 29013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (image->debug != MagickFalse) 29023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 29033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy assert(exception != (ExceptionInfo *) NULL); 2904e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy assert(exception->signature == MagickCoreSignature); 29053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 29063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Determine number of color values needed per control point */ 29073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy number_colors=0; 2908ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 29093884f69ac6f82e16fc379fb6c6521960c19045a2cristy number_colors++; 2910ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 29113884f69ac6f82e16fc379fb6c6521960c19045a2cristy number_colors++; 2912ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 29133884f69ac6f82e16fc379fb6c6521960c19045a2cristy number_colors++; 2914ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 29153884f69ac6f82e16fc379fb6c6521960c19045a2cristy (image->colorspace == CMYKColorspace)) 29163884f69ac6f82e16fc379fb6c6521960c19045a2cristy number_colors++; 2917ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 291817f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy (image->alpha_trait != UndefinedPixelTrait)) 29193884f69ac6f82e16fc379fb6c6521960c19045a2cristy number_colors++; 29203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 29213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* 2922216e87a01399287638cc24e70c8cc8947205004fanthony Convert input arguments into mapping coefficients, this this case 2923216e87a01399287638cc24e70c8cc8947205004fanthony we are mapping (distorting) colors, rather than coordinates. 29243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 2925827944d54938c1f8a74ff53cd35c11801060d995dirk { DistortMethod 2926216e87a01399287638cc24e70c8cc8947205004fanthony distort_method; 2927216e87a01399287638cc24e70c8cc8947205004fanthony 2928827944d54938c1f8a74ff53cd35c11801060d995dirk distort_method=(DistortMethod) method; 2929216e87a01399287638cc24e70c8cc8947205004fanthony if ( distort_method >= SentinelDistortion ) 2930216e87a01399287638cc24e70c8cc8947205004fanthony distort_method = ShepardsDistortion; /* Pretend to be Shepards */ 2931216e87a01399287638cc24e70c8cc8947205004fanthony coeff = GenerateCoefficients(image, &distort_method, number_arguments, 2932216e87a01399287638cc24e70c8cc8947205004fanthony arguments, number_colors, exception); 2933216e87a01399287638cc24e70c8cc8947205004fanthony if ( coeff == (double *) NULL ) 2934216e87a01399287638cc24e70c8cc8947205004fanthony return((Image *) NULL); 2935216e87a01399287638cc24e70c8cc8947205004fanthony /* 2936216e87a01399287638cc24e70c8cc8947205004fanthony Note some Distort Methods may fall back to other simpler methods, 2937216e87a01399287638cc24e70c8cc8947205004fanthony Currently the only fallback of concern is Bilinear to Affine 2938216e87a01399287638cc24e70c8cc8947205004fanthony (Barycentric), which is alaso sparse_colr method. This also ensures 2939216e87a01399287638cc24e70c8cc8947205004fanthony correct two and one color Barycentric handling. 2940216e87a01399287638cc24e70c8cc8947205004fanthony */ 2941216e87a01399287638cc24e70c8cc8947205004fanthony sparse_method = (SparseColorMethod) distort_method; 2942216e87a01399287638cc24e70c8cc8947205004fanthony if ( distort_method == ShepardsDistortion ) 294347bb5df69322136901ccab9ad266d21ceff50500anthony sparse_method = method; /* return non-distort methods to normal */ 294447bb5df69322136901ccab9ad266d21ceff50500anthony if ( sparse_method == InverseColorInterpolate ) 294547bb5df69322136901ccab9ad266d21ceff50500anthony coeff[0]=0.5; /* sqrt() the squared distance for inverse */ 2946216e87a01399287638cc24e70c8cc8947205004fanthony } 29473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 29483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Verbose output */ 2949972c2e42a2171341bbf55a48cb36882616a591b1dirk if (IsStringTrue(GetImageArtifact(image,"verbose")) != MagickFalse) { 29503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 2951216e87a01399287638cc24e70c8cc8947205004fanthony switch (sparse_method) { 29523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BarycentricColorInterpolate: 29533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 2954bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t x=0; 29555acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Barycentric Sparse Color:\n"); 2956ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 29575acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -channel R -fx '%+lf*i %+lf*j %+lf' \\\n", 29583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[x], coeff[x+1], coeff[x+2]),x+=3; 2959ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 29605acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -channel G -fx '%+lf*i %+lf*j %+lf' \\\n", 29613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[x], coeff[x+1], coeff[x+2]),x+=3; 2962ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 29635acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -channel B -fx '%+lf*i %+lf*j %+lf' \\\n", 29643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[x], coeff[x+1], coeff[x+2]),x+=3; 2965ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 29663884f69ac6f82e16fc379fb6c6521960c19045a2cristy (image->colorspace == CMYKColorspace)) 29675acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -channel K -fx '%+lf*i %+lf*j %+lf' \\\n", 29683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[x], coeff[x+1], coeff[x+2]),x+=3; 2969ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 297017f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy (image->alpha_trait != UndefinedPixelTrait)) 29715acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -channel A -fx '%+lf*i %+lf*j %+lf' \\\n", 29723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[x], coeff[x+1], coeff[x+2]),x+=3; 29733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 29743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 29753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BilinearColorInterpolate: 29763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 2977bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t x=0; 29785acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, "Bilinear Sparse Color\n"); 2979ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 29805acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -channel R -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n", 29813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[ x ], coeff[x+1], 29823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[x+2], coeff[x+3]),x+=4; 2983ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 29845acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -channel G -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n", 29853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[ x ], coeff[x+1], 29863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[x+2], coeff[x+3]),x+=4; 2987ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 29885acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -channel B -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n", 29893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[ x ], coeff[x+1], 29903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[x+2], coeff[x+3]),x+=4; 2991ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 29923884f69ac6f82e16fc379fb6c6521960c19045a2cristy (image->colorspace == CMYKColorspace)) 29935acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -channel K -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n", 29943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[ x ], coeff[x+1], 29953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[x+2], coeff[x+3]),x+=4; 2996ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 299717f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy (image->alpha_trait != UndefinedPixelTrait)) 29985acdd94fa3dabd964fcad53b4948ed7cac2886b1cristy (void) FormatLocaleFile(stderr, " -channel A -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n", 29993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[ x ], coeff[x+1], 30003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[x+2], coeff[x+3]),x+=4; 30013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 30023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 30033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy default: 3004216e87a01399287638cc24e70c8cc8947205004fanthony /* sparse color method is too complex for FX emulation */ 30053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 30063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 30073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 30083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 30093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* Generate new image for generated interpolated gradient. 30103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy * ASIDE: Actually we could have just replaced the colors of the original 3011216e87a01399287638cc24e70c8cc8947205004fanthony * image, but IM Core policy, is if storage class could change then clone 30123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy * the image. 30133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */ 30143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 3015c925339225980372a6a2eaf2a93693e57a40e5ffanthony sparse_image=CloneImage(image,0,0,MagickTrue,exception); 30163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (sparse_image == (Image *) NULL) 30173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((Image *) NULL); 3018574cc26500992189f637cd1cdf93d0654e7df7aecristy if (SetImageStorageClass(sparse_image,DirectClass,exception) == MagickFalse) 30193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { /* if image is ColorMapped - change it to DirectClass */ 30203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sparse_image=DestroyImage(sparse_image); 30213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return((Image *) NULL); 30223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 30233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { /* ----- MAIN CODE ----- */ 3024cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy CacheView 3025cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy *sparse_view; 30263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 30273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy MagickBooleanType 30283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status; 30293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 3030cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy MagickOffsetType 3031cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy progress; 3032cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy 3033cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy ssize_t 3034cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy j; 30353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 30363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status=MagickTrue; 30373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy progress=0; 303846ff2676b1044ea4101ac7a59b83289cd8f6cfdacristy sparse_view=AcquireAuthenticCacheView(sparse_image,exception); 3039b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 3040ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy #pragma omp parallel for schedule(static,4) shared(progress,status) \ 30415e6b259130f9dbe0da4666f734937017babe573acristy magick_threads(image,sparse_image,sparse_image->rows,1) 30423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif 3043bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy for (j=0; j < (ssize_t) sparse_image->rows; j++) 30443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 30453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy MagickBooleanType 30463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sync; 30473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 30484c08aed51c5899665ade97263692328eea4af106cristy PixelInfo 30493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy pixel; /* pixel to assign to distorted image */ 30503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 3051bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t 30523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy i; 30533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 30544c08aed51c5899665ade97263692328eea4af106cristy register Quantum 305505d2ff7ebf21f659f5b11e45afb294e152f4330cdirk *magick_restrict q; 30563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 305735a36a0014370557d0fae15cda1c1766196339e1anthony q=GetCacheViewAuthenticPixels(sparse_view,0,j,sparse_image->columns, 30583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 1,exception); 3059acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy if (q == (Quantum *) NULL) 30603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 30613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status=MagickFalse; 30623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy continue; 30633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 30644c08aed51c5899665ade97263692328eea4af106cristy GetPixelInfo(sparse_image,&pixel); 306535a36a0014370557d0fae15cda1c1766196339e1anthony for (i=0; i < (ssize_t) image->columns; i++) 30663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 3067803640d20a6a664315eddfff6f8531d0c5e0871dcristy GetPixelInfoPixel(image,q,&pixel); 3068216e87a01399287638cc24e70c8cc8947205004fanthony switch (sparse_method) 30693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 30703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BarycentricColorInterpolate: 30713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 3072bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t x=0; 3073ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 30743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy pixel.red = coeff[x]*i +coeff[x+1]*j 30753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy +coeff[x+2], x+=3; 3076ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 30773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy pixel.green = coeff[x]*i +coeff[x+1]*j 30783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy +coeff[x+2], x+=3; 3079ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 30803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy pixel.blue = coeff[x]*i +coeff[x+1]*j 30813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy +coeff[x+2], x+=3; 3082ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 30833884f69ac6f82e16fc379fb6c6521960c19045a2cristy (image->colorspace == CMYKColorspace)) 30844c08aed51c5899665ade97263692328eea4af106cristy pixel.black = coeff[x]*i +coeff[x+1]*j 30853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy +coeff[x+2], x+=3; 3086ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 308717f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy (image->alpha_trait != UndefinedPixelTrait)) 30883884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.alpha = coeff[x]*i +coeff[x+1]*j 30893884f69ac6f82e16fc379fb6c6521960c19045a2cristy +coeff[x+2], x+=3; 30903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 30913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 30923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case BilinearColorInterpolate: 30933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 3094bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t x=0; 3095ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 30963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy pixel.red = coeff[x]*i + coeff[x+1]*j + 30973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[x+2]*i*j + coeff[x+3], x+=4; 3098ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 30993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy pixel.green = coeff[x]*i + coeff[x+1]*j + 31003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[x+2]*i*j + coeff[x+3], x+=4; 3101ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 31023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy pixel.blue = coeff[x]*i + coeff[x+1]*j + 31033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[x+2]*i*j + coeff[x+3], x+=4; 3104ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 31053884f69ac6f82e16fc379fb6c6521960c19045a2cristy (image->colorspace == CMYKColorspace)) 31064c08aed51c5899665ade97263692328eea4af106cristy pixel.black = coeff[x]*i + coeff[x+1]*j + 31073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff[x+2]*i*j + coeff[x+3], x+=4; 3108ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 310917f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy (image->alpha_trait != UndefinedPixelTrait)) 31103884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.alpha = coeff[x]*i + coeff[x+1]*j + 31113884f69ac6f82e16fc379fb6c6521960c19045a2cristy coeff[x+2]*i*j + coeff[x+3], x+=4; 31123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 31133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 311409d867c5236ae386cb2a036298e37aa986478047anthony case InverseColorInterpolate: 3115216e87a01399287638cc24e70c8cc8947205004fanthony case ShepardsColorInterpolate: 3116216e87a01399287638cc24e70c8cc8947205004fanthony { /* Inverse (Squared) Distance weights average (IDW) */ 3117bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 31183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy k; 31193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 31203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy denominator; 31213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 3122ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 31233884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.red=0.0; 3124ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 31253884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.green=0.0; 3126ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 31273884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.blue=0.0; 3128ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 31293884f69ac6f82e16fc379fb6c6521960c19045a2cristy (image->colorspace == CMYKColorspace)) 31303884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.black=0.0; 3131ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 313217f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy (image->alpha_trait != UndefinedPixelTrait)) 31333884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.alpha=0.0; 31343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy denominator = 0.0; 31353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy for(k=0; k<number_arguments; k+=2+number_colors) { 3136bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t x=(ssize_t) k+2; 31373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double weight = 31383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ((double)i-arguments[ k ])*((double)i-arguments[ k ]) 31393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + ((double)j-arguments[k+1])*((double)j-arguments[k+1]); 314047bb5df69322136901ccab9ad266d21ceff50500anthony weight = pow(weight,coeff[0]); /* inverse of power factor */ 31413abf6c31cb8c15a2b01903e371a921db702fa838cristy weight = ( weight < 1.0 ) ? 1.0 : 1.0/weight; 3142ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 31433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy pixel.red += arguments[x++]*weight; 3144ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 31453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy pixel.green += arguments[x++]*weight; 3146ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 31473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy pixel.blue += arguments[x++]*weight; 3148ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 31493884f69ac6f82e16fc379fb6c6521960c19045a2cristy (image->colorspace == CMYKColorspace)) 31504c08aed51c5899665ade97263692328eea4af106cristy pixel.black += arguments[x++]*weight; 3151ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 315217f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy (image->alpha_trait != UndefinedPixelTrait)) 31533884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.alpha += arguments[x++]*weight; 31543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy denominator += weight; 31553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 3156ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 31573884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.red/=denominator; 3158ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 31593884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.green/=denominator; 3160ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 31613884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.blue/=denominator; 3162ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 31633884f69ac6f82e16fc379fb6c6521960c19045a2cristy (image->colorspace == CMYKColorspace)) 31643884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.black/=denominator; 3165ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 316617f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy (image->alpha_trait != UndefinedPixelTrait)) 31673884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.alpha/=denominator; 31683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 31693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 317004bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville case ManhattanColorInterpolate: 317104bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville { 317204bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville size_t 317304bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville k; 317404bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville 317504bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville double 317604bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville minimum = MagickMaximumValue; 317704bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville 317804bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville /* 317904bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville Just use the closest control point you can find! 318004bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville */ 318104bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville for(k=0; k<number_arguments; k+=2+number_colors) { 318204bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville double distance = 318304bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville fabs((double)i-arguments[ k ]) 318404bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville + fabs((double)j-arguments[k+1]); 318504bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville if ( distance < minimum ) { 318604bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville register ssize_t x=(ssize_t) k+2; 318704bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 318804bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville pixel.red=arguments[x++]; 318904bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 319004bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville pixel.green=arguments[x++]; 319104bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 319204bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville pixel.blue=arguments[x++]; 319304bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 319404bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville (image->colorspace == CMYKColorspace)) 319504bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville pixel.black=arguments[x++]; 319604bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 319704bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville (image->alpha_trait != UndefinedPixelTrait)) 319804bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville pixel.alpha=arguments[x++]; 319904bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville minimum = distance; 320004bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville } 320104bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville } 320204bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville break; 320304bb72afbdb7cc9ddf0c271f9e815d1a889cdc18Eric McConville } 32043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy case VoronoiColorInterpolate: 32053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy default: 32060283b31ed43486c1b3c6d903f6992b6402419c40cristy { 3207bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy size_t 32083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy k; 32090283b31ed43486c1b3c6d903f6992b6402419c40cristy 32103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double 3211fe181a767c3b3e61b9133829c504e75e34916de8cristy minimum = MagickMaximumValue; 32123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 32130283b31ed43486c1b3c6d903f6992b6402419c40cristy /* 32140283b31ed43486c1b3c6d903f6992b6402419c40cristy Just use the closest control point you can find! 32150283b31ed43486c1b3c6d903f6992b6402419c40cristy */ 32160283b31ed43486c1b3c6d903f6992b6402419c40cristy for (k=0; k<number_arguments; k+=2+number_colors) { 32173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy double distance = 32183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy ((double)i-arguments[ k ])*((double)i-arguments[ k ]) 32193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy + ((double)j-arguments[k+1])*((double)j-arguments[k+1]); 32203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if ( distance < minimum ) { 3221bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy register ssize_t x=(ssize_t) k+2; 3222ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 32233884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.red=arguments[x++]; 3224ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 32253884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.green=arguments[x++]; 3226ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 32273884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.blue=arguments[x++]; 3228ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 32293884f69ac6f82e16fc379fb6c6521960c19045a2cristy (image->colorspace == CMYKColorspace)) 32303884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.black=arguments[x++]; 3231ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 323217f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy (image->alpha_trait != UndefinedPixelTrait)) 32333884f69ac6f82e16fc379fb6c6521960c19045a2cristy pixel.alpha=arguments[x++]; 32343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy minimum = distance; 32353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 32363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 32373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy break; 32383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 32393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 32403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy /* set the color directly back into the source image */ 3241ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 3242a29b069eef3fc51ae1f9181367fe82374ced5995cristy pixel.red=ClampPixel(QuantumRange*pixel.red); 3243ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 3244a29b069eef3fc51ae1f9181367fe82374ced5995cristy pixel.green=ClampPixel(QuantumRange*pixel.green); 3245ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 3246a29b069eef3fc51ae1f9181367fe82374ced5995cristy pixel.blue=ClampPixel(QuantumRange*pixel.blue); 3247ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 32483884f69ac6f82e16fc379fb6c6521960c19045a2cristy (image->colorspace == CMYKColorspace)) 3249a29b069eef3fc51ae1f9181367fe82374ced5995cristy pixel.black=ClampPixel(QuantumRange*pixel.black); 3250ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 325117f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy (image->alpha_trait != UndefinedPixelTrait)) 3252a29b069eef3fc51ae1f9181367fe82374ced5995cristy pixel.alpha=ClampPixel(QuantumRange*pixel.alpha); 325311a06d3f2cac0f17af7963e83bc6e9ebd2a377c0cristy SetPixelViaPixelInfo(sparse_image,&pixel,q); 3254ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy q+=GetPixelChannels(sparse_image); 32553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 32563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sync=SyncCacheViewAuthenticPixels(sparse_view,exception); 32573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (sync == MagickFalse) 32583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status=MagickFalse; 32593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (image->progress_monitor != (MagickProgressMonitor) NULL) 32603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy { 32613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy MagickBooleanType 32623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy proceed; 32633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy 3264b5d5f725fef80ff5d50db3111c05a1a521b81e7fcristy#if defined(MAGICKCORE_OPENMP_SUPPORT) 3265ac245f8a51ea65b085d751c41d8ca4b426bdfe5bcristy #pragma omp critical (MagickCore_SparseColorImage) 32663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#endif 32673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy proceed=SetImageProgress(image,SparseColorTag,progress++,image->rows); 32683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (proceed == MagickFalse) 32693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy status=MagickFalse; 32703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 32713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 32723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sparse_view=DestroyCacheView(sparse_view); 32733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy if (status == MagickFalse) 32743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy sparse_image=DestroyImage(sparse_image); 32753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy } 32763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy coeff = (double *) RelinquishMagickMemory(coeff); 32773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy return(sparse_image); 32783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} 3279