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