|
MagickCore
6.7.5
|
00001 /* 00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00003 % % 00004 % % 00005 % % 00006 % FFFFF X X % 00007 % F X X % 00008 % FFF X % 00009 % F X X % 00010 % F X X % 00011 % % 00012 % % 00013 % MagickCore Image Special Effects Methods % 00014 % % 00015 % Software Design % 00016 % John Cristy % 00017 % October 1996 % 00018 % % 00019 % % 00020 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization % 00021 % dedicated to making software imaging solutions freely available. % 00022 % % 00023 % You may not use this file except in compliance with the License. You may % 00024 % obtain a copy of the License at % 00025 % % 00026 % http://www.imagemagick.org/script/license.php % 00027 % % 00028 % Unless required by applicable law or agreed to in writing, software % 00029 % distributed under the License is distributed on an "AS IS" BASIS, % 00030 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 00031 % See the License for the specific language governing permissions and % 00032 % limitations under the License. % 00033 % % 00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00035 % 00036 % 00037 % 00038 */ 00039 00040 /* 00041 Include declarations. 00042 */ 00043 #include "MagickCore/studio.h" 00044 #include "MagickCore/annotate.h" 00045 #include "MagickCore/artifact.h" 00046 #include "MagickCore/attribute.h" 00047 #include "MagickCore/cache.h" 00048 #include "MagickCore/cache-view.h" 00049 #include "MagickCore/color.h" 00050 #include "MagickCore/color-private.h" 00051 #include "MagickCore/composite.h" 00052 #include "MagickCore/decorate.h" 00053 #include "MagickCore/distort.h" 00054 #include "MagickCore/draw.h" 00055 #include "MagickCore/effect.h" 00056 #include "MagickCore/enhance.h" 00057 #include "MagickCore/exception.h" 00058 #include "MagickCore/exception-private.h" 00059 #include "MagickCore/fx.h" 00060 #include "MagickCore/fx-private.h" 00061 #include "MagickCore/gem.h" 00062 #include "MagickCore/gem-private.h" 00063 #include "MagickCore/geometry.h" 00064 #include "MagickCore/layer.h" 00065 #include "MagickCore/list.h" 00066 #include "MagickCore/log.h" 00067 #include "MagickCore/image.h" 00068 #include "MagickCore/image-private.h" 00069 #include "MagickCore/magick.h" 00070 #include "MagickCore/memory_.h" 00071 #include "MagickCore/monitor.h" 00072 #include "MagickCore/monitor-private.h" 00073 #include "MagickCore/option.h" 00074 #include "MagickCore/pixel.h" 00075 #include "MagickCore/pixel-accessor.h" 00076 #include "MagickCore/property.h" 00077 #include "MagickCore/quantum.h" 00078 #include "MagickCore/quantum-private.h" 00079 #include "MagickCore/random_.h" 00080 #include "MagickCore/random-private.h" 00081 #include "MagickCore/resample.h" 00082 #include "MagickCore/resample-private.h" 00083 #include "MagickCore/resize.h" 00084 #include "MagickCore/splay-tree.h" 00085 #include "MagickCore/statistic.h" 00086 #include "MagickCore/string_.h" 00087 #include "MagickCore/string-private.h" 00088 #include "MagickCore/thread-private.h" 00089 #include "MagickCore/transform.h" 00090 #include "MagickCore/utility.h" 00091 00092 /* 00093 Define declarations. 00094 */ 00095 #define LeftShiftOperator 0xf5 00096 #define RightShiftOperator 0xf6 00097 #define LessThanEqualOperator 0xf7 00098 #define GreaterThanEqualOperator 0xf8 00099 #define EqualOperator 0xf9 00100 #define NotEqualOperator 0xfa 00101 #define LogicalAndOperator 0xfb 00102 #define LogicalOrOperator 0xfc 00103 #define ExponentialNotation 0xfd 00104 00105 struct _FxInfo 00106 { 00107 const Image 00108 *images; 00109 00110 char 00111 *expression; 00112 00113 FILE 00114 *file; 00115 00116 SplayTreeInfo 00117 *colors, 00118 *symbols; 00119 00120 CacheView 00121 **view; 00122 00123 RandomInfo 00124 *random_info; 00125 00126 ExceptionInfo 00127 *exception; 00128 }; 00129 00130 /* 00131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00132 % % 00133 % % 00134 % % 00135 + A c q u i r e F x I n f o % 00136 % % 00137 % % 00138 % % 00139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00140 % 00141 % AcquireFxInfo() allocates the FxInfo structure. 00142 % 00143 % The format of the AcquireFxInfo method is: 00144 % 00145 % FxInfo *AcquireFxInfo(Image *image,const char *expression) 00146 % 00147 % A description of each parameter follows: 00148 % 00149 % o image: the image. 00150 % 00151 % o expression: the expression. 00152 % 00153 */ 00154 MagickPrivate FxInfo *AcquireFxInfo(const Image *image,const char *expression) 00155 { 00156 char 00157 fx_op[2]; 00158 00159 const Image 00160 *next; 00161 00162 FxInfo 00163 *fx_info; 00164 00165 register ssize_t 00166 i; 00167 00168 fx_info=(FxInfo *) AcquireMagickMemory(sizeof(*fx_info)); 00169 if (fx_info == (FxInfo *) NULL) 00170 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 00171 (void) ResetMagickMemory(fx_info,0,sizeof(*fx_info)); 00172 fx_info->exception=AcquireExceptionInfo(); 00173 fx_info->images=image; 00174 fx_info->colors=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory, 00175 RelinquishMagickMemory); 00176 fx_info->symbols=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory, 00177 RelinquishMagickMemory); 00178 fx_info->view=(CacheView **) AcquireQuantumMemory(GetImageListLength( 00179 fx_info->images),sizeof(*fx_info->view)); 00180 if (fx_info->view == (CacheView **) NULL) 00181 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 00182 i=0; 00183 next=GetFirstImageInList(fx_info->images); 00184 for ( ; next != (Image *) NULL; next=next->next) 00185 { 00186 fx_info->view[i]=AcquireCacheView(next); 00187 i++; 00188 } 00189 fx_info->random_info=AcquireRandomInfo(); 00190 fx_info->expression=ConstantString(expression); 00191 fx_info->file=stderr; 00192 (void) SubstituteString(&fx_info->expression," ",""); /* compact string */ 00193 /* 00194 Force right-to-left associativity for unary negation. 00195 */ 00196 (void) SubstituteString(&fx_info->expression,"-","-1.0*"); 00197 /* 00198 Convert complex to simple operators. 00199 */ 00200 fx_op[1]='\0'; 00201 *fx_op=(char) LeftShiftOperator; 00202 (void) SubstituteString(&fx_info->expression,"<<",fx_op); 00203 *fx_op=(char) RightShiftOperator; 00204 (void) SubstituteString(&fx_info->expression,">>",fx_op); 00205 *fx_op=(char) LessThanEqualOperator; 00206 (void) SubstituteString(&fx_info->expression,"<=",fx_op); 00207 *fx_op=(char) GreaterThanEqualOperator; 00208 (void) SubstituteString(&fx_info->expression,">=",fx_op); 00209 *fx_op=(char) EqualOperator; 00210 (void) SubstituteString(&fx_info->expression,"==",fx_op); 00211 *fx_op=(char) NotEqualOperator; 00212 (void) SubstituteString(&fx_info->expression,"!=",fx_op); 00213 *fx_op=(char) LogicalAndOperator; 00214 (void) SubstituteString(&fx_info->expression,"&&",fx_op); 00215 *fx_op=(char) LogicalOrOperator; 00216 (void) SubstituteString(&fx_info->expression,"||",fx_op); 00217 *fx_op=(char) ExponentialNotation; 00218 (void) SubstituteString(&fx_info->expression,"**",fx_op); 00219 return(fx_info); 00220 } 00221 00222 /* 00223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00224 % % 00225 % % 00226 % % 00227 % A d d N o i s e I m a g e % 00228 % % 00229 % % 00230 % % 00231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00232 % 00233 % AddNoiseImage() adds random noise to the image. 00234 % 00235 % The format of the AddNoiseImage method is: 00236 % 00237 % Image *AddNoiseImage(const Image *image,const NoiseType noise_type, 00238 % const double attenuate,ExceptionInfo *exception) 00239 % 00240 % A description of each parameter follows: 00241 % 00242 % o image: the image. 00243 % 00244 % o channel: the channel type. 00245 % 00246 % o noise_type: The type of noise: Uniform, Gaussian, Multiplicative, 00247 % Impulse, Laplacian, or Poisson. 00248 % 00249 % o attenuate: attenuate the random distribution. 00250 % 00251 % o exception: return any errors or warnings in this structure. 00252 % 00253 */ 00254 MagickExport Image *AddNoiseImage(const Image *image,const NoiseType noise_type, 00255 const double attenuate,ExceptionInfo *exception) 00256 { 00257 #define AddNoiseImageTag "AddNoise/Image" 00258 00259 CacheView 00260 *image_view, 00261 *noise_view; 00262 00263 Image 00264 *noise_image; 00265 00266 MagickBooleanType 00267 status; 00268 00269 MagickOffsetType 00270 progress; 00271 00272 RandomInfo 00273 **restrict random_info; 00274 00275 ssize_t 00276 y; 00277 00278 /* 00279 Initialize noise image attributes. 00280 */ 00281 assert(image != (const Image *) NULL); 00282 assert(image->signature == MagickSignature); 00283 if (image->debug != MagickFalse) 00284 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 00285 assert(exception != (ExceptionInfo *) NULL); 00286 assert(exception->signature == MagickSignature); 00287 noise_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception); 00288 if (noise_image == (Image *) NULL) 00289 return((Image *) NULL); 00290 if (SetImageStorageClass(noise_image,DirectClass,exception) == MagickFalse) 00291 { 00292 noise_image=DestroyImage(noise_image); 00293 return((Image *) NULL); 00294 } 00295 /* 00296 Add noise in each row. 00297 */ 00298 status=MagickTrue; 00299 progress=0; 00300 random_info=AcquireRandomInfoThreadSet(); 00301 image_view=AcquireCacheView(image); 00302 noise_view=AcquireCacheView(noise_image); 00303 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00304 #pragma omp parallel for schedule(static,4) shared(progress,status) 00305 #endif 00306 for (y=0; y < (ssize_t) image->rows; y++) 00307 { 00308 const int 00309 id = GetOpenMPThreadId(); 00310 00311 MagickBooleanType 00312 sync; 00313 00314 register const Quantum 00315 *restrict p; 00316 00317 register ssize_t 00318 x; 00319 00320 register Quantum 00321 *restrict q; 00322 00323 if (status == MagickFalse) 00324 continue; 00325 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 00326 q=QueueCacheViewAuthenticPixels(noise_view,0,y,noise_image->columns,1, 00327 exception); 00328 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 00329 { 00330 status=MagickFalse; 00331 continue; 00332 } 00333 for (x=0; x < (ssize_t) image->columns; x++) 00334 { 00335 register ssize_t 00336 i; 00337 00338 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 00339 { 00340 PixelChannel 00341 channel; 00342 00343 PixelTrait 00344 noise_traits, 00345 traits; 00346 00347 channel=GetPixelChannelMapChannel(image,i); 00348 traits=GetPixelChannelMapTraits(image,channel); 00349 noise_traits=GetPixelChannelMapTraits(noise_image,channel); 00350 if ((traits == UndefinedPixelTrait) || 00351 (noise_traits == UndefinedPixelTrait)) 00352 continue; 00353 if (((noise_traits & CopyPixelTrait) != 0) || 00354 (GetPixelMask(image,p) != 0)) 00355 { 00356 SetPixelChannel(noise_image,channel,p[i],q); 00357 continue; 00358 } 00359 SetPixelChannel(noise_image,channel,ClampToQuantum( 00360 GenerateDifferentialNoise(random_info[id],p[i],noise_type,attenuate)), 00361 q); 00362 } 00363 p+=GetPixelChannels(image); 00364 q+=GetPixelChannels(noise_image); 00365 } 00366 sync=SyncCacheViewAuthenticPixels(noise_view,exception); 00367 if (sync == MagickFalse) 00368 status=MagickFalse; 00369 if (image->progress_monitor != (MagickProgressMonitor) NULL) 00370 { 00371 MagickBooleanType 00372 proceed; 00373 00374 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00375 #pragma omp critical (MagickCore_AddNoiseImage) 00376 #endif 00377 proceed=SetImageProgress(image,AddNoiseImageTag,progress++, 00378 image->rows); 00379 if (proceed == MagickFalse) 00380 status=MagickFalse; 00381 } 00382 } 00383 noise_view=DestroyCacheView(noise_view); 00384 image_view=DestroyCacheView(image_view); 00385 random_info=DestroyRandomInfoThreadSet(random_info); 00386 if (status == MagickFalse) 00387 noise_image=DestroyImage(noise_image); 00388 return(noise_image); 00389 } 00390 00391 /* 00392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00393 % % 00394 % % 00395 % % 00396 % B l u e S h i f t I m a g e % 00397 % % 00398 % % 00399 % % 00400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00401 % 00402 % BlueShiftImage() mutes the colors of the image to simulate a scene at 00403 % nighttime in the moonlight. 00404 % 00405 % The format of the BlueShiftImage method is: 00406 % 00407 % Image *BlueShiftImage(const Image *image,const double factor, 00408 % ExceptionInfo *exception) 00409 % 00410 % A description of each parameter follows: 00411 % 00412 % o image: the image. 00413 % 00414 % o factor: the shift factor. 00415 % 00416 % o exception: return any errors or warnings in this structure. 00417 % 00418 */ 00419 MagickExport Image *BlueShiftImage(const Image *image,const double factor, 00420 ExceptionInfo *exception) 00421 { 00422 #define BlueShiftImageTag "BlueShift/Image" 00423 00424 CacheView 00425 *image_view, 00426 *shift_view; 00427 00428 Image 00429 *shift_image; 00430 00431 MagickBooleanType 00432 status; 00433 00434 MagickOffsetType 00435 progress; 00436 00437 ssize_t 00438 y; 00439 00440 /* 00441 Allocate blue shift image. 00442 */ 00443 assert(image != (const Image *) NULL); 00444 assert(image->signature == MagickSignature); 00445 if (image->debug != MagickFalse) 00446 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 00447 assert(exception != (ExceptionInfo *) NULL); 00448 assert(exception->signature == MagickSignature); 00449 shift_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception); 00450 if (shift_image == (Image *) NULL) 00451 return((Image *) NULL); 00452 if (SetImageStorageClass(shift_image,DirectClass,exception) == MagickFalse) 00453 { 00454 shift_image=DestroyImage(shift_image); 00455 return((Image *) NULL); 00456 } 00457 /* 00458 Blue-shift DirectClass image. 00459 */ 00460 status=MagickTrue; 00461 progress=0; 00462 image_view=AcquireCacheView(image); 00463 shift_view=AcquireCacheView(shift_image); 00464 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00465 #pragma omp parallel for schedule(static,4) shared(progress,status) 00466 #endif 00467 for (y=0; y < (ssize_t) image->rows; y++) 00468 { 00469 MagickBooleanType 00470 sync; 00471 00472 PixelInfo 00473 pixel; 00474 00475 Quantum 00476 quantum; 00477 00478 register const Quantum 00479 *restrict p; 00480 00481 register ssize_t 00482 x; 00483 00484 register Quantum 00485 *restrict q; 00486 00487 if (status == MagickFalse) 00488 continue; 00489 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 00490 q=QueueCacheViewAuthenticPixels(shift_view,0,y,shift_image->columns,1, 00491 exception); 00492 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 00493 { 00494 status=MagickFalse; 00495 continue; 00496 } 00497 for (x=0; x < (ssize_t) image->columns; x++) 00498 { 00499 quantum=GetPixelRed(image,p); 00500 if (GetPixelGreen(image,p) < quantum) 00501 quantum=GetPixelGreen(image,p); 00502 if (GetPixelBlue(image,p) < quantum) 00503 quantum=GetPixelBlue(image,p); 00504 pixel.red=0.5*(GetPixelRed(image,p)+factor*quantum); 00505 pixel.green=0.5*(GetPixelGreen(image,p)+factor*quantum); 00506 pixel.blue=0.5*(GetPixelBlue(image,p)+factor*quantum); 00507 quantum=GetPixelRed(image,p); 00508 if (GetPixelGreen(image,p) > quantum) 00509 quantum=GetPixelGreen(image,p); 00510 if (GetPixelBlue(image,p) > quantum) 00511 quantum=GetPixelBlue(image,p); 00512 pixel.red=0.5*(pixel.red+factor*quantum); 00513 pixel.green=0.5*(pixel.green+factor*quantum); 00514 pixel.blue=0.5*(pixel.blue+factor*quantum); 00515 SetPixelRed(shift_image,ClampToQuantum(pixel.red),q); 00516 SetPixelGreen(shift_image,ClampToQuantum(pixel.green),q); 00517 SetPixelBlue(shift_image,ClampToQuantum(pixel.blue),q); 00518 p+=GetPixelChannels(image); 00519 q+=GetPixelChannels(shift_image); 00520 } 00521 sync=SyncCacheViewAuthenticPixels(shift_view,exception); 00522 if (sync == MagickFalse) 00523 status=MagickFalse; 00524 if (image->progress_monitor != (MagickProgressMonitor) NULL) 00525 { 00526 MagickBooleanType 00527 proceed; 00528 00529 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00530 #pragma omp critical (MagickCore_BlueShiftImage) 00531 #endif 00532 proceed=SetImageProgress(image,BlueShiftImageTag,progress++, 00533 image->rows); 00534 if (proceed == MagickFalse) 00535 status=MagickFalse; 00536 } 00537 } 00538 image_view=DestroyCacheView(image_view); 00539 shift_view=DestroyCacheView(shift_view); 00540 if (status == MagickFalse) 00541 shift_image=DestroyImage(shift_image); 00542 return(shift_image); 00543 } 00544 00545 /* 00546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00547 % % 00548 % % 00549 % % 00550 % C h a r c o a l I m a g e % 00551 % % 00552 % % 00553 % % 00554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00555 % 00556 % CharcoalImage() creates a new image that is a copy of an existing one with 00557 % the edge highlighted. It allocates the memory necessary for the new Image 00558 % structure and returns a pointer to the new image. 00559 % 00560 % The format of the CharcoalImage method is: 00561 % 00562 % Image *CharcoalImage(const Image *image,const double radius, 00563 % const double sigma,const double bias,ExceptionInfo *exception) 00564 % 00565 % A description of each parameter follows: 00566 % 00567 % o image: the image. 00568 % 00569 % o radius: the radius of the pixel neighborhood. 00570 % 00571 % o sigma: the standard deviation of the Gaussian, in pixels. 00572 % 00573 % o bias: the bias. 00574 % 00575 % o exception: return any errors or warnings in this structure. 00576 % 00577 */ 00578 MagickExport Image *CharcoalImage(const Image *image,const double radius, 00579 const double sigma,const double bias,ExceptionInfo *exception) 00580 { 00581 Image 00582 *charcoal_image, 00583 *clone_image, 00584 *edge_image; 00585 00586 assert(image != (Image *) NULL); 00587 assert(image->signature == MagickSignature); 00588 if (image->debug != MagickFalse) 00589 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 00590 assert(exception != (ExceptionInfo *) NULL); 00591 assert(exception->signature == MagickSignature); 00592 clone_image=CloneImage(image,0,0,MagickTrue,exception); 00593 if (clone_image == (Image *) NULL) 00594 return((Image *) NULL); 00595 (void) SetImageType(clone_image,GrayscaleType,exception); 00596 edge_image=EdgeImage(clone_image,radius,sigma,exception); 00597 clone_image=DestroyImage(clone_image); 00598 if (edge_image == (Image *) NULL) 00599 return((Image *) NULL); 00600 charcoal_image=BlurImage(edge_image,radius,sigma,bias,exception); 00601 edge_image=DestroyImage(edge_image); 00602 if (charcoal_image == (Image *) NULL) 00603 return((Image *) NULL); 00604 (void) NormalizeImage(charcoal_image,exception); 00605 (void) NegateImage(charcoal_image,MagickFalse,exception); 00606 (void) SetImageType(charcoal_image,GrayscaleType,exception); 00607 return(charcoal_image); 00608 } 00609 00610 /* 00611 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00612 % % 00613 % % 00614 % % 00615 % C o l o r i z e I m a g e % 00616 % % 00617 % % 00618 % % 00619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00620 % 00621 % ColorizeImage() blends the fill color with each pixel in the image. 00622 % A percentage blend is specified with opacity. Control the application 00623 % of different color components by specifying a different percentage for 00624 % each component (e.g. 90/100/10 is 90% red, 100% green, and 10% blue). 00625 % 00626 % The format of the ColorizeImage method is: 00627 % 00628 % Image *ColorizeImage(const Image *image,const char *blend, 00629 % const PixelInfo *colorize,ExceptionInfo *exception) 00630 % 00631 % A description of each parameter follows: 00632 % 00633 % o image: the image. 00634 % 00635 % o blend: A character string indicating the level of blending as a 00636 % percentage. 00637 % 00638 % o colorize: A color value. 00639 % 00640 % o exception: return any errors or warnings in this structure. 00641 % 00642 */ 00643 MagickExport Image *ColorizeImage(const Image *image,const char *blend, 00644 const PixelInfo *colorize,ExceptionInfo *exception) 00645 { 00646 #define ColorizeImageTag "Colorize/Image" 00647 00648 CacheView 00649 *colorize_view, 00650 *image_view; 00651 00652 GeometryInfo 00653 geometry_info; 00654 00655 Image 00656 *colorize_image; 00657 00658 MagickBooleanType 00659 status; 00660 00661 MagickOffsetType 00662 progress; 00663 00664 MagickStatusType 00665 flags; 00666 00667 PixelInfo 00668 pixel; 00669 00670 ssize_t 00671 y; 00672 00673 /* 00674 Allocate colorized image. 00675 */ 00676 assert(image != (const Image *) NULL); 00677 assert(image->signature == MagickSignature); 00678 if (image->debug != MagickFalse) 00679 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 00680 assert(exception != (ExceptionInfo *) NULL); 00681 assert(exception->signature == MagickSignature); 00682 colorize_image=CloneImage(image,image->columns,image->rows,MagickTrue, 00683 exception); 00684 if (colorize_image == (Image *) NULL) 00685 return((Image *) NULL); 00686 if (SetImageStorageClass(colorize_image,DirectClass,exception) == MagickFalse) 00687 { 00688 colorize_image=DestroyImage(colorize_image); 00689 return((Image *) NULL); 00690 } 00691 if ((colorize->matte != MagickFalse) && 00692 (colorize_image->matte == MagickFalse)) 00693 (void) SetImageAlpha(colorize_image,OpaqueAlpha,exception); 00694 if (blend == (const char *) NULL) 00695 return(colorize_image); 00696 /* 00697 Determine RGB values of the fill color for pixel 00698 */ 00699 GetPixelInfo(image,&pixel); 00700 flags=ParseGeometry(blend,&geometry_info); 00701 pixel.red=geometry_info.rho; 00702 pixel.green=geometry_info.rho; 00703 pixel.blue=geometry_info.rho; 00704 pixel.alpha=100.0; 00705 if ((flags & SigmaValue) != 0) 00706 pixel.green=geometry_info.sigma; 00707 if ((flags & XiValue) != 0) 00708 pixel.blue=geometry_info.xi; 00709 if ((flags & PsiValue) != 0) 00710 pixel.alpha=geometry_info.psi; 00711 if (pixel.colorspace == CMYKColorspace) 00712 { 00713 pixel.black=geometry_info.rho; 00714 if ((flags & PsiValue) != 0) 00715 pixel.black=geometry_info.psi; 00716 if ((flags & ChiValue) != 0) 00717 pixel.alpha=geometry_info.chi; 00718 } 00719 /* 00720 Colorize DirectClass image. 00721 */ 00722 status=MagickTrue; 00723 progress=0; 00724 image_view=AcquireCacheView(image); 00725 colorize_view=AcquireCacheView(colorize_image); 00726 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00727 #pragma omp parallel for schedule(static,4) shared(progress,status) 00728 #endif 00729 for (y=0; y < (ssize_t) image->rows; y++) 00730 { 00731 MagickBooleanType 00732 sync; 00733 00734 register const Quantum 00735 *restrict p; 00736 00737 register ssize_t 00738 x; 00739 00740 register Quantum 00741 *restrict q; 00742 00743 if (status == MagickFalse) 00744 continue; 00745 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 00746 q=QueueCacheViewAuthenticPixels(colorize_view,0,y,colorize_image->columns,1, 00747 exception); 00748 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 00749 { 00750 status=MagickFalse; 00751 continue; 00752 } 00753 for (x=0; x < (ssize_t) image->columns; x++) 00754 { 00755 register ssize_t 00756 i; 00757 00758 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 00759 { 00760 PixelChannel 00761 channel; 00762 00763 PixelTrait 00764 colorize_traits, 00765 traits; 00766 00767 channel=GetPixelChannelMapChannel(image,i); 00768 traits=GetPixelChannelMapTraits(image,channel); 00769 colorize_traits=GetPixelChannelMapTraits(colorize_image,channel); 00770 if ((traits == UndefinedPixelTrait) || 00771 (colorize_traits == UndefinedPixelTrait)) 00772 continue; 00773 if (((colorize_traits & CopyPixelTrait) != 0) || 00774 (GetPixelMask(image,p) != 0)) 00775 { 00776 SetPixelChannel(colorize_image,channel,p[i],q); 00777 continue; 00778 } 00779 switch (channel) 00780 { 00781 case RedPixelChannel: 00782 { 00783 SetPixelChannel(colorize_image,channel,ClampToQuantum((p[i]* 00784 (100.0-pixel.red)+colorize->red*pixel.red)/100.0),q); 00785 break; 00786 } 00787 case GreenPixelChannel: 00788 { 00789 SetPixelChannel(colorize_image,channel,ClampToQuantum((p[i]* 00790 (100.0-pixel.green)+colorize->green*pixel.green)/100.0),q); 00791 break; 00792 } 00793 case BluePixelChannel: 00794 { 00795 SetPixelChannel(colorize_image,channel,ClampToQuantum((p[i]* 00796 (100.0-pixel.blue)+colorize->blue*pixel.blue)/100.0),q); 00797 break; 00798 } 00799 case BlackPixelChannel: 00800 { 00801 SetPixelChannel(colorize_image,channel,ClampToQuantum((p[i]* 00802 (100.0-pixel.black)+colorize->black*pixel.black)/100.0),q); 00803 break; 00804 } 00805 case AlphaPixelChannel: 00806 { 00807 SetPixelChannel(colorize_image,channel,ClampToQuantum((p[i]* 00808 (100.0-pixel.alpha)+colorize->alpha*pixel.alpha)/100.0),q); 00809 break; 00810 } 00811 default: 00812 { 00813 SetPixelChannel(colorize_image,channel,p[i],q); 00814 break; 00815 } 00816 } 00817 } 00818 p+=GetPixelChannels(image); 00819 q+=GetPixelChannels(colorize_image); 00820 } 00821 sync=SyncCacheViewAuthenticPixels(colorize_view,exception); 00822 if (sync == MagickFalse) 00823 status=MagickFalse; 00824 if (image->progress_monitor != (MagickProgressMonitor) NULL) 00825 { 00826 MagickBooleanType 00827 proceed; 00828 00829 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00830 #pragma omp critical (MagickCore_ColorizeImage) 00831 #endif 00832 proceed=SetImageProgress(image,ColorizeImageTag,progress++,image->rows); 00833 if (proceed == MagickFalse) 00834 status=MagickFalse; 00835 } 00836 } 00837 image_view=DestroyCacheView(image_view); 00838 colorize_view=DestroyCacheView(colorize_view); 00839 if (status == MagickFalse) 00840 colorize_image=DestroyImage(colorize_image); 00841 return(colorize_image); 00842 } 00843 00844 /* 00845 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00846 % % 00847 % % 00848 % % 00849 % C o l o r M a t r i x I m a g e % 00850 % % 00851 % % 00852 % % 00853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00854 % 00855 % ColorMatrixImage() applies color transformation to an image. This method 00856 % permits saturation changes, hue rotation, luminance to alpha, and various 00857 % other effects. Although variable-sized transformation matrices can be used, 00858 % typically one uses a 5x5 matrix for an RGBA image and a 6x6 for CMYKA 00859 % (or RGBA with offsets). The matrix is similar to those used by Adobe Flash 00860 % except offsets are in column 6 rather than 5 (in support of CMYKA images) 00861 % and offsets are normalized (divide Flash offset by 255). 00862 % 00863 % The format of the ColorMatrixImage method is: 00864 % 00865 % Image *ColorMatrixImage(const Image *image, 00866 % const KernelInfo *color_matrix,ExceptionInfo *exception) 00867 % 00868 % A description of each parameter follows: 00869 % 00870 % o image: the image. 00871 % 00872 % o color_matrix: the color matrix. 00873 % 00874 % o exception: return any errors or warnings in this structure. 00875 % 00876 */ 00877 /* FUTURE: modify to make use of a MagickMatrix Mutliply function 00878 That should be provided in "matrix.c" 00879 (ASIDE: actually distorts should do this too but currently doesn't) 00880 */ 00881 00882 MagickExport Image *ColorMatrixImage(const Image *image, 00883 const KernelInfo *color_matrix,ExceptionInfo *exception) 00884 { 00885 #define ColorMatrixImageTag "ColorMatrix/Image" 00886 00887 CacheView 00888 *color_view, 00889 *image_view; 00890 00891 double 00892 ColorMatrix[6][6] = 00893 { 00894 { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, 00895 { 0.0, 1.0, 0.0, 0.0, 0.0, 0.0 }, 00896 { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 }, 00897 { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 00898 { 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 }, 00899 { 0.0, 0.0, 0.0, 0.0, 0.0, 1.0 } 00900 }; 00901 00902 Image 00903 *color_image; 00904 00905 MagickBooleanType 00906 status; 00907 00908 MagickOffsetType 00909 progress; 00910 00911 register ssize_t 00912 i; 00913 00914 ssize_t 00915 u, 00916 v, 00917 y; 00918 00919 /* 00920 Map given color_matrix, into a 6x6 matrix RGBKA and a constant 00921 */ 00922 assert(image != (Image *) NULL); 00923 assert(image->signature == MagickSignature); 00924 if (image->debug != MagickFalse) 00925 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 00926 assert(exception != (ExceptionInfo *) NULL); 00927 assert(exception->signature == MagickSignature); 00928 i=0; 00929 for (v=0; v < (ssize_t) color_matrix->height; v++) 00930 for (u=0; u < (ssize_t) color_matrix->width; u++) 00931 { 00932 if ((v < 6) && (u < 6)) 00933 ColorMatrix[v][u]=color_matrix->values[i]; 00934 i++; 00935 } 00936 /* 00937 Initialize color image. 00938 */ 00939 color_image=CloneImage(image,0,0,MagickTrue,exception); 00940 if (color_image == (Image *) NULL) 00941 return((Image *) NULL); 00942 if (SetImageStorageClass(color_image,DirectClass,exception) == MagickFalse) 00943 { 00944 color_image=DestroyImage(color_image); 00945 return((Image *) NULL); 00946 } 00947 if (image->debug != MagickFalse) 00948 { 00949 char 00950 format[MaxTextExtent], 00951 *message; 00952 00953 (void) LogMagickEvent(TransformEvent,GetMagickModule(), 00954 " ColorMatrix image with color matrix:"); 00955 message=AcquireString(""); 00956 for (v=0; v < 6; v++) 00957 { 00958 *message='\0'; 00959 (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) v); 00960 (void) ConcatenateString(&message,format); 00961 for (u=0; u < 6; u++) 00962 { 00963 (void) FormatLocaleString(format,MaxTextExtent,"%+f ", 00964 ColorMatrix[v][u]); 00965 (void) ConcatenateString(&message,format); 00966 } 00967 (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message); 00968 } 00969 message=DestroyString(message); 00970 } 00971 /* 00972 Apply the ColorMatrix to image. 00973 */ 00974 status=MagickTrue; 00975 progress=0; 00976 image_view=AcquireCacheView(image); 00977 color_view=AcquireCacheView(color_image); 00978 #if defined(MAGICKCORE_OPENMP_SUPPORT) 00979 #pragma omp parallel for schedule(static,4) shared(progress,status) 00980 #endif 00981 for (y=0; y < (ssize_t) image->rows; y++) 00982 { 00983 MagickRealType 00984 pixel; 00985 00986 register const Quantum 00987 *restrict p; 00988 00989 register Quantum 00990 *restrict q; 00991 00992 register ssize_t 00993 x; 00994 00995 if (status == MagickFalse) 00996 continue; 00997 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 00998 q=GetCacheViewAuthenticPixels(color_view,0,y,color_image->columns,1, 00999 exception); 01000 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 01001 { 01002 status=MagickFalse; 01003 continue; 01004 } 01005 for (x=0; x < (ssize_t) image->columns; x++) 01006 { 01007 register ssize_t 01008 v; 01009 01010 size_t 01011 height; 01012 01013 height=color_matrix->height > 6 ? 6UL : color_matrix->height; 01014 for (v=0; v < (ssize_t) height; v++) 01015 { 01016 pixel=ColorMatrix[v][0]*GetPixelRed(image,p)+ColorMatrix[v][1]* 01017 GetPixelGreen(image,p)+ColorMatrix[v][2]*GetPixelBlue(image,p); 01018 if (image->colorspace == CMYKColorspace) 01019 pixel+=ColorMatrix[v][3]*GetPixelBlack(image,p); 01020 if (image->matte != MagickFalse) 01021 pixel+=ColorMatrix[v][4]*GetPixelAlpha(image,p); 01022 pixel+=QuantumRange*ColorMatrix[v][5]; 01023 switch (v) 01024 { 01025 case 0: SetPixelRed(color_image,ClampToQuantum(pixel),q); break; 01026 case 1: SetPixelGreen(color_image,ClampToQuantum(pixel),q); break; 01027 case 2: SetPixelBlue(color_image,ClampToQuantum(pixel),q); break; 01028 case 3: 01029 { 01030 if (image->colorspace == CMYKColorspace) 01031 SetPixelBlack(color_image,ClampToQuantum(pixel),q); 01032 break; 01033 } 01034 case 4: 01035 { 01036 if (image->matte != MagickFalse) 01037 SetPixelAlpha(color_image,ClampToQuantum(pixel),q); 01038 break; 01039 } 01040 } 01041 } 01042 p+=GetPixelChannels(image); 01043 q+=GetPixelChannels(color_image); 01044 } 01045 if (SyncCacheViewAuthenticPixels(color_view,exception) == MagickFalse) 01046 status=MagickFalse; 01047 if (image->progress_monitor != (MagickProgressMonitor) NULL) 01048 { 01049 MagickBooleanType 01050 proceed; 01051 01052 #if defined(MAGICKCORE_OPENMP_SUPPORT) 01053 #pragma omp critical (MagickCore_ColorMatrixImage) 01054 #endif 01055 proceed=SetImageProgress(image,ColorMatrixImageTag,progress++, 01056 image->rows); 01057 if (proceed == MagickFalse) 01058 status=MagickFalse; 01059 } 01060 } 01061 color_view=DestroyCacheView(color_view); 01062 image_view=DestroyCacheView(image_view); 01063 if (status == MagickFalse) 01064 color_image=DestroyImage(color_image); 01065 return(color_image); 01066 } 01067 01068 /* 01069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01070 % % 01071 % % 01072 % % 01073 + D e s t r o y F x I n f o % 01074 % % 01075 % % 01076 % % 01077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01078 % 01079 % DestroyFxInfo() deallocates memory associated with an FxInfo structure. 01080 % 01081 % The format of the DestroyFxInfo method is: 01082 % 01083 % ImageInfo *DestroyFxInfo(ImageInfo *fx_info) 01084 % 01085 % A description of each parameter follows: 01086 % 01087 % o fx_info: the fx info. 01088 % 01089 */ 01090 MagickPrivate FxInfo *DestroyFxInfo(FxInfo *fx_info) 01091 { 01092 register ssize_t 01093 i; 01094 01095 fx_info->exception=DestroyExceptionInfo(fx_info->exception); 01096 fx_info->expression=DestroyString(fx_info->expression); 01097 fx_info->symbols=DestroySplayTree(fx_info->symbols); 01098 fx_info->colors=DestroySplayTree(fx_info->colors); 01099 for (i=(ssize_t) GetImageListLength(fx_info->images)-1; i >= 0; i--) 01100 fx_info->view[i]=DestroyCacheView(fx_info->view[i]); 01101 fx_info->view=(CacheView **) RelinquishMagickMemory(fx_info->view); 01102 fx_info->random_info=DestroyRandomInfo(fx_info->random_info); 01103 fx_info=(FxInfo *) RelinquishMagickMemory(fx_info); 01104 return(fx_info); 01105 } 01106 01107 /* 01108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01109 % % 01110 % % 01111 % % 01112 + F x E v a l u a t e C h a n n e l E x p r e s s i o n % 01113 % % 01114 % % 01115 % % 01116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01117 % 01118 % FxEvaluateChannelExpression() evaluates an expression and returns the 01119 % results. 01120 % 01121 % The format of the FxEvaluateExpression method is: 01122 % 01123 % MagickRealType FxEvaluateChannelExpression(FxInfo *fx_info, 01124 % const PixelChannel channel,const ssize_t x,const ssize_t y, 01125 % MagickRealType *alpha,Exceptioninfo *exception) 01126 % MagickRealType FxEvaluateExpression(FxInfo *fx_info, 01127 % MagickRealType *alpha,Exceptioninfo *exception) 01128 % 01129 % A description of each parameter follows: 01130 % 01131 % o fx_info: the fx info. 01132 % 01133 % o channel: the channel. 01134 % 01135 % o x,y: the pixel position. 01136 % 01137 % o alpha: the result. 01138 % 01139 % o exception: return any errors or warnings in this structure. 01140 % 01141 */ 01142 01143 static inline double MagickMax(const double x,const double y) 01144 { 01145 if (x > y) 01146 return(x); 01147 return(y); 01148 } 01149 01150 static inline double MagickMin(const double x,const double y) 01151 { 01152 if (x < y) 01153 return(x); 01154 return(y); 01155 } 01156 01157 static MagickRealType FxChannelStatistics(FxInfo *fx_info,const Image *image, 01158 PixelChannel channel,const char *symbol,ExceptionInfo *exception) 01159 { 01160 char 01161 key[MaxTextExtent], 01162 statistic[MaxTextExtent]; 01163 01164 const char 01165 *value; 01166 01167 register const char 01168 *p; 01169 01170 for (p=symbol; (*p != '.') && (*p != '\0'); p++) ; 01171 if (*p == '.') 01172 switch (*++p) /* e.g. depth.r */ 01173 { 01174 case 'r': channel=RedPixelChannel; break; 01175 case 'g': channel=GreenPixelChannel; break; 01176 case 'b': channel=BluePixelChannel; break; 01177 case 'c': channel=CyanPixelChannel; break; 01178 case 'm': channel=MagentaPixelChannel; break; 01179 case 'y': channel=YellowPixelChannel; break; 01180 case 'k': channel=BlackPixelChannel; break; 01181 default: break; 01182 } 01183 (void) FormatLocaleString(key,MaxTextExtent,"%p.%.20g.%s",(void *) image, 01184 (double) channel,symbol); 01185 value=(const char *) GetValueFromSplayTree(fx_info->symbols,key); 01186 if (value != (const char *) NULL) 01187 return(QuantumScale*StringToDouble(value,(char **) NULL)); 01188 (void) DeleteNodeFromSplayTree(fx_info->symbols,key); 01189 if (LocaleNCompare(symbol,"depth",5) == 0) 01190 { 01191 size_t 01192 depth; 01193 01194 depth=GetImageDepth(image,exception); 01195 (void) FormatLocaleString(statistic,MaxTextExtent,"%.20g",(double) depth); 01196 } 01197 if (LocaleNCompare(symbol,"kurtosis",8) == 0) 01198 { 01199 double 01200 kurtosis, 01201 skewness; 01202 01203 (void) GetImageKurtosis(image,&kurtosis,&skewness,exception); 01204 (void) FormatLocaleString(statistic,MaxTextExtent,"%g",kurtosis); 01205 } 01206 if (LocaleNCompare(symbol,"maxima",6) == 0) 01207 { 01208 double 01209 maxima, 01210 minima; 01211 01212 (void) GetImageRange(image,&minima,&maxima,exception); 01213 (void) FormatLocaleString(statistic,MaxTextExtent,"%g",maxima); 01214 } 01215 if (LocaleNCompare(symbol,"mean",4) == 0) 01216 { 01217 double 01218 mean, 01219 standard_deviation; 01220 01221 (void) GetImageMean(image,&mean,&standard_deviation,exception); 01222 (void) FormatLocaleString(statistic,MaxTextExtent,"%g",mean); 01223 } 01224 if (LocaleNCompare(symbol,"minima",6) == 0) 01225 { 01226 double 01227 maxima, 01228 minima; 01229 01230 (void) GetImageRange(image,&minima,&maxima,exception); 01231 (void) FormatLocaleString(statistic,MaxTextExtent,"%g",minima); 01232 } 01233 if (LocaleNCompare(symbol,"skewness",8) == 0) 01234 { 01235 double 01236 kurtosis, 01237 skewness; 01238 01239 (void) GetImageKurtosis(image,&kurtosis,&skewness,exception); 01240 (void) FormatLocaleString(statistic,MaxTextExtent,"%g",skewness); 01241 } 01242 if (LocaleNCompare(symbol,"standard_deviation",18) == 0) 01243 { 01244 double 01245 mean, 01246 standard_deviation; 01247 01248 (void) GetImageMean(image,&mean,&standard_deviation,exception); 01249 (void) FormatLocaleString(statistic,MaxTextExtent,"%g", 01250 standard_deviation); 01251 } 01252 (void) AddValueToSplayTree(fx_info->symbols,ConstantString(key), 01253 ConstantString(statistic)); 01254 return(QuantumScale*StringToDouble(statistic,(char **) NULL)); 01255 } 01256 01257 static MagickRealType 01258 FxEvaluateSubexpression(FxInfo *,const PixelChannel,const ssize_t, 01259 const ssize_t,const char *,MagickRealType *,ExceptionInfo *); 01260 01261 static MagickOffsetType FxGCD(MagickOffsetType alpha,MagickOffsetType beta) 01262 { 01263 if (beta != 0) 01264 return(FxGCD(beta,alpha % beta)); 01265 return(alpha); 01266 } 01267 01268 static inline const char *FxSubexpression(const char *expression, 01269 ExceptionInfo *exception) 01270 { 01271 const char 01272 *subexpression; 01273 01274 register ssize_t 01275 level; 01276 01277 level=0; 01278 subexpression=expression; 01279 while ((*subexpression != '\0') && 01280 ((level != 1) || (strchr(")",(int) *subexpression) == (char *) NULL))) 01281 { 01282 if (strchr("(",(int) *subexpression) != (char *) NULL) 01283 level++; 01284 else 01285 if (strchr(")",(int) *subexpression) != (char *) NULL) 01286 level--; 01287 subexpression++; 01288 } 01289 if (*subexpression == '\0') 01290 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 01291 "UnbalancedParenthesis","`%s'",expression); 01292 return(subexpression); 01293 } 01294 01295 static MagickRealType FxGetSymbol(FxInfo *fx_info,const PixelChannel channel, 01296 const ssize_t x,const ssize_t y,const char *expression, 01297 ExceptionInfo *exception) 01298 { 01299 char 01300 *q, 01301 subexpression[MaxTextExtent], 01302 symbol[MaxTextExtent]; 01303 01304 const char 01305 *p, 01306 *value; 01307 01308 Image 01309 *image; 01310 01311 PixelInfo 01312 pixel; 01313 01314 MagickRealType 01315 alpha, 01316 beta; 01317 01318 PointInfo 01319 point; 01320 01321 register ssize_t 01322 i; 01323 01324 size_t 01325 length, 01326 level; 01327 01328 p=expression; 01329 i=GetImageIndexInList(fx_info->images); 01330 level=0; 01331 point.x=(double) x; 01332 point.y=(double) y; 01333 if (isalpha((int) *(p+1)) == 0) 01334 { 01335 if (strchr("suv",(int) *p) != (char *) NULL) 01336 { 01337 switch (*p) 01338 { 01339 case 's': 01340 default: 01341 { 01342 i=GetImageIndexInList(fx_info->images); 01343 break; 01344 } 01345 case 'u': i=0; break; 01346 case 'v': i=1; break; 01347 } 01348 p++; 01349 if (*p == '[') 01350 { 01351 level++; 01352 q=subexpression; 01353 for (p++; *p != '\0'; ) 01354 { 01355 if (*p == '[') 01356 level++; 01357 else 01358 if (*p == ']') 01359 { 01360 level--; 01361 if (level == 0) 01362 break; 01363 } 01364 *q++=(*p++); 01365 } 01366 *q='\0'; 01367 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression, 01368 &beta,exception); 01369 i=(ssize_t) (alpha+0.5); 01370 p++; 01371 } 01372 if (*p == '.') 01373 p++; 01374 } 01375 if ((isalpha((int) *(p+1)) == 0) && (*p == 'p')) 01376 { 01377 p++; 01378 if (*p == '{') 01379 { 01380 level++; 01381 q=subexpression; 01382 for (p++; *p != '\0'; ) 01383 { 01384 if (*p == '{') 01385 level++; 01386 else 01387 if (*p == '}') 01388 { 01389 level--; 01390 if (level == 0) 01391 break; 01392 } 01393 *q++=(*p++); 01394 } 01395 *q='\0'; 01396 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression, 01397 &beta,exception); 01398 point.x=alpha; 01399 point.y=beta; 01400 p++; 01401 } 01402 else 01403 if (*p == '[') 01404 { 01405 level++; 01406 q=subexpression; 01407 for (p++; *p != '\0'; ) 01408 { 01409 if (*p == '[') 01410 level++; 01411 else 01412 if (*p == ']') 01413 { 01414 level--; 01415 if (level == 0) 01416 break; 01417 } 01418 *q++=(*p++); 01419 } 01420 *q='\0'; 01421 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression, 01422 &beta,exception); 01423 point.x+=alpha; 01424 point.y+=beta; 01425 p++; 01426 } 01427 if (*p == '.') 01428 p++; 01429 } 01430 } 01431 length=GetImageListLength(fx_info->images); 01432 while (i < 0) 01433 i+=(ssize_t) length; 01434 i%=length; 01435 image=GetImageFromList(fx_info->images,i); 01436 if (image == (Image *) NULL) 01437 { 01438 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 01439 "NoSuchImage","`%s'",expression); 01440 return(0.0); 01441 } 01442 GetPixelInfo(image,&pixel); 01443 (void) InterpolatePixelInfo(image,fx_info->view[i],image->interpolate, 01444 point.x,point.y,&pixel,exception); 01445 if ((strlen(p) > 2) && (LocaleCompare(p,"intensity") != 0) && 01446 (LocaleCompare(p,"luminance") != 0) && (LocaleCompare(p,"hue") != 0) && 01447 (LocaleCompare(p,"saturation") != 0) && 01448 (LocaleCompare(p,"lightness") != 0)) 01449 { 01450 char 01451 name[MaxTextExtent]; 01452 01453 (void) CopyMagickString(name,p,MaxTextExtent); 01454 for (q=name+(strlen(name)-1); q > name; q--) 01455 { 01456 if (*q == ')') 01457 break; 01458 if (*q == '.') 01459 { 01460 *q='\0'; 01461 break; 01462 } 01463 } 01464 if ((strlen(name) > 2) && 01465 (GetValueFromSplayTree(fx_info->symbols,name) == (const char *) NULL)) 01466 { 01467 PixelInfo 01468 *color; 01469 01470 color=(PixelInfo *) GetValueFromSplayTree(fx_info->colors,name); 01471 if (color != (PixelInfo *) NULL) 01472 { 01473 pixel=(*color); 01474 p+=strlen(name); 01475 } 01476 else 01477 { 01478 MagickBooleanType 01479 status; 01480 01481 status=QueryColorCompliance(name,AllCompliance,&pixel, 01482 fx_info->exception); 01483 if (status != MagickFalse) 01484 { 01485 (void) AddValueToSplayTree(fx_info->colors,ConstantString( 01486 name),ClonePixelInfo(&pixel)); 01487 p+=strlen(name); 01488 } 01489 } 01490 } 01491 } 01492 (void) CopyMagickString(symbol,p,MaxTextExtent); 01493 StripString(symbol); 01494 if (*symbol == '\0') 01495 { 01496 switch (channel) 01497 { 01498 case RedPixelChannel: return(QuantumScale*pixel.red); 01499 case GreenPixelChannel: return(QuantumScale*pixel.green); 01500 case BluePixelChannel: return(QuantumScale*pixel.blue); 01501 case BlackPixelChannel: 01502 { 01503 if (image->colorspace != CMYKColorspace) 01504 { 01505 (void) ThrowMagickException(exception,GetMagickModule(), 01506 ImageError,"ColorSeparatedImageRequired","`%s'", 01507 image->filename); 01508 return(0.0); 01509 } 01510 return(QuantumScale*pixel.black); 01511 } 01512 case AlphaPixelChannel: 01513 { 01514 MagickRealType 01515 alpha; 01516 01517 if (pixel.matte == MagickFalse) 01518 return(1.0); 01519 alpha=(MagickRealType) (QuantumScale*pixel.alpha); 01520 return(alpha); 01521 } 01522 case IndexPixelChannel: 01523 return(0.0); 01524 case IntensityPixelChannel: 01525 { 01526 return(QuantumScale*GetPixelInfoIntensity(&pixel)); 01527 } 01528 default: 01529 break; 01530 } 01531 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 01532 "UnableToParseExpression","`%s'",p); 01533 return(0.0); 01534 } 01535 switch (*symbol) 01536 { 01537 case 'A': 01538 case 'a': 01539 { 01540 if (LocaleCompare(symbol,"a") == 0) 01541 return((MagickRealType) (QuantumScale*pixel.alpha)); 01542 break; 01543 } 01544 case 'B': 01545 case 'b': 01546 { 01547 if (LocaleCompare(symbol,"b") == 0) 01548 return(QuantumScale*pixel.blue); 01549 break; 01550 } 01551 case 'C': 01552 case 'c': 01553 { 01554 if (LocaleNCompare(symbol,"channel",7) == 0) 01555 { 01556 GeometryInfo 01557 channel_info; 01558 01559 MagickStatusType 01560 flags; 01561 01562 flags=ParseGeometry(symbol+7,&channel_info); 01563 if (image->colorspace == CMYKColorspace) 01564 switch (channel) 01565 { 01566 case CyanPixelChannel: 01567 { 01568 if ((flags & RhoValue) == 0) 01569 return(0.0); 01570 return(channel_info.rho); 01571 } 01572 case MagentaPixelChannel: 01573 { 01574 if ((flags & SigmaValue) == 0) 01575 return(0.0); 01576 return(channel_info.sigma); 01577 } 01578 case YellowPixelChannel: 01579 { 01580 if ((flags & XiValue) == 0) 01581 return(0.0); 01582 return(channel_info.xi); 01583 } 01584 case BlackPixelChannel: 01585 { 01586 if ((flags & PsiValue) == 0) 01587 return(0.0); 01588 return(channel_info.psi); 01589 } 01590 case AlphaPixelChannel: 01591 { 01592 if ((flags & ChiValue) == 0) 01593 return(0.0); 01594 return(channel_info.chi); 01595 } 01596 default: 01597 return(0.0); 01598 } 01599 switch (channel) 01600 { 01601 case RedPixelChannel: 01602 { 01603 if ((flags & RhoValue) == 0) 01604 return(0.0); 01605 return(channel_info.rho); 01606 } 01607 case GreenPixelChannel: 01608 { 01609 if ((flags & SigmaValue) == 0) 01610 return(0.0); 01611 return(channel_info.sigma); 01612 } 01613 case BluePixelChannel: 01614 { 01615 if ((flags & XiValue) == 0) 01616 return(0.0); 01617 return(channel_info.xi); 01618 } 01619 case BlackPixelChannel: 01620 { 01621 if ((flags & ChiValue) == 0) 01622 return(0.0); 01623 return(channel_info.chi); 01624 } 01625 case AlphaPixelChannel: 01626 { 01627 if ((flags & PsiValue) == 0) 01628 return(0.0); 01629 return(channel_info.psi); 01630 } 01631 default: 01632 return(0.0); 01633 } 01634 return(0.0); 01635 } 01636 if (LocaleCompare(symbol,"c") == 0) 01637 return(QuantumScale*pixel.red); 01638 break; 01639 } 01640 case 'D': 01641 case 'd': 01642 { 01643 if (LocaleNCompare(symbol,"depth",5) == 0) 01644 return(FxChannelStatistics(fx_info,image,channel,symbol,exception)); 01645 break; 01646 } 01647 case 'G': 01648 case 'g': 01649 { 01650 if (LocaleCompare(symbol,"g") == 0) 01651 return(QuantumScale*pixel.green); 01652 break; 01653 } 01654 case 'K': 01655 case 'k': 01656 { 01657 if (LocaleNCompare(symbol,"kurtosis",8) == 0) 01658 return(FxChannelStatistics(fx_info,image,channel,symbol,exception)); 01659 if (LocaleCompare(symbol,"k") == 0) 01660 { 01661 if (image->colorspace != CMYKColorspace) 01662 { 01663 (void) ThrowMagickException(exception,GetMagickModule(), 01664 OptionError,"ColorSeparatedImageRequired","`%s'", 01665 image->filename); 01666 return(0.0); 01667 } 01668 return(QuantumScale*pixel.black); 01669 } 01670 break; 01671 } 01672 case 'H': 01673 case 'h': 01674 { 01675 if (LocaleCompare(symbol,"h") == 0) 01676 return((MagickRealType) image->rows); 01677 if (LocaleCompare(symbol,"hue") == 0) 01678 { 01679 double 01680 hue, 01681 lightness, 01682 saturation; 01683 01684 ConvertRGBToHSL(pixel.red,pixel.green,pixel.blue,&hue,&saturation, 01685 &lightness); 01686 return(hue); 01687 } 01688 break; 01689 } 01690 case 'I': 01691 case 'i': 01692 { 01693 if ((LocaleCompare(symbol,"image.depth") == 0) || 01694 (LocaleCompare(symbol,"image.minima") == 0) || 01695 (LocaleCompare(symbol,"image.maxima") == 0) || 01696 (LocaleCompare(symbol,"image.mean") == 0) || 01697 (LocaleCompare(symbol,"image.kurtosis") == 0) || 01698 (LocaleCompare(symbol,"image.skewness") == 0) || 01699 (LocaleCompare(symbol,"image.standard_deviation") == 0)) 01700 return(FxChannelStatistics(fx_info,image,channel,symbol+6,exception)); 01701 if (LocaleCompare(symbol,"image.resolution.x") == 0) 01702 return(image->resolution.x); 01703 if (LocaleCompare(symbol,"image.resolution.y") == 0) 01704 return(image->resolution.y); 01705 if (LocaleCompare(symbol,"intensity") == 0) 01706 return(QuantumScale*GetPixelInfoIntensity(&pixel)); 01707 if (LocaleCompare(symbol,"i") == 0) 01708 return((MagickRealType) x); 01709 break; 01710 } 01711 case 'J': 01712 case 'j': 01713 { 01714 if (LocaleCompare(symbol,"j") == 0) 01715 return((MagickRealType) y); 01716 break; 01717 } 01718 case 'L': 01719 case 'l': 01720 { 01721 if (LocaleCompare(symbol,"lightness") == 0) 01722 { 01723 double 01724 hue, 01725 lightness, 01726 saturation; 01727 01728 ConvertRGBToHSL(pixel.red,pixel.green,pixel.blue,&hue,&saturation, 01729 &lightness); 01730 return(lightness); 01731 } 01732 if (LocaleCompare(symbol,"luminance") == 0) 01733 { 01734 double 01735 luminence; 01736 01737 luminence=0.2126*pixel.red+0.7152*pixel.green+0.0722*pixel.blue; 01738 return(QuantumScale*luminence); 01739 } 01740 break; 01741 } 01742 case 'M': 01743 case 'm': 01744 { 01745 if (LocaleNCompare(symbol,"maxima",6) == 0) 01746 return(FxChannelStatistics(fx_info,image,channel,symbol,exception)); 01747 if (LocaleNCompare(symbol,"mean",4) == 0) 01748 return(FxChannelStatistics(fx_info,image,channel,symbol,exception)); 01749 if (LocaleNCompare(symbol,"minima",6) == 0) 01750 return(FxChannelStatistics(fx_info,image,channel,symbol,exception)); 01751 if (LocaleCompare(symbol,"m") == 0) 01752 return(QuantumScale*pixel.blue); 01753 break; 01754 } 01755 case 'N': 01756 case 'n': 01757 { 01758 if (LocaleCompare(symbol,"n") == 0) 01759 return((MagickRealType) GetImageListLength(fx_info->images)); 01760 break; 01761 } 01762 case 'O': 01763 case 'o': 01764 { 01765 if (LocaleCompare(symbol,"o") == 0) 01766 return(QuantumScale*pixel.alpha); 01767 break; 01768 } 01769 case 'P': 01770 case 'p': 01771 { 01772 if (LocaleCompare(symbol,"page.height") == 0) 01773 return((MagickRealType) image->page.height); 01774 if (LocaleCompare(symbol,"page.width") == 0) 01775 return((MagickRealType) image->page.width); 01776 if (LocaleCompare(symbol,"page.x") == 0) 01777 return((MagickRealType) image->page.x); 01778 if (LocaleCompare(symbol,"page.y") == 0) 01779 return((MagickRealType) image->page.y); 01780 break; 01781 } 01782 case 'R': 01783 case 'r': 01784 { 01785 if (LocaleCompare(symbol,"resolution.x") == 0) 01786 return(image->resolution.x); 01787 if (LocaleCompare(symbol,"resolution.y") == 0) 01788 return(image->resolution.y); 01789 if (LocaleCompare(symbol,"r") == 0) 01790 return(QuantumScale*pixel.red); 01791 break; 01792 } 01793 case 'S': 01794 case 's': 01795 { 01796 if (LocaleCompare(symbol,"saturation") == 0) 01797 { 01798 double 01799 hue, 01800 lightness, 01801 saturation; 01802 01803 ConvertRGBToHSL(pixel.red,pixel.green,pixel.blue,&hue,&saturation, 01804 &lightness); 01805 return(saturation); 01806 } 01807 if (LocaleNCompare(symbol,"skewness",8) == 0) 01808 return(FxChannelStatistics(fx_info,image,channel,symbol,exception)); 01809 if (LocaleNCompare(symbol,"standard_deviation",18) == 0) 01810 return(FxChannelStatistics(fx_info,image,channel,symbol,exception)); 01811 break; 01812 } 01813 case 'T': 01814 case 't': 01815 { 01816 if (LocaleCompare(symbol,"t") == 0) 01817 return((MagickRealType) GetImageIndexInList(fx_info->images)); 01818 break; 01819 } 01820 case 'W': 01821 case 'w': 01822 { 01823 if (LocaleCompare(symbol,"w") == 0) 01824 return((MagickRealType) image->columns); 01825 break; 01826 } 01827 case 'Y': 01828 case 'y': 01829 { 01830 if (LocaleCompare(symbol,"y") == 0) 01831 return(QuantumScale*pixel.green); 01832 break; 01833 } 01834 case 'Z': 01835 case 'z': 01836 { 01837 if (LocaleCompare(symbol,"z") == 0) 01838 { 01839 MagickRealType 01840 depth; 01841 01842 depth=(MagickRealType) GetImageDepth(image,fx_info->exception); 01843 return(depth); 01844 } 01845 break; 01846 } 01847 default: 01848 break; 01849 } 01850 value=(const char *) GetValueFromSplayTree(fx_info->symbols,symbol); 01851 if (value != (const char *) NULL) 01852 return((MagickRealType) StringToDouble(value,(char **) NULL)); 01853 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 01854 "UnableToParseExpression","`%s'",symbol); 01855 return(0.0); 01856 } 01857 01858 static const char *FxOperatorPrecedence(const char *expression, 01859 ExceptionInfo *exception) 01860 { 01861 typedef enum 01862 { 01863 UndefinedPrecedence, 01864 NullPrecedence, 01865 BitwiseComplementPrecedence, 01866 ExponentPrecedence, 01867 ExponentialNotationPrecedence, 01868 MultiplyPrecedence, 01869 AdditionPrecedence, 01870 ShiftPrecedence, 01871 RelationalPrecedence, 01872 EquivalencyPrecedence, 01873 BitwiseAndPrecedence, 01874 BitwiseOrPrecedence, 01875 LogicalAndPrecedence, 01876 LogicalOrPrecedence, 01877 TernaryPrecedence, 01878 AssignmentPrecedence, 01879 CommaPrecedence, 01880 SeparatorPrecedence 01881 } FxPrecedence; 01882 01883 FxPrecedence 01884 precedence, 01885 target; 01886 01887 register const char 01888 *subexpression; 01889 01890 register int 01891 c; 01892 01893 size_t 01894 level; 01895 01896 c=0; 01897 level=0; 01898 subexpression=(const char *) NULL; 01899 target=NullPrecedence; 01900 while (*expression != '\0') 01901 { 01902 precedence=UndefinedPrecedence; 01903 if ((isspace((int) ((char) *expression)) != 0) || (c == (int) '@')) 01904 { 01905 expression++; 01906 continue; 01907 } 01908 switch (*expression) 01909 { 01910 case 'A': 01911 case 'a': 01912 { 01913 #if defined(MAGICKCORE_HAVE_ACOSH) 01914 if (LocaleNCompare(expression,"acosh",5) == 0) 01915 { 01916 expression+=5; 01917 break; 01918 } 01919 #endif 01920 #if defined(MAGICKCORE_HAVE_ASINH) 01921 if (LocaleNCompare(expression,"asinh",5) == 0) 01922 { 01923 expression+=5; 01924 break; 01925 } 01926 #endif 01927 #if defined(MAGICKCORE_HAVE_ATANH) 01928 if (LocaleNCompare(expression,"atanh",5) == 0) 01929 { 01930 expression+=5; 01931 break; 01932 } 01933 #endif 01934 break; 01935 } 01936 case 'E': 01937 case 'e': 01938 { 01939 if ((LocaleNCompare(expression,"E+",2) == 0) || 01940 (LocaleNCompare(expression,"E-",2) == 0)) 01941 { 01942 expression+=2; /* scientific notation */ 01943 break; 01944 } 01945 } 01946 case 'J': 01947 case 'j': 01948 { 01949 if ((LocaleNCompare(expression,"j0",2) == 0) || 01950 (LocaleNCompare(expression,"j1",2) == 0)) 01951 { 01952 expression+=2; 01953 break; 01954 } 01955 break; 01956 } 01957 case '#': 01958 { 01959 while (isxdigit((int) ((unsigned char) *(expression+1))) != 0) 01960 expression++; 01961 break; 01962 } 01963 default: 01964 break; 01965 } 01966 if ((c == (int) '{') || (c == (int) '[')) 01967 level++; 01968 else 01969 if ((c == (int) '}') || (c == (int) ']')) 01970 level--; 01971 if (level == 0) 01972 switch ((unsigned char) *expression) 01973 { 01974 case '~': 01975 case '!': 01976 { 01977 precedence=BitwiseComplementPrecedence; 01978 break; 01979 } 01980 case '^': 01981 case '@': 01982 { 01983 precedence=ExponentPrecedence; 01984 break; 01985 } 01986 default: 01987 { 01988 if (((c != 0) && ((isdigit((int) ((char) c)) != 0) || 01989 (strchr(")",c) != (char *) NULL))) && 01990 (((islower((int) ((char) *expression)) != 0) || 01991 (strchr("(",(int) *expression) != (char *) NULL)) || 01992 ((isdigit((int) ((char) c)) == 0) && 01993 (isdigit((int) ((char) *expression)) != 0))) && 01994 (strchr("xy",(int) *expression) == (char *) NULL)) 01995 precedence=MultiplyPrecedence; 01996 break; 01997 } 01998 case '*': 01999 case '/': 02000 case '%': 02001 { 02002 precedence=MultiplyPrecedence; 02003 break; 02004 } 02005 case '+': 02006 case '-': 02007 { 02008 if ((strchr("(+-/*%:&^|<>~,",c) == (char *) NULL) || 02009 (isalpha(c) != 0)) 02010 precedence=AdditionPrecedence; 02011 break; 02012 } 02013 case LeftShiftOperator: 02014 case RightShiftOperator: 02015 { 02016 precedence=ShiftPrecedence; 02017 break; 02018 } 02019 case '<': 02020 case LessThanEqualOperator: 02021 case GreaterThanEqualOperator: 02022 case '>': 02023 { 02024 precedence=RelationalPrecedence; 02025 break; 02026 } 02027 case EqualOperator: 02028 case NotEqualOperator: 02029 { 02030 precedence=EquivalencyPrecedence; 02031 break; 02032 } 02033 case '&': 02034 { 02035 precedence=BitwiseAndPrecedence; 02036 break; 02037 } 02038 case '|': 02039 { 02040 precedence=BitwiseOrPrecedence; 02041 break; 02042 } 02043 case LogicalAndOperator: 02044 { 02045 precedence=LogicalAndPrecedence; 02046 break; 02047 } 02048 case LogicalOrOperator: 02049 { 02050 precedence=LogicalOrPrecedence; 02051 break; 02052 } 02053 case ExponentialNotation: 02054 { 02055 precedence=ExponentialNotationPrecedence; 02056 break; 02057 } 02058 case ':': 02059 case '?': 02060 { 02061 precedence=TernaryPrecedence; 02062 break; 02063 } 02064 case '=': 02065 { 02066 precedence=AssignmentPrecedence; 02067 break; 02068 } 02069 case ',': 02070 { 02071 precedence=CommaPrecedence; 02072 break; 02073 } 02074 case ';': 02075 { 02076 precedence=SeparatorPrecedence; 02077 break; 02078 } 02079 } 02080 if ((precedence == BitwiseComplementPrecedence) || 02081 (precedence == TernaryPrecedence) || 02082 (precedence == AssignmentPrecedence)) 02083 { 02084 if (precedence > target) 02085 { 02086 /* 02087 Right-to-left associativity. 02088 */ 02089 target=precedence; 02090 subexpression=expression; 02091 } 02092 } 02093 else 02094 if (precedence >= target) 02095 { 02096 /* 02097 Left-to-right associativity. 02098 */ 02099 target=precedence; 02100 subexpression=expression; 02101 } 02102 if (strchr("(",(int) *expression) != (char *) NULL) 02103 expression=FxSubexpression(expression,exception); 02104 c=(int) (*expression++); 02105 } 02106 return(subexpression); 02107 } 02108 02109 static MagickRealType FxEvaluateSubexpression(FxInfo *fx_info, 02110 const PixelChannel channel,const ssize_t x,const ssize_t y, 02111 const char *expression,MagickRealType *beta,ExceptionInfo *exception) 02112 { 02113 char 02114 *q, 02115 subexpression[MaxTextExtent]; 02116 02117 MagickRealType 02118 alpha, 02119 gamma; 02120 02121 register const char 02122 *p; 02123 02124 *beta=0.0; 02125 if (exception->severity != UndefinedException) 02126 return(0.0); 02127 while (isspace((int) *expression) != 0) 02128 expression++; 02129 if (*expression == '\0') 02130 { 02131 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 02132 "MissingExpression","`%s'",expression); 02133 return(0.0); 02134 } 02135 *subexpression='\0'; 02136 p=FxOperatorPrecedence(expression,exception); 02137 if (p != (const char *) NULL) 02138 { 02139 (void) CopyMagickString(subexpression,expression,(size_t) 02140 (p-expression+1)); 02141 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,beta, 02142 exception); 02143 switch ((unsigned char) *p) 02144 { 02145 case '~': 02146 { 02147 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02148 *beta=(MagickRealType) (~(size_t) *beta); 02149 return(*beta); 02150 } 02151 case '!': 02152 { 02153 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02154 return(*beta == 0.0 ? 1.0 : 0.0); 02155 } 02156 case '^': 02157 { 02158 *beta=pow((double) alpha,(double) FxEvaluateSubexpression(fx_info, 02159 channel,x,y,++p,beta,exception)); 02160 return(*beta); 02161 } 02162 case '*': 02163 case ExponentialNotation: 02164 { 02165 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02166 return(alpha*(*beta)); 02167 } 02168 case '/': 02169 { 02170 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02171 if (*beta == 0.0) 02172 { 02173 if (exception->severity == UndefinedException) 02174 (void) ThrowMagickException(exception,GetMagickModule(), 02175 OptionError,"DivideByZero","`%s'",expression); 02176 return(0.0); 02177 } 02178 return(alpha/(*beta)); 02179 } 02180 case '%': 02181 { 02182 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02183 *beta=fabs(floor(((double) *beta)+0.5)); 02184 if (*beta == 0.0) 02185 { 02186 (void) ThrowMagickException(exception,GetMagickModule(), 02187 OptionError,"DivideByZero","`%s'",expression); 02188 return(0.0); 02189 } 02190 return(fmod((double) alpha,(double) *beta)); 02191 } 02192 case '+': 02193 { 02194 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02195 return(alpha+(*beta)); 02196 } 02197 case '-': 02198 { 02199 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02200 return(alpha-(*beta)); 02201 } 02202 case LeftShiftOperator: 02203 { 02204 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02205 *beta=(MagickRealType) ((size_t) (alpha+0.5) << (size_t) (gamma+0.5)); 02206 return(*beta); 02207 } 02208 case RightShiftOperator: 02209 { 02210 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02211 *beta=(MagickRealType) ((size_t) (alpha+0.5) >> (size_t) (gamma+0.5)); 02212 return(*beta); 02213 } 02214 case '<': 02215 { 02216 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02217 return(alpha < *beta ? 1.0 : 0.0); 02218 } 02219 case LessThanEqualOperator: 02220 { 02221 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02222 return(alpha <= *beta ? 1.0 : 0.0); 02223 } 02224 case '>': 02225 { 02226 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02227 return(alpha > *beta ? 1.0 : 0.0); 02228 } 02229 case GreaterThanEqualOperator: 02230 { 02231 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02232 return(alpha >= *beta ? 1.0 : 0.0); 02233 } 02234 case EqualOperator: 02235 { 02236 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02237 return(fabs(alpha-(*beta)) <= MagickEpsilon ? 1.0 : 0.0); 02238 } 02239 case NotEqualOperator: 02240 { 02241 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02242 return(fabs(alpha-(*beta)) > MagickEpsilon ? 1.0 : 0.0); 02243 } 02244 case '&': 02245 { 02246 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02247 *beta=(MagickRealType) ((size_t) (alpha+0.5) & (size_t) (gamma+0.5)); 02248 return(*beta); 02249 } 02250 case '|': 02251 { 02252 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02253 *beta=(MagickRealType) ((size_t) (alpha+0.5) | (size_t) (gamma+0.5)); 02254 return(*beta); 02255 } 02256 case LogicalAndOperator: 02257 { 02258 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02259 *beta=(alpha > 0.0) && (gamma > 0.0) ? 1.0 : 0.0; 02260 return(*beta); 02261 } 02262 case LogicalOrOperator: 02263 { 02264 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02265 *beta=(alpha > 0.0) || (gamma > 0.0) ? 1.0 : 0.0; 02266 return(*beta); 02267 } 02268 case '?': 02269 { 02270 MagickRealType 02271 gamma; 02272 02273 (void) CopyMagickString(subexpression,++p,MaxTextExtent); 02274 q=subexpression; 02275 p=StringToken(":",&q); 02276 if (q == (char *) NULL) 02277 { 02278 (void) ThrowMagickException(exception,GetMagickModule(), 02279 OptionError,"UnableToParseExpression","`%s'",subexpression); 02280 return(0.0); 02281 } 02282 if (fabs((double) alpha) > MagickEpsilon) 02283 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,beta,exception); 02284 else 02285 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,q,beta,exception); 02286 return(gamma); 02287 } 02288 case '=': 02289 { 02290 char 02291 numeric[MaxTextExtent]; 02292 02293 q=subexpression; 02294 while (isalpha((int) ((unsigned char) *q)) != 0) 02295 q++; 02296 if (*q != '\0') 02297 { 02298 (void) ThrowMagickException(exception,GetMagickModule(), 02299 OptionError,"UnableToParseExpression","`%s'",subexpression); 02300 return(0.0); 02301 } 02302 ClearMagickException(exception); 02303 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02304 (void) FormatLocaleString(numeric,MaxTextExtent,"%g",(double) 02305 *beta); 02306 (void) DeleteNodeFromSplayTree(fx_info->symbols,subexpression); 02307 (void) AddValueToSplayTree(fx_info->symbols,ConstantString( 02308 subexpression),ConstantString(numeric)); 02309 return(*beta); 02310 } 02311 case ',': 02312 { 02313 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02314 return(alpha); 02315 } 02316 case ';': 02317 { 02318 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception); 02319 return(*beta); 02320 } 02321 default: 02322 { 02323 gamma=alpha*FxEvaluateSubexpression(fx_info,channel,x,y,p,beta, 02324 exception); 02325 return(gamma); 02326 } 02327 } 02328 } 02329 if (strchr("(",(int) *expression) != (char *) NULL) 02330 { 02331 (void) CopyMagickString(subexpression,expression+1,MaxTextExtent); 02332 subexpression[strlen(subexpression)-1]='\0'; 02333 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,beta, 02334 exception); 02335 return(gamma); 02336 } 02337 switch (*expression) 02338 { 02339 case '+': 02340 { 02341 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta, 02342 exception); 02343 return(1.0*gamma); 02344 } 02345 case '-': 02346 { 02347 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta, 02348 exception); 02349 return(-1.0*gamma); 02350 } 02351 case '~': 02352 { 02353 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta, 02354 exception); 02355 return((MagickRealType) (~(size_t) (gamma+0.5))); 02356 } 02357 case 'A': 02358 case 'a': 02359 { 02360 if (LocaleNCompare(expression,"abs",3) == 0) 02361 { 02362 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta, 02363 exception); 02364 return((MagickRealType) fabs((double) alpha)); 02365 } 02366 #if defined(MAGICKCORE_HAVE_ACOSH) 02367 if (LocaleNCompare(expression,"acosh",5) == 0) 02368 { 02369 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta, 02370 exception); 02371 return((MagickRealType) acosh((double) alpha)); 02372 } 02373 #endif 02374 if (LocaleNCompare(expression,"acos",4) == 0) 02375 { 02376 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta, 02377 exception); 02378 return((MagickRealType) acos((double) alpha)); 02379 } 02380 #if defined(MAGICKCORE_HAVE_J1) 02381 if (LocaleNCompare(expression,"airy",4) == 0) 02382 { 02383 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta, 02384 exception); 02385 if (alpha == 0.0) 02386 return(1.0); 02387 gamma=2.0*j1((double) (MagickPI*alpha))/(MagickPI*alpha); 02388 return(gamma*gamma); 02389 } 02390 #endif 02391 #if defined(MAGICKCORE_HAVE_ASINH) 02392 if (LocaleNCompare(expression,"asinh",5) == 0) 02393 { 02394 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta, 02395 exception); 02396 return((MagickRealType) asinh((double) alpha)); 02397 } 02398 #endif 02399 if (LocaleNCompare(expression,"asin",4) == 0) 02400 { 02401 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta, 02402 exception); 02403 return((MagickRealType) asin((double) alpha)); 02404 } 02405 if (LocaleNCompare(expression,"alt",3) == 0) 02406 { 02407 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta, 02408 exception); 02409 return(((ssize_t) alpha) & 0x01 ? -1.0 : 1.0); 02410 } 02411 if (LocaleNCompare(expression,"atan2",5) == 0) 02412 { 02413 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta, 02414 exception); 02415 return((MagickRealType) atan2((double) alpha,(double) *beta)); 02416 } 02417 #if defined(MAGICKCORE_HAVE_ATANH) 02418 if (LocaleNCompare(expression,"atanh",5) == 0) 02419 { 02420 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta, 02421 exception); 02422 return((MagickRealType) atanh((double) alpha)); 02423 } 02424 #endif 02425 if (LocaleNCompare(expression,"atan",4) == 0) 02426 { 02427 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta, 02428 exception); 02429 return((MagickRealType) atan((double) alpha)); 02430 } 02431 if (LocaleCompare(expression,"a") == 0) 02432 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02433 break; 02434 } 02435 case 'B': 02436 case 'b': 02437 { 02438 if (LocaleCompare(expression,"b") == 0) 02439 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02440 break; 02441 } 02442 case 'C': 02443 case 'c': 02444 { 02445 if (LocaleNCompare(expression,"ceil",4) == 0) 02446 { 02447 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta, 02448 exception); 02449 return((MagickRealType) ceil((double) alpha)); 02450 } 02451 if (LocaleNCompare(expression,"cosh",4) == 0) 02452 { 02453 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta, 02454 exception); 02455 return((MagickRealType) cosh((double) alpha)); 02456 } 02457 if (LocaleNCompare(expression,"cos",3) == 0) 02458 { 02459 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta, 02460 exception); 02461 return((MagickRealType) cos((double) alpha)); 02462 } 02463 if (LocaleCompare(expression,"c") == 0) 02464 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02465 break; 02466 } 02467 case 'D': 02468 case 'd': 02469 { 02470 if (LocaleNCompare(expression,"debug",5) == 0) 02471 { 02472 const char 02473 *type; 02474 02475 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta, 02476 exception); 02477 if (fx_info->images->colorspace == CMYKColorspace) 02478 switch (channel) 02479 { 02480 case CyanPixelChannel: type="cyan"; break; 02481 case MagentaPixelChannel: type="magenta"; break; 02482 case YellowPixelChannel: type="yellow"; break; 02483 case AlphaPixelChannel: type="opacity"; break; 02484 case BlackPixelChannel: type="black"; break; 02485 default: type="unknown"; break; 02486 } 02487 else 02488 switch (channel) 02489 { 02490 case RedPixelChannel: type="red"; break; 02491 case GreenPixelChannel: type="green"; break; 02492 case BluePixelChannel: type="blue"; break; 02493 case AlphaPixelChannel: type="opacity"; break; 02494 default: type="unknown"; break; 02495 } 02496 (void) CopyMagickString(subexpression,expression+6,MaxTextExtent); 02497 if (strlen(subexpression) > 1) 02498 subexpression[strlen(subexpression)-1]='\0'; 02499 if (fx_info->file != (FILE *) NULL) 02500 (void) FormatLocaleFile(fx_info->file,"%s[%.20g,%.20g].%s: " 02501 "%s=%.*g\n",fx_info->images->filename,(double) x,(double) y,type, 02502 subexpression,GetMagickPrecision(),(double) alpha); 02503 return(0.0); 02504 } 02505 if (LocaleNCompare(expression,"drc",3) == 0) 02506 { 02507 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta, 02508 exception); 02509 return((MagickRealType) (alpha/(*beta*(alpha-1.0)+1.0))); 02510 } 02511 break; 02512 } 02513 case 'E': 02514 case 'e': 02515 { 02516 if (LocaleCompare(expression,"epsilon") == 0) 02517 return((MagickRealType) MagickEpsilon); 02518 if (LocaleNCompare(expression,"exp",3) == 0) 02519 { 02520 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta, 02521 exception); 02522 return((MagickRealType) exp((double) alpha)); 02523 } 02524 if (LocaleCompare(expression,"e") == 0) 02525 return((MagickRealType) 2.7182818284590452354); 02526 break; 02527 } 02528 case 'F': 02529 case 'f': 02530 { 02531 if (LocaleNCompare(expression,"floor",5) == 0) 02532 { 02533 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta, 02534 exception); 02535 return((MagickRealType) floor((double) alpha)); 02536 } 02537 break; 02538 } 02539 case 'G': 02540 case 'g': 02541 { 02542 if (LocaleNCompare(expression,"gauss",5) == 0) 02543 { 02544 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta, 02545 exception); 02546 gamma=exp((double) (-alpha*alpha/2.0))/sqrt(2.0*MagickPI); 02547 return((MagickRealType) gamma); 02548 } 02549 if (LocaleNCompare(expression,"gcd",3) == 0) 02550 { 02551 MagickOffsetType 02552 gcd; 02553 02554 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta, 02555 exception); 02556 gcd=FxGCD((MagickOffsetType) (alpha+0.5),(MagickOffsetType) (*beta+ 02557 0.5)); 02558 return((MagickRealType) gcd); 02559 } 02560 if (LocaleCompare(expression,"g") == 0) 02561 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02562 break; 02563 } 02564 case 'H': 02565 case 'h': 02566 { 02567 if (LocaleCompare(expression,"h") == 0) 02568 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02569 if (LocaleCompare(expression,"hue") == 0) 02570 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02571 if (LocaleNCompare(expression,"hypot",5) == 0) 02572 { 02573 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta, 02574 exception); 02575 return((MagickRealType) hypot((double) alpha,(double) *beta)); 02576 } 02577 break; 02578 } 02579 case 'K': 02580 case 'k': 02581 { 02582 if (LocaleCompare(expression,"k") == 0) 02583 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02584 break; 02585 } 02586 case 'I': 02587 case 'i': 02588 { 02589 if (LocaleCompare(expression,"intensity") == 0) 02590 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02591 if (LocaleNCompare(expression,"int",3) == 0) 02592 { 02593 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta, 02594 exception); 02595 return((MagickRealType) floor(alpha)); 02596 } 02597 #if defined(MAGICKCORE_HAVE_ISNAN) 02598 if (LocaleNCompare(expression,"isnan",5) == 0) 02599 { 02600 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta, 02601 exception); 02602 return((MagickRealType) !!isnan((double) alpha)); 02603 } 02604 #endif 02605 if (LocaleCompare(expression,"i") == 0) 02606 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02607 break; 02608 } 02609 case 'J': 02610 case 'j': 02611 { 02612 if (LocaleCompare(expression,"j") == 0) 02613 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02614 #if defined(MAGICKCORE_HAVE_J0) 02615 if (LocaleNCompare(expression,"j0",2) == 0) 02616 { 02617 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta, 02618 exception); 02619 return((MagickRealType) j0((double) alpha)); 02620 } 02621 #endif 02622 #if defined(MAGICKCORE_HAVE_J1) 02623 if (LocaleNCompare(expression,"j1",2) == 0) 02624 { 02625 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta, 02626 exception); 02627 return((MagickRealType) j1((double) alpha)); 02628 } 02629 #endif 02630 #if defined(MAGICKCORE_HAVE_J1) 02631 if (LocaleNCompare(expression,"jinc",4) == 0) 02632 { 02633 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta, 02634 exception); 02635 if (alpha == 0.0) 02636 return(1.0); 02637 gamma=(MagickRealType) (2.0*j1((double) (MagickPI*alpha))/(MagickPI* 02638 alpha)); 02639 return(gamma); 02640 } 02641 #endif 02642 break; 02643 } 02644 case 'L': 02645 case 'l': 02646 { 02647 if (LocaleNCompare(expression,"ln",2) == 0) 02648 { 02649 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta, 02650 exception); 02651 return((MagickRealType) log((double) alpha)); 02652 } 02653 if (LocaleNCompare(expression,"logtwo",6) == 0) 02654 { 02655 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,beta, 02656 exception); 02657 return((MagickRealType) log10((double) alpha))/log10(2.0); 02658 } 02659 if (LocaleNCompare(expression,"log",3) == 0) 02660 { 02661 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta, 02662 exception); 02663 return((MagickRealType) log10((double) alpha)); 02664 } 02665 if (LocaleCompare(expression,"lightness") == 0) 02666 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02667 break; 02668 } 02669 case 'M': 02670 case 'm': 02671 { 02672 if (LocaleCompare(expression,"MaxRGB") == 0) 02673 return((MagickRealType) QuantumRange); 02674 if (LocaleNCompare(expression,"maxima",6) == 0) 02675 break; 02676 if (LocaleNCompare(expression,"max",3) == 0) 02677 { 02678 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta, 02679 exception); 02680 return(alpha > *beta ? alpha : *beta); 02681 } 02682 if (LocaleNCompare(expression,"minima",6) == 0) 02683 break; 02684 if (LocaleNCompare(expression,"min",3) == 0) 02685 { 02686 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta, 02687 exception); 02688 return(alpha < *beta ? alpha : *beta); 02689 } 02690 if (LocaleNCompare(expression,"mod",3) == 0) 02691 { 02692 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta, 02693 exception); 02694 gamma=alpha-floor((double) (alpha/(*beta)))*(*beta); 02695 return(gamma); 02696 } 02697 if (LocaleCompare(expression,"m") == 0) 02698 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02699 break; 02700 } 02701 case 'N': 02702 case 'n': 02703 { 02704 if (LocaleNCompare(expression,"not",3) == 0) 02705 { 02706 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta, 02707 exception); 02708 return((MagickRealType) (alpha < MagickEpsilon)); 02709 } 02710 if (LocaleCompare(expression,"n") == 0) 02711 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02712 break; 02713 } 02714 case 'O': 02715 case 'o': 02716 { 02717 if (LocaleCompare(expression,"Opaque") == 0) 02718 return(1.0); 02719 if (LocaleCompare(expression,"o") == 0) 02720 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02721 break; 02722 } 02723 case 'P': 02724 case 'p': 02725 { 02726 if (LocaleCompare(expression,"phi") == 0) 02727 return((MagickRealType) MagickPHI); 02728 if (LocaleCompare(expression,"pi") == 0) 02729 return((MagickRealType) MagickPI); 02730 if (LocaleNCompare(expression,"pow",3) == 0) 02731 { 02732 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta, 02733 exception); 02734 return((MagickRealType) pow((double) alpha,(double) *beta)); 02735 } 02736 if (LocaleCompare(expression,"p") == 0) 02737 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02738 break; 02739 } 02740 case 'Q': 02741 case 'q': 02742 { 02743 if (LocaleCompare(expression,"QuantumRange") == 0) 02744 return((MagickRealType) QuantumRange); 02745 if (LocaleCompare(expression,"QuantumScale") == 0) 02746 return((MagickRealType) QuantumScale); 02747 break; 02748 } 02749 case 'R': 02750 case 'r': 02751 { 02752 if (LocaleNCompare(expression,"rand",4) == 0) 02753 return((MagickRealType) GetPseudoRandomValue(fx_info->random_info)); 02754 if (LocaleNCompare(expression,"round",5) == 0) 02755 { 02756 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta, 02757 exception); 02758 return((MagickRealType) floor((double) alpha+0.5)); 02759 } 02760 if (LocaleCompare(expression,"r") == 0) 02761 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02762 break; 02763 } 02764 case 'S': 02765 case 's': 02766 { 02767 if (LocaleCompare(expression,"saturation") == 0) 02768 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02769 if (LocaleNCompare(expression,"sign",4) == 0) 02770 { 02771 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta, 02772 exception); 02773 return(alpha < 0.0 ? -1.0 : 1.0); 02774 } 02775 if (LocaleNCompare(expression,"sinc",4) == 0) 02776 { 02777 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta, 02778 exception); 02779 if (alpha == 0) 02780 return(1.0); 02781 gamma=(MagickRealType) (sin((double) (MagickPI*alpha))/ 02782 (MagickPI*alpha)); 02783 return(gamma); 02784 } 02785 if (LocaleNCompare(expression,"sinh",4) == 0) 02786 { 02787 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta, 02788 exception); 02789 return((MagickRealType) sinh((double) alpha)); 02790 } 02791 if (LocaleNCompare(expression,"sin",3) == 0) 02792 { 02793 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta, 02794 exception); 02795 return((MagickRealType) sin((double) alpha)); 02796 } 02797 if (LocaleNCompare(expression,"sqrt",4) == 0) 02798 { 02799 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta, 02800 exception); 02801 return((MagickRealType) sqrt((double) alpha)); 02802 } 02803 if (LocaleNCompare(expression,"squish",6) == 0) 02804 { 02805 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,beta, 02806 exception); 02807 return((MagickRealType) (1.0/(1.0+exp((double) (4.0*alpha))))); 02808 } 02809 if (LocaleCompare(expression,"s") == 0) 02810 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02811 break; 02812 } 02813 case 'T': 02814 case 't': 02815 { 02816 if (LocaleNCompare(expression,"tanh",4) == 0) 02817 { 02818 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta, 02819 exception); 02820 return((MagickRealType) tanh((double) alpha)); 02821 } 02822 if (LocaleNCompare(expression,"tan",3) == 0) 02823 { 02824 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta, 02825 exception); 02826 return((MagickRealType) tan((double) alpha)); 02827 } 02828 if (LocaleCompare(expression,"Transparent") == 0) 02829 return(0.0); 02830 if (LocaleNCompare(expression,"trunc",5) == 0) 02831 { 02832 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta, 02833 exception); 02834 if (alpha >= 0.0) 02835 return((MagickRealType) floor((double) alpha)); 02836 return((MagickRealType) ceil((double) alpha)); 02837 } 02838 if (LocaleCompare(expression,"t") == 0) 02839 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02840 break; 02841 } 02842 case 'U': 02843 case 'u': 02844 { 02845 if (LocaleCompare(expression,"u") == 0) 02846 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02847 break; 02848 } 02849 case 'V': 02850 case 'v': 02851 { 02852 if (LocaleCompare(expression,"v") == 0) 02853 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02854 break; 02855 } 02856 case 'W': 02857 case 'w': 02858 { 02859 if (LocaleNCompare(expression,"while",5) == 0) 02860 { 02861 do 02862 { 02863 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta, 02864 exception); 02865 } while (fabs((double) alpha) >= MagickEpsilon); 02866 return((MagickRealType) *beta); 02867 } 02868 if (LocaleCompare(expression,"w") == 0) 02869 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02870 break; 02871 } 02872 case 'Y': 02873 case 'y': 02874 { 02875 if (LocaleCompare(expression,"y") == 0) 02876 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02877 break; 02878 } 02879 case 'Z': 02880 case 'z': 02881 { 02882 if (LocaleCompare(expression,"z") == 0) 02883 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02884 break; 02885 } 02886 default: 02887 break; 02888 } 02889 q=(char *) expression; 02890 alpha=InterpretSiPrefixValue(expression,&q); 02891 if (q == expression) 02892 return(FxGetSymbol(fx_info,channel,x,y,expression,exception)); 02893 return(alpha); 02894 } 02895 02896 MagickPrivate MagickBooleanType FxEvaluateExpression(FxInfo *fx_info, 02897 MagickRealType *alpha,ExceptionInfo *exception) 02898 { 02899 MagickBooleanType 02900 status; 02901 02902 status=FxEvaluateChannelExpression(fx_info,GrayPixelChannel,0,0,alpha, 02903 exception); 02904 return(status); 02905 } 02906 02907 MagickExport MagickBooleanType FxPreprocessExpression(FxInfo *fx_info, 02908 MagickRealType *alpha,ExceptionInfo *exception) 02909 { 02910 FILE 02911 *file; 02912 02913 MagickBooleanType 02914 status; 02915 02916 file=fx_info->file; 02917 fx_info->file=(FILE *) NULL; 02918 status=FxEvaluateChannelExpression(fx_info,GrayPixelChannel,0,0,alpha, 02919 exception); 02920 fx_info->file=file; 02921 return(status); 02922 } 02923 02924 MagickPrivate MagickBooleanType FxEvaluateChannelExpression(FxInfo *fx_info, 02925 const PixelChannel channel,const ssize_t x,const ssize_t y, 02926 MagickRealType *alpha,ExceptionInfo *exception) 02927 { 02928 MagickRealType 02929 beta; 02930 02931 beta=0.0; 02932 *alpha=FxEvaluateSubexpression(fx_info,channel,x,y,fx_info->expression,&beta, 02933 exception); 02934 return(exception->severity == OptionError ? MagickFalse : MagickTrue); 02935 } 02936 02937 /* 02938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02939 % % 02940 % % 02941 % % 02942 % F x I m a g e % 02943 % % 02944 % % 02945 % % 02946 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02947 % 02948 % FxImage() applies a mathematical expression to the specified image. 02949 % 02950 % The format of the FxImage method is: 02951 % 02952 % Image *FxImage(const Image *image,const char *expression, 02953 % ExceptionInfo *exception) 02954 % 02955 % A description of each parameter follows: 02956 % 02957 % o image: the image. 02958 % 02959 % o expression: A mathematical expression. 02960 % 02961 % o exception: return any errors or warnings in this structure. 02962 % 02963 */ 02964 02965 static FxInfo **DestroyFxThreadSet(FxInfo **fx_info) 02966 { 02967 register ssize_t 02968 i; 02969 02970 assert(fx_info != (FxInfo **) NULL); 02971 for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++) 02972 if (fx_info[i] != (FxInfo *) NULL) 02973 fx_info[i]=DestroyFxInfo(fx_info[i]); 02974 fx_info=(FxInfo **) RelinquishMagickMemory(fx_info); 02975 return(fx_info); 02976 } 02977 02978 static FxInfo **AcquireFxThreadSet(const Image *image,const char *expression, 02979 ExceptionInfo *exception) 02980 { 02981 char 02982 *fx_expression; 02983 02984 FxInfo 02985 **fx_info; 02986 02987 MagickRealType 02988 alpha; 02989 02990 register ssize_t 02991 i; 02992 02993 size_t 02994 number_threads; 02995 02996 number_threads=GetOpenMPMaximumThreads(); 02997 fx_info=(FxInfo **) AcquireQuantumMemory(number_threads,sizeof(*fx_info)); 02998 if (fx_info == (FxInfo **) NULL) 02999 return((FxInfo **) NULL); 03000 (void) ResetMagickMemory(fx_info,0,number_threads*sizeof(*fx_info)); 03001 if (*expression != '@') 03002 fx_expression=ConstantString(expression); 03003 else 03004 fx_expression=FileToString(expression+1,~0,exception); 03005 for (i=0; i < (ssize_t) number_threads; i++) 03006 { 03007 fx_info[i]=AcquireFxInfo(image,fx_expression); 03008 if (fx_info[i] == (FxInfo *) NULL) 03009 return(DestroyFxThreadSet(fx_info)); 03010 (void) FxPreprocessExpression(fx_info[i],&alpha,fx_info[i]->exception); 03011 } 03012 fx_expression=DestroyString(fx_expression); 03013 return(fx_info); 03014 } 03015 03016 MagickExport Image *FxImage(const Image *image,const char *expression, 03017 ExceptionInfo *exception) 03018 { 03019 #define FxImageTag "Fx/Image" 03020 03021 CacheView 03022 *fx_view, 03023 *image_view; 03024 03025 FxInfo 03026 **restrict fx_info; 03027 03028 Image 03029 *fx_image; 03030 03031 MagickBooleanType 03032 status; 03033 03034 MagickOffsetType 03035 progress; 03036 03037 MagickRealType 03038 alpha; 03039 03040 ssize_t 03041 y; 03042 03043 assert(image != (Image *) NULL); 03044 assert(image->signature == MagickSignature); 03045 if (image->debug != MagickFalse) 03046 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 03047 fx_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception); 03048 if (fx_image == (Image *) NULL) 03049 return((Image *) NULL); 03050 if (SetImageStorageClass(fx_image,DirectClass,exception) == MagickFalse) 03051 { 03052 fx_image=DestroyImage(fx_image); 03053 return((Image *) NULL); 03054 } 03055 fx_info=AcquireFxThreadSet(image,expression,exception); 03056 if (fx_info == (FxInfo **) NULL) 03057 { 03058 fx_image=DestroyImage(fx_image); 03059 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed"); 03060 } 03061 status=FxPreprocessExpression(fx_info[0],&alpha,exception); 03062 if (status == MagickFalse) 03063 { 03064 fx_image=DestroyImage(fx_image); 03065 fx_info=DestroyFxThreadSet(fx_info); 03066 return((Image *) NULL); 03067 } 03068 /* 03069 Fx image. 03070 */ 03071 status=MagickTrue; 03072 progress=0; 03073 image_view=AcquireCacheView(image); 03074 fx_view=AcquireCacheView(fx_image); 03075 #if defined(MAGICKCORE_OPENMP_SUPPORT) 03076 #pragma omp parallel for schedule(static,4) shared(progress,status) 03077 #endif 03078 for (y=0; y < (ssize_t) fx_image->rows; y++) 03079 { 03080 const int 03081 id = GetOpenMPThreadId(); 03082 03083 register const Quantum 03084 *restrict p; 03085 03086 register Quantum 03087 *restrict q; 03088 03089 register ssize_t 03090 x; 03091 03092 if (status == MagickFalse) 03093 continue; 03094 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 03095 q=QueueCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception); 03096 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 03097 { 03098 status=MagickFalse; 03099 continue; 03100 } 03101 for (x=0; x < (ssize_t) fx_image->columns; x++) 03102 { 03103 register ssize_t 03104 i; 03105 03106 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 03107 { 03108 MagickRealType 03109 alpha; 03110 03111 PixelChannel 03112 channel; 03113 03114 PixelTrait 03115 fx_traits, 03116 traits; 03117 03118 channel=GetPixelChannelMapChannel(image,i); 03119 traits=GetPixelChannelMapTraits(image,channel); 03120 fx_traits=GetPixelChannelMapTraits(fx_image,channel); 03121 if ((traits == UndefinedPixelTrait) || 03122 (fx_traits == UndefinedPixelTrait)) 03123 continue; 03124 if (((fx_traits & CopyPixelTrait) != 0) || 03125 (GetPixelMask(image,p) != 0)) 03126 { 03127 SetPixelChannel(fx_image,channel,p[i],q); 03128 continue; 03129 } 03130 alpha=0.0; 03131 (void) FxEvaluateChannelExpression(fx_info[id],channel,x,y,&alpha, 03132 exception); 03133 q[i]=ClampToQuantum((MagickRealType) QuantumRange*alpha); 03134 } 03135 p+=GetPixelChannels(image); 03136 q+=GetPixelChannels(fx_image); 03137 } 03138 if (SyncCacheViewAuthenticPixels(fx_view,exception) == MagickFalse) 03139 status=MagickFalse; 03140 if (image->progress_monitor != (MagickProgressMonitor) NULL) 03141 { 03142 MagickBooleanType 03143 proceed; 03144 03145 #if defined(MAGICKCORE_OPENMP_SUPPORT) 03146 #pragma omp critical (MagickCore_FxImage) 03147 #endif 03148 proceed=SetImageProgress(image,FxImageTag,progress++,image->rows); 03149 if (proceed == MagickFalse) 03150 status=MagickFalse; 03151 } 03152 } 03153 fx_view=DestroyCacheView(fx_view); 03154 image_view=DestroyCacheView(image_view); 03155 fx_info=DestroyFxThreadSet(fx_info); 03156 if (status == MagickFalse) 03157 fx_image=DestroyImage(fx_image); 03158 return(fx_image); 03159 } 03160 03161 /* 03162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03163 % % 03164 % % 03165 % % 03166 % I m p l o d e I m a g e % 03167 % % 03168 % % 03169 % % 03170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03171 % 03172 % ImplodeImage() creates a new image that is a copy of an existing 03173 % one with the image pixels "implode" by the specified percentage. It 03174 % allocates the memory necessary for the new Image structure and returns a 03175 % pointer to the new image. 03176 % 03177 % The format of the ImplodeImage method is: 03178 % 03179 % Image *ImplodeImage(const Image *image,const double amount, 03180 % const PixelInterpolateMethod method,ExceptionInfo *exception) 03181 % 03182 % A description of each parameter follows: 03183 % 03184 % o implode_image: Method ImplodeImage returns a pointer to the image 03185 % after it is implode. A null image is returned if there is a memory 03186 % shortage. 03187 % 03188 % o image: the image. 03189 % 03190 % o amount: Define the extent of the implosion. 03191 % 03192 % o method: the pixel interpolation method. 03193 % 03194 % o exception: return any errors or warnings in this structure. 03195 % 03196 */ 03197 MagickExport Image *ImplodeImage(const Image *image,const double amount, 03198 const PixelInterpolateMethod method,ExceptionInfo *exception) 03199 { 03200 #define ImplodeImageTag "Implode/Image" 03201 03202 CacheView 03203 *image_view, 03204 *implode_view; 03205 03206 Image 03207 *implode_image; 03208 03209 MagickBooleanType 03210 status; 03211 03212 MagickOffsetType 03213 progress; 03214 03215 MagickRealType 03216 radius; 03217 03218 PointInfo 03219 center, 03220 scale; 03221 03222 ssize_t 03223 y; 03224 03225 /* 03226 Initialize implode image attributes. 03227 */ 03228 assert(image != (Image *) NULL); 03229 assert(image->signature == MagickSignature); 03230 if (image->debug != MagickFalse) 03231 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 03232 assert(exception != (ExceptionInfo *) NULL); 03233 assert(exception->signature == MagickSignature); 03234 implode_image=CloneImage(image,image->columns,image->rows,MagickTrue, 03235 exception); 03236 if (implode_image == (Image *) NULL) 03237 return((Image *) NULL); 03238 if (SetImageStorageClass(implode_image,DirectClass,exception) == MagickFalse) 03239 { 03240 implode_image=DestroyImage(implode_image); 03241 return((Image *) NULL); 03242 } 03243 if (implode_image->background_color.alpha != OpaqueAlpha) 03244 implode_image->matte=MagickTrue; 03245 /* 03246 Compute scaling factor. 03247 */ 03248 scale.x=1.0; 03249 scale.y=1.0; 03250 center.x=0.5*image->columns; 03251 center.y=0.5*image->rows; 03252 radius=center.x; 03253 if (image->columns > image->rows) 03254 scale.y=(double) image->columns/(double) image->rows; 03255 else 03256 if (image->columns < image->rows) 03257 { 03258 scale.x=(double) image->rows/(double) image->columns; 03259 radius=center.y; 03260 } 03261 /* 03262 Implode image. 03263 */ 03264 status=MagickTrue; 03265 progress=0; 03266 image_view=AcquireCacheView(image); 03267 implode_view=AcquireCacheView(implode_image); 03268 #if defined(MAGICKCORE_OPENMP_SUPPORT) 03269 #pragma omp parallel for schedule(static,4) shared(progress,status) 03270 #endif 03271 for (y=0; y < (ssize_t) image->rows; y++) 03272 { 03273 MagickRealType 03274 distance; 03275 03276 PointInfo 03277 delta; 03278 03279 register const Quantum 03280 *restrict p; 03281 03282 register ssize_t 03283 x; 03284 03285 register Quantum 03286 *restrict q; 03287 03288 if (status == MagickFalse) 03289 continue; 03290 p=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); 03291 q=QueueCacheViewAuthenticPixels(implode_view,0,y,implode_image->columns,1, 03292 exception); 03293 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 03294 { 03295 status=MagickFalse; 03296 continue; 03297 } 03298 delta.y=scale.y*(double) (y-center.y); 03299 for (x=0; x < (ssize_t) image->columns; x++) 03300 { 03301 register ssize_t 03302 i; 03303 03304 /* 03305 Determine if the pixel is within an ellipse. 03306 */ 03307 if (GetPixelMask(image,p) != 0) 03308 { 03309 p+=GetPixelChannels(image); 03310 q+=GetPixelChannels(implode_image); 03311 continue; 03312 } 03313 delta.x=scale.x*(double) (x-center.x); 03314 distance=delta.x*delta.x+delta.y*delta.y; 03315 if (distance >= (radius*radius)) 03316 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 03317 { 03318 PixelChannel 03319 channel; 03320 03321 PixelTrait 03322 implode_traits, 03323 traits; 03324 03325 channel=GetPixelChannelMapChannel(image,i); 03326 traits=GetPixelChannelMapTraits(image,channel); 03327 implode_traits=GetPixelChannelMapTraits(implode_image,channel); 03328 if ((traits == UndefinedPixelTrait) || 03329 (implode_traits == UndefinedPixelTrait)) 03330 continue; 03331 SetPixelChannel(implode_image,channel,p[i],q); 03332 } 03333 else 03334 { 03335 double 03336 factor; 03337 03338 /* 03339 Implode the pixel. 03340 */ 03341 factor=1.0; 03342 if (distance > 0.0) 03343 factor=pow(sin((double) (MagickPI*sqrt((double) distance)/radius/ 03344 2)),-amount); 03345 status=InterpolatePixelChannels(image,image_view,implode_image,method, 03346 (double) (factor*delta.x/scale.x+center.x),(double) (factor*delta.y/ 03347 scale.y+center.y),q,exception); 03348 } 03349 p+=GetPixelChannels(image); 03350 q+=GetPixelChannels(implode_image); 03351 } 03352 if (SyncCacheViewAuthenticPixels(implode_view,exception) == MagickFalse) 03353 status=MagickFalse; 03354 if (image->progress_monitor != (MagickProgressMonitor) NULL) 03355 { 03356 MagickBooleanType 03357 proceed; 03358 03359 #if defined(MAGICKCORE_OPENMP_SUPPORT) 03360 #pragma omp critical (MagickCore_ImplodeImage) 03361 #endif 03362 proceed=SetImageProgress(image,ImplodeImageTag,progress++,image->rows); 03363 if (proceed == MagickFalse) 03364 status=MagickFalse; 03365 } 03366 } 03367 implode_view=DestroyCacheView(implode_view); 03368 image_view=DestroyCacheView(image_view); 03369 if (status == MagickFalse) 03370 implode_image=DestroyImage(implode_image); 03371 return(implode_image); 03372 } 03373 03374 /* 03375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03376 % % 03377 % % 03378 % % 03379 % M o r p h I m a g e s % 03380 % % 03381 % % 03382 % % 03383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03384 % 03385 % The MorphImages() method requires a minimum of two images. The first 03386 % image is transformed into the second by a number of intervening images 03387 % as specified by frames. 03388 % 03389 % The format of the MorphImage method is: 03390 % 03391 % Image *MorphImages(const Image *image,const size_t number_frames, 03392 % ExceptionInfo *exception) 03393 % 03394 % A description of each parameter follows: 03395 % 03396 % o image: the image. 03397 % 03398 % o number_frames: Define the number of in-between image to generate. 03399 % The more in-between frames, the smoother the morph. 03400 % 03401 % o exception: return any errors or warnings in this structure. 03402 % 03403 */ 03404 MagickExport Image *MorphImages(const Image *image, 03405 const size_t number_frames,ExceptionInfo *exception) 03406 { 03407 #define MorphImageTag "Morph/Image" 03408 03409 Image 03410 *morph_image, 03411 *morph_images; 03412 03413 MagickBooleanType 03414 status; 03415 03416 MagickOffsetType 03417 scene; 03418 03419 MagickRealType 03420 alpha, 03421 beta; 03422 03423 register const Image 03424 *next; 03425 03426 register ssize_t 03427 i; 03428 03429 ssize_t 03430 y; 03431 03432 /* 03433 Clone first frame in sequence. 03434 */ 03435 assert(image != (Image *) NULL); 03436 assert(image->signature == MagickSignature); 03437 if (image->debug != MagickFalse) 03438 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 03439 assert(exception != (ExceptionInfo *) NULL); 03440 assert(exception->signature == MagickSignature); 03441 morph_images=CloneImage(image,0,0,MagickTrue,exception); 03442 if (morph_images == (Image *) NULL) 03443 return((Image *) NULL); 03444 if (GetNextImageInList(image) == (Image *) NULL) 03445 { 03446 /* 03447 Morph single image. 03448 */ 03449 for (i=1; i < (ssize_t) number_frames; i++) 03450 { 03451 morph_image=CloneImage(image,0,0,MagickTrue,exception); 03452 if (morph_image == (Image *) NULL) 03453 { 03454 morph_images=DestroyImageList(morph_images); 03455 return((Image *) NULL); 03456 } 03457 AppendImageToList(&morph_images,morph_image); 03458 if (image->progress_monitor != (MagickProgressMonitor) NULL) 03459 { 03460 MagickBooleanType 03461 proceed; 03462 03463 proceed=SetImageProgress(image,MorphImageTag,(MagickOffsetType) i, 03464 number_frames); 03465 if (proceed == MagickFalse) 03466 status=MagickFalse; 03467 } 03468 } 03469 return(GetFirstImageInList(morph_images)); 03470 } 03471 /* 03472 Morph image sequence. 03473 */ 03474 status=MagickTrue; 03475 scene=0; 03476 next=image; 03477 for ( ; GetNextImageInList(next) != (Image *) NULL; next=GetNextImageInList(next)) 03478 { 03479 for (i=0; i < (ssize_t) number_frames; i++) 03480 { 03481 CacheView 03482 *image_view, 03483 *morph_view; 03484 03485 beta=(MagickRealType) (i+1.0)/(MagickRealType) (number_frames+1.0); 03486 alpha=1.0-beta; 03487 morph_image=ResizeImage(next,(size_t) (alpha*next->columns+beta* 03488 GetNextImageInList(next)->columns+0.5),(size_t) (alpha* 03489 next->rows+beta*GetNextImageInList(next)->rows+0.5), 03490 next->filter,next->blur,exception); 03491 if (morph_image == (Image *) NULL) 03492 { 03493 morph_images=DestroyImageList(morph_images); 03494 return((Image *) NULL); 03495 } 03496 status=SetImageStorageClass(morph_image,DirectClass,exception); 03497 if (status == MagickFalse) 03498 { 03499 morph_image=DestroyImage(morph_image); 03500 return((Image *) NULL); 03501 } 03502 AppendImageToList(&morph_images,morph_image); 03503 morph_images=GetLastImageInList(morph_images); 03504 morph_image=ResizeImage(GetNextImageInList(next),morph_images->columns, 03505 morph_images->rows,GetNextImageInList(next)->filter, 03506 GetNextImageInList(next)->blur,exception); 03507 if (morph_image == (Image *) NULL) 03508 { 03509 morph_images=DestroyImageList(morph_images); 03510 return((Image *) NULL); 03511 } 03512 image_view=AcquireCacheView(morph_image); 03513 morph_view=AcquireCacheView(morph_images); 03514 #if defined(MAGICKCORE_OPENMP_SUPPORT) 03515 #pragma omp parallel for schedule(static,4) shared(status) 03516 #endif 03517 for (y=0; y < (ssize_t) morph_images->rows; y++) 03518 { 03519 MagickBooleanType 03520 sync; 03521 03522 register const Quantum 03523 *restrict p; 03524 03525 register ssize_t 03526 x; 03527 03528 register Quantum 03529 *restrict q; 03530 03531 if (status == MagickFalse) 03532 continue; 03533 p=GetCacheViewVirtualPixels(image_view,0,y,morph_image->columns,1, 03534 exception); 03535 q=GetCacheViewAuthenticPixels(morph_view,0,y,morph_images->columns,1, 03536 exception); 03537 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 03538 { 03539 status=MagickFalse; 03540 continue; 03541 } 03542 for (x=0; x < (ssize_t) morph_images->columns; x++) 03543 { 03544 register ssize_t 03545 i; 03546 03547 for (i=0; i < (ssize_t) GetPixelChannels(morph_image); i++) 03548 { 03549 PixelChannel 03550 channel; 03551 03552 PixelTrait 03553 morph_traits, 03554 traits; 03555 03556 channel=GetPixelChannelMapChannel(image,i); 03557 traits=GetPixelChannelMapTraits(image,channel); 03558 morph_traits=GetPixelChannelMapTraits(morph_image,channel); 03559 if ((traits == UndefinedPixelTrait) || 03560 (morph_traits == UndefinedPixelTrait)) 03561 continue; 03562 if (((morph_traits & CopyPixelTrait) != 0) || 03563 (GetPixelMask(image,p) != 0)) 03564 { 03565 SetPixelChannel(morph_image,channel,p[i],q); 03566 continue; 03567 } 03568 SetPixelChannel(morph_image,channel,ClampToQuantum(alpha* 03569 GetPixelChannel(morph_images,channel,q)+beta*p[i]),q); 03570 } 03571 p+=GetPixelChannels(morph_image); 03572 q+=GetPixelChannels(morph_images); 03573 } 03574 sync=SyncCacheViewAuthenticPixels(morph_view,exception); 03575 if (sync == MagickFalse) 03576 status=MagickFalse; 03577 } 03578 morph_view=DestroyCacheView(morph_view); 03579 image_view=DestroyCacheView(image_view); 03580 morph_image=DestroyImage(morph_image); 03581 } 03582 if (i < (ssize_t) number_frames) 03583 break; 03584 /* 03585 Clone last frame in sequence. 03586 */ 03587 morph_image=CloneImage(GetNextImageInList(next),0,0,MagickTrue,exception); 03588 if (morph_image == (Image *) NULL) 03589 { 03590 morph_images=DestroyImageList(morph_images); 03591 return((Image *) NULL); 03592 } 03593 AppendImageToList(&morph_images,morph_image); 03594 morph_images=GetLastImageInList(morph_images); 03595 if (image->progress_monitor != (MagickProgressMonitor) NULL) 03596 { 03597 MagickBooleanType 03598 proceed; 03599 03600 #if defined(MAGICKCORE_OPENMP_SUPPORT) 03601 #pragma omp critical (MagickCore_MorphImages) 03602 #endif 03603 proceed=SetImageProgress(image,MorphImageTag,scene, 03604 GetImageListLength(image)); 03605 if (proceed == MagickFalse) 03606 status=MagickFalse; 03607 } 03608 scene++; 03609 } 03610 if (GetNextImageInList(next) != (Image *) NULL) 03611 { 03612 morph_images=DestroyImageList(morph_images); 03613 return((Image *) NULL); 03614 } 03615 return(GetFirstImageInList(morph_images)); 03616 } 03617 03618 /* 03619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03620 % % 03621 % % 03622 % % 03623 % P l a s m a I m a g e % 03624 % % 03625 % % 03626 % % 03627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03628 % 03629 % PlasmaImage() initializes an image with plasma fractal values. The image 03630 % must be initialized with a base color and the random number generator 03631 % seeded before this method is called. 03632 % 03633 % The format of the PlasmaImage method is: 03634 % 03635 % MagickBooleanType PlasmaImage(Image *image,const SegmentInfo *segment, 03636 % size_t attenuate,size_t depth,ExceptionInfo *exception) 03637 % 03638 % A description of each parameter follows: 03639 % 03640 % o image: the image. 03641 % 03642 % o segment: Define the region to apply plasma fractals values. 03643 % 03644 % o attenuate: Define the plasma attenuation factor. 03645 % 03646 % o depth: Limit the plasma recursion depth. 03647 % 03648 % o exception: return any errors or warnings in this structure. 03649 % 03650 */ 03651 03652 static inline Quantum PlasmaPixel(RandomInfo *random_info, 03653 const MagickRealType pixel,const MagickRealType noise) 03654 { 03655 Quantum 03656 plasma; 03657 03658 plasma=ClampToQuantum(pixel+noise*GetPseudoRandomValue(random_info)- 03659 noise/2.0); 03660 return(plasma); 03661 } 03662 03663 static MagickBooleanType PlasmaImageProxy(Image *image,CacheView *image_view, 03664 CacheView *u_view,CacheView *v_view,RandomInfo *random_info, 03665 const SegmentInfo *segment,size_t attenuate,size_t depth, 03666 ExceptionInfo *exception) 03667 { 03668 MagickRealType 03669 plasma; 03670 03671 PixelChannel 03672 channel; 03673 03674 PixelTrait 03675 traits; 03676 03677 register const Quantum 03678 *restrict u, 03679 *restrict v; 03680 03681 register Quantum 03682 *restrict q; 03683 03684 register ssize_t 03685 i; 03686 03687 ssize_t 03688 x, 03689 x_mid, 03690 y, 03691 y_mid; 03692 03693 if (((segment->x2-segment->x1) == 0.0) && ((segment->y2-segment->y1) == 0.0)) 03694 return(MagickTrue); 03695 if (depth != 0) 03696 { 03697 SegmentInfo 03698 local_info; 03699 03700 /* 03701 Divide the area into quadrants and recurse. 03702 */ 03703 depth--; 03704 attenuate++; 03705 x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5); 03706 y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5); 03707 local_info=(*segment); 03708 local_info.x2=(double) x_mid; 03709 local_info.y2=(double) y_mid; 03710 (void) PlasmaImageProxy(image,image_view,u_view,v_view,random_info, 03711 &local_info,attenuate,depth,exception); 03712 local_info=(*segment); 03713 local_info.y1=(double) y_mid; 03714 local_info.x2=(double) x_mid; 03715 (void) PlasmaImageProxy(image,image_view,u_view,v_view,random_info, 03716 &local_info,attenuate,depth,exception); 03717 local_info=(*segment); 03718 local_info.x1=(double) x_mid; 03719 local_info.y2=(double) y_mid; 03720 (void) PlasmaImageProxy(image,image_view,u_view,v_view,random_info, 03721 &local_info,attenuate,depth,exception); 03722 local_info=(*segment); 03723 local_info.x1=(double) x_mid; 03724 local_info.y1=(double) y_mid; 03725 return(PlasmaImageProxy(image,image_view,u_view,v_view,random_info, 03726 &local_info,attenuate,depth,exception)); 03727 } 03728 x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5); 03729 y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5); 03730 if ((segment->x1 == (double) x_mid) && (segment->x2 == (double) x_mid) && 03731 (segment->y1 == (double) y_mid) && (segment->y2 == (double) y_mid)) 03732 return(MagickFalse); 03733 /* 03734 Average pixels and apply plasma. 03735 */ 03736 plasma=(MagickRealType) QuantumRange/(2.0*attenuate); 03737 if ((segment->x1 != (double) x_mid) || (segment->x2 != (double) x_mid)) 03738 { 03739 /* 03740 Left pixel. 03741 */ 03742 x=(ssize_t) ceil(segment->x1-0.5); 03743 u=GetCacheViewVirtualPixels(u_view,x,(ssize_t) ceil(segment->y1-0.5),1,1, 03744 exception); 03745 v=GetCacheViewVirtualPixels(v_view,x,(ssize_t) ceil(segment->y2-0.5),1,1, 03746 exception); 03747 q=QueueCacheViewAuthenticPixels(image_view,x,y_mid,1,1,exception); 03748 if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) || 03749 (q == (Quantum *) NULL)) 03750 return(MagickTrue); 03751 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 03752 { 03753 channel=GetPixelChannelMapChannel(image,i); 03754 traits=GetPixelChannelMapTraits(image,channel); 03755 if (traits == UndefinedPixelTrait) 03756 continue; 03757 q[i]=PlasmaPixel(random_info,(u[channel]+v[channel])/2.0,plasma); 03758 } 03759 (void) SyncCacheViewAuthenticPixels(image_view,exception); 03760 if (segment->x1 != segment->x2) 03761 { 03762 /* 03763 Right pixel. 03764 */ 03765 x=(ssize_t) ceil(segment->x2-0.5); 03766 u=GetCacheViewVirtualPixels(u_view,x,(ssize_t) ceil(segment->y1-0.5), 03767 1,1,exception); 03768 v=GetCacheViewVirtualPixels(v_view,x,(ssize_t) ceil(segment->y2-0.5), 03769 1,1,exception); 03770 q=QueueCacheViewAuthenticPixels(image_view,x,y_mid,1,1,exception); 03771 if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) || 03772 (q == (Quantum *) NULL)) 03773 return(MagickTrue); 03774 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 03775 { 03776 channel=GetPixelChannelMapChannel(image,i); 03777 traits=GetPixelChannelMapTraits(image,channel); 03778 if (traits == UndefinedPixelTrait) 03779 continue; 03780 q[i]=PlasmaPixel(random_info,(u[channel]+v[channel])/2.0,plasma); 03781 } 03782 (void) SyncCacheViewAuthenticPixels(image_view,exception); 03783 } 03784 } 03785 if ((segment->y1 != (double) y_mid) || (segment->y2 != (double) y_mid)) 03786 { 03787 if ((segment->x1 != (double) x_mid) || (segment->y2 != (double) y_mid)) 03788 { 03789 /* 03790 Bottom pixel. 03791 */ 03792 y=(ssize_t) ceil(segment->y2-0.5); 03793 u=GetCacheViewVirtualPixels(u_view,(ssize_t) ceil(segment->x1-0.5),y, 03794 1,1,exception); 03795 v=GetCacheViewVirtualPixels(v_view,(ssize_t) ceil(segment->x2-0.5),y, 03796 1,1,exception); 03797 q=QueueCacheViewAuthenticPixels(image_view,x_mid,y,1,1,exception); 03798 if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) || 03799 (q == (Quantum *) NULL)) 03800 return(MagickTrue); 03801 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 03802 { 03803 channel=GetPixelChannelMapChannel(image,i); 03804 traits=GetPixelChannelMapTraits(image,channel); 03805 if (traits == UndefinedPixelTrait) 03806 continue; 03807 q[i]=PlasmaPixel(random_info,(u[channel]+v[channel])/2.0,plasma); 03808 } 03809 (void) SyncCacheViewAuthenticPixels(image_view,exception); 03810 } 03811 if (segment->y1 != segment->y2) 03812 { 03813 /* 03814 Top pixel. 03815 */ 03816 y=(ssize_t) ceil(segment->y1-0.5); 03817 u=GetCacheViewVirtualPixels(u_view,(ssize_t) ceil(segment->x1-0.5),y, 03818 1,1,exception); 03819 v=GetCacheViewVirtualPixels(v_view,(ssize_t) ceil(segment->x2-0.5),y, 03820 1,1,exception); 03821 q=QueueCacheViewAuthenticPixels(image_view,x_mid,y,1,1,exception); 03822 if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) || 03823 (q == (Quantum *) NULL)) 03824 return(MagickTrue); 03825 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 03826 { 03827 channel=GetPixelChannelMapChannel(image,i); 03828 traits=GetPixelChannelMapTraits(image,channel); 03829 if (traits == UndefinedPixelTrait) 03830 continue; 03831 q[i]=PlasmaPixel(random_info,(u[channel]+v[channel])/2.0,plasma); 03832 } 03833 (void) SyncCacheViewAuthenticPixels(image_view,exception); 03834 } 03835 } 03836 if ((segment->x1 != segment->x2) || (segment->y1 != segment->y2)) 03837 { 03838 /* 03839 Middle pixel. 03840 */ 03841 x=(ssize_t) ceil(segment->x1-0.5); 03842 y=(ssize_t) ceil(segment->y1-0.5); 03843 u=GetCacheViewVirtualPixels(u_view,x,y,1,1,exception); 03844 x=(ssize_t) ceil(segment->x2-0.5); 03845 y=(ssize_t) ceil(segment->y2-0.5); 03846 v=GetCacheViewVirtualPixels(v_view,x,y,1,1,exception); 03847 q=QueueCacheViewAuthenticPixels(image_view,x_mid,y_mid,1,1,exception); 03848 if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) || 03849 (q == (Quantum *) NULL)) 03850 return(MagickTrue); 03851 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 03852 { 03853 channel=GetPixelChannelMapChannel(image,i); 03854 traits=GetPixelChannelMapTraits(image,channel); 03855 if (traits == UndefinedPixelTrait) 03856 continue; 03857 q[i]=PlasmaPixel(random_info,(u[channel]+v[channel])/2.0,plasma); 03858 } 03859 (void) SyncCacheViewAuthenticPixels(image_view,exception); 03860 } 03861 if (((segment->x2-segment->x1) < 3.0) && ((segment->y2-segment->y1) < 3.0)) 03862 return(MagickTrue); 03863 return(MagickFalse); 03864 } 03865 03866 MagickExport MagickBooleanType PlasmaImage(Image *image, 03867 const SegmentInfo *segment,size_t attenuate,size_t depth, 03868 ExceptionInfo *exception) 03869 { 03870 CacheView 03871 *image_view, 03872 *u_view, 03873 *v_view; 03874 03875 MagickBooleanType 03876 status; 03877 03878 RandomInfo 03879 *random_info; 03880 03881 if (image->debug != MagickFalse) 03882 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 03883 assert(image != (Image *) NULL); 03884 assert(image->signature == MagickSignature); 03885 if (image->debug != MagickFalse) 03886 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 03887 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 03888 return(MagickFalse); 03889 image_view=AcquireCacheView(image); 03890 u_view=AcquireCacheView(image); 03891 v_view=AcquireCacheView(image); 03892 random_info=AcquireRandomInfo(); 03893 status=PlasmaImageProxy(image,image_view,u_view,v_view,random_info,segment, 03894 attenuate,depth,exception); 03895 random_info=DestroyRandomInfo(random_info); 03896 v_view=DestroyCacheView(v_view); 03897 u_view=DestroyCacheView(u_view); 03898 image_view=DestroyCacheView(image_view); 03899 return(status); 03900 } 03901 03902 /* 03903 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03904 % % 03905 % % 03906 % % 03907 % P o l a r o i d I m a g e % 03908 % % 03909 % % 03910 % % 03911 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03912 % 03913 % PolaroidImage() simulates a Polaroid picture. 03914 % 03915 % The format of the AnnotateImage method is: 03916 % 03917 % Image *PolaroidImage(const Image *image,const DrawInfo *draw_info, 03918 % const char *caption,const double angle, 03919 % const PixelInterpolateMethod method,ExceptionInfo exception) 03920 % 03921 % A description of each parameter follows: 03922 % 03923 % o image: the image. 03924 % 03925 % o draw_info: the draw info. 03926 % 03927 % o caption: the Polaroid caption. 03928 % 03929 % o angle: Apply the effect along this angle. 03930 % 03931 % o method: the pixel interpolation method. 03932 % 03933 % o exception: return any errors or warnings in this structure. 03934 % 03935 */ 03936 MagickExport Image *PolaroidImage(const Image *image,const DrawInfo *draw_info, 03937 const char *caption,const double angle,const PixelInterpolateMethod method, 03938 ExceptionInfo *exception) 03939 { 03940 Image 03941 *bend_image, 03942 *caption_image, 03943 *flop_image, 03944 *picture_image, 03945 *polaroid_image, 03946 *rotate_image, 03947 *trim_image; 03948 03949 size_t 03950 height; 03951 03952 ssize_t 03953 quantum; 03954 03955 /* 03956 Simulate a Polaroid picture. 03957 */ 03958 assert(image != (Image *) NULL); 03959 assert(image->signature == MagickSignature); 03960 if (image->debug != MagickFalse) 03961 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 03962 assert(exception != (ExceptionInfo *) NULL); 03963 assert(exception->signature == MagickSignature); 03964 quantum=(ssize_t) MagickMax(MagickMax((double) image->columns,(double) 03965 image->rows)/25.0,10.0); 03966 height=image->rows+2*quantum; 03967 caption_image=(Image *) NULL; 03968 if (caption != (const char *) NULL) 03969 { 03970 char 03971 geometry[MaxTextExtent], 03972 *text; 03973 03974 DrawInfo 03975 *annotate_info; 03976 03977 MagickBooleanType 03978 status; 03979 03980 ssize_t 03981 count; 03982 03983 TypeMetric 03984 metrics; 03985 03986 /* 03987 Generate caption image. 03988 */ 03989 caption_image=CloneImage(image,image->columns,1,MagickTrue,exception); 03990 if (caption_image == (Image *) NULL) 03991 return((Image *) NULL); 03992 annotate_info=CloneDrawInfo((const ImageInfo *) NULL,draw_info); 03993 text=InterpretImageProperties((ImageInfo *) NULL,(Image *) image,caption, 03994 exception); 03995 (void) CloneString(&annotate_info->text,text); 03996 count=FormatMagickCaption(caption_image,annotate_info,MagickTrue,&metrics, 03997 &text,exception); 03998 status=SetImageExtent(caption_image,image->columns,(size_t) ((count+1)* 03999 (metrics.ascent-metrics.descent)+0.5),exception); 04000 if (status == MagickFalse) 04001 caption_image=DestroyImage(caption_image); 04002 else 04003 { 04004 caption_image->background_color=image->border_color; 04005 (void) SetImageBackgroundColor(caption_image,exception); 04006 (void) CloneString(&annotate_info->text,text); 04007 (void) FormatLocaleString(geometry,MaxTextExtent,"+0+%g", 04008 metrics.ascent); 04009 if (annotate_info->gravity == UndefinedGravity) 04010 (void) CloneString(&annotate_info->geometry,AcquireString( 04011 geometry)); 04012 (void) AnnotateImage(caption_image,annotate_info,exception); 04013 height+=caption_image->rows; 04014 } 04015 annotate_info=DestroyDrawInfo(annotate_info); 04016 text=DestroyString(text); 04017 } 04018 picture_image=CloneImage(image,image->columns+2*quantum,height,MagickTrue, 04019 exception); 04020 if (picture_image == (Image *) NULL) 04021 { 04022 if (caption_image != (Image *) NULL) 04023 caption_image=DestroyImage(caption_image); 04024 return((Image *) NULL); 04025 } 04026 picture_image->background_color=image->border_color; 04027 (void) SetImageBackgroundColor(picture_image,exception); 04028 (void) CompositeImage(picture_image,OverCompositeOp,image,quantum,quantum, 04029 exception); 04030 if (caption_image != (Image *) NULL) 04031 { 04032 (void) CompositeImage(picture_image,OverCompositeOp,caption_image,quantum, 04033 (ssize_t) (image->rows+3*quantum/2),exception); 04034 caption_image=DestroyImage(caption_image); 04035 } 04036 (void) QueryColorCompliance("none",AllCompliance, 04037 &picture_image->background_color,exception); 04038 (void) SetImageAlphaChannel(picture_image,OpaqueAlphaChannel,exception); 04039 rotate_image=RotateImage(picture_image,90.0,exception); 04040 picture_image=DestroyImage(picture_image); 04041 if (rotate_image == (Image *) NULL) 04042 return((Image *) NULL); 04043 picture_image=rotate_image; 04044 bend_image=WaveImage(picture_image,0.01*picture_image->rows,2.0* 04045 picture_image->columns,method,exception); 04046 picture_image=DestroyImage(picture_image); 04047 if (bend_image == (Image *) NULL) 04048 return((Image *) NULL); 04049 picture_image=bend_image; 04050 rotate_image=RotateImage(picture_image,-90.0,exception); 04051 picture_image=DestroyImage(picture_image); 04052 if (rotate_image == (Image *) NULL) 04053 return((Image *) NULL); 04054 picture_image=rotate_image; 04055 picture_image->background_color=image->background_color; 04056 polaroid_image=ShadowImage(picture_image,80.0,2.0,0.0,quantum/3,quantum/3, 04057 exception); 04058 if (polaroid_image == (Image *) NULL) 04059 { 04060 picture_image=DestroyImage(picture_image); 04061 return(picture_image); 04062 } 04063 flop_image=FlopImage(polaroid_image,exception); 04064 polaroid_image=DestroyImage(polaroid_image); 04065 if (flop_image == (Image *) NULL) 04066 { 04067 picture_image=DestroyImage(picture_image); 04068 return(picture_image); 04069 } 04070 polaroid_image=flop_image; 04071 (void) CompositeImage(polaroid_image,OverCompositeOp,picture_image,(ssize_t) 04072 (-0.01*picture_image->columns/2.0),0L,exception); 04073 picture_image=DestroyImage(picture_image); 04074 (void) QueryColorCompliance("none",AllCompliance, 04075 &polaroid_image->background_color,exception); 04076 rotate_image=RotateImage(polaroid_image,angle,exception); 04077 polaroid_image=DestroyImage(polaroid_image); 04078 if (rotate_image == (Image *) NULL) 04079 return((Image *) NULL); 04080 polaroid_image=rotate_image; 04081 trim_image=TrimImage(polaroid_image,exception); 04082 polaroid_image=DestroyImage(polaroid_image); 04083 if (trim_image == (Image *) NULL) 04084 return((Image *) NULL); 04085 polaroid_image=trim_image; 04086 return(polaroid_image); 04087 } 04088 04089 /* 04090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 04091 % % 04092 % % 04093 % % 04094 % S e p i a T o n e I m a g e % 04095 % % 04096 % % 04097 % % 04098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 04099 % 04100 % MagickSepiaToneImage() applies a special effect to the image, similar to the 04101 % effect achieved in a photo darkroom by sepia toning. Threshold ranges from 04102 % 0 to QuantumRange and is a measure of the extent of the sepia toning. A 04103 % threshold of 80% is a good starting point for a reasonable tone. 04104 % 04105 % The format of the SepiaToneImage method is: 04106 % 04107 % Image *SepiaToneImage(const Image *image,const double threshold, 04108 % ExceptionInfo *exception) 04109 % 04110 % A description of each parameter follows: 04111 % 04112 % o image: the image. 04113 % 04114 % o threshold: the tone threshold. 04115 % 04116 % o exception: return any errors or warnings in this structure. 04117 % 04118 */ 04119 MagickExport Image *SepiaToneImage(const Image *image,const double threshold, 04120 ExceptionInfo *exception) 04121 { 04122 #define SepiaToneImageTag "SepiaTone/Image" 04123 04124 CacheView 04125 *image_view, 04126 *sepia_view; 04127 04128 Image 04129 *sepia_image; 04130 04131 MagickBooleanType 04132 status; 04133 04134 MagickOffsetType 04135 progress; 04136 04137 ssize_t 04138 y; 04139 04140 /* 04141 Initialize sepia-toned image attributes. 04142 */ 04143 assert(image != (const Image *) NULL); 04144 assert(image->signature == MagickSignature); 04145 if (image->debug != MagickFalse) 04146 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 04147 assert(exception != (ExceptionInfo *) NULL); 04148 assert(exception->signature == MagickSignature); 04149 sepia_image=CloneImage(image,0,0,MagickTrue,exception); 04150 if (sepia_image == (Image *) NULL) 04151 return((Image *) NULL); 04152 if (SetImageStorageClass(sepia_image,DirectClass,exception) == MagickFalse) 04153 { 04154 sepia_image=DestroyImage(sepia_image); 04155 return((Image *) NULL); 04156 } 04157 /* 04158 Tone each row of the image. 04159 */ 04160 status=MagickTrue; 04161 progress=0; 04162 image_view=AcquireCacheView(image); 04163 sepia_view=AcquireCacheView(sepia_image); 04164 #if defined(MAGICKCORE_OPENMP_SUPPORT) 04165 #pragma omp parallel for schedule(static,4) shared(progress,status) 04166 #endif 04167 for (y=0; y < (ssize_t) image->rows; y++) 04168 { 04169 register const Quantum 04170 *restrict p; 04171 04172 register ssize_t 04173 x; 04174 04175 register Quantum 04176 *restrict q; 04177 04178 if (status == MagickFalse) 04179 continue; 04180 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception); 04181 q=GetCacheViewAuthenticPixels(sepia_view,0,y,sepia_image->columns,1, 04182 exception); 04183 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL)) 04184 { 04185 status=MagickFalse; 04186 continue; 04187 } 04188 for (x=0; x < (ssize_t) image->columns; x++) 04189 { 04190 MagickRealType 04191 intensity, 04192 tone; 04193 04194 intensity=(MagickRealType) GetPixelIntensity(image,p); 04195 tone=intensity > threshold ? (MagickRealType) QuantumRange : intensity+ 04196 (MagickRealType) QuantumRange-threshold; 04197 SetPixelRed(sepia_image,ClampToQuantum(tone),q); 04198 tone=intensity > (7.0*threshold/6.0) ? (MagickRealType) QuantumRange : 04199 intensity+(MagickRealType) QuantumRange-7.0*threshold/6.0; 04200 SetPixelGreen(sepia_image,ClampToQuantum(tone),q); 04201 tone=intensity < (threshold/6.0) ? 0 : intensity-threshold/6.0; 04202 SetPixelBlue(sepia_image,ClampToQuantum(tone),q); 04203 tone=threshold/7.0; 04204 if ((MagickRealType) GetPixelGreen(image,q) < tone) 04205 SetPixelGreen(sepia_image,ClampToQuantum(tone),q); 04206 if ((MagickRealType) GetPixelBlue(image,q) < tone) 04207 SetPixelBlue(sepia_image,ClampToQuantum(tone),q); 04208 p+=GetPixelChannels(image); 04209 q+=GetPixelChannels(sepia_image); 04210 } 04211 if (SyncCacheViewAuthenticPixels(sepia_view,exception) == MagickFalse) 04212 status=MagickFalse; 04213 if (image->progress_monitor != (MagickProgressMonitor) NULL) 04214 { 04215 MagickBooleanType 04216 proceed; 04217 04218 #if defined(MAGICKCORE_OPENMP_SUPPORT) 04219 #pragma omp critical (MagickCore_SepiaToneImage) 04220 #endif 04221 proceed=SetImageProgress(image,SepiaToneImageTag,progress++, 04222 image->rows); 04223 if (proceed == MagickFalse) 04224 status=MagickFalse; 04225 } 04226 } 04227 sepia_view=DestroyCacheView(sepia_view); 04228 image_view=DestroyCacheView(image_view); 04229 (void) NormalizeImage(sepia_image,exception); 04230 (void) ContrastImage(sepia_image,MagickTrue,exception); 04231 if (status == MagickFalse) 04232 sepia_image=DestroyImage(sepia_image); 04233 return(sepia_image); 04234 } 04235 04236 /* 04237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 04238 % % 04239 % % 04240 % % 04241 % S h a d o w I m a g e % 04242 % % 04243 % % 04244 % % 04245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 04246 % 04247 % ShadowImage() simulates a shadow from the specified image and returns it. 04248 % 04249 % The format of the ShadowImage method is: 04250 % 04251 % Image *ShadowImage(const Image *image,const double alpha, 04252 % const double sigma,const double bias,const ssize_t x_offset, 04253 % const ssize_t y_offset,ExceptionInfo *exception) 04254 % 04255 % A description of each parameter follows: 04256 % 04257 % o image: the image. 04258 % 04259 % o alpha: percentage transparency. 04260 % 04261 % o sigma: the standard deviation of the Gaussian, in pixels. 04262 % 04263 % o bias: the bias. 04264 % 04265 % o x_offset: the shadow x-offset. 04266 % 04267 % o y_offset: the shadow y-offset. 04268 % 04269 % o exception: return any errors or warnings in this structure. 04270 % 04271 */ 04272 MagickExport Image *ShadowImage(const Image *image,const double alpha, 04273 const double sigma,const double bias,const ssize_t x_offset, 04274 const ssize_t y_offset,ExceptionInfo *exception) 04275 { 04276 #define ShadowImageTag "Shadow/Image" 04277 04278 CacheView 04279 *image_view; 04280 04281 ChannelType 04282 channel_mask; 04283 04284 Image 04285 *border_image, 04286 *clone_image, 04287 *shadow_image; 04288 04289 MagickBooleanType 04290 status; 04291 04292 RectangleInfo 04293 border_info; 04294 04295 ssize_t 04296 y; 04297 04298 assert(image != (Image *) NULL); 04299 assert(image->signature == MagickSignature); 04300 if (image->debug != MagickFalse) 04301 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 04302 assert(exception != (ExceptionInfo *) NULL); 04303 assert(exception->signature == MagickSignature); 04304 clone_image=CloneImage(image,0,0,MagickTrue,exception); 04305 if (clone_image == (Image *) NULL) 04306 return((Image *) NULL); 04307 (void) SetImageVirtualPixelMethod(clone_image,EdgeVirtualPixelMethod, 04308 exception); 04309 border_info.width=(size_t) floor(2.0*sigma+0.5); 04310 border_info.height=(size_t) floor(2.0*sigma+0.5); 04311 border_info.x=0; 04312 border_info.y=0; 04313 (void) QueryColorCompliance("none",AllCompliance,&clone_image->border_color, 04314 exception); 04315 clone_image->