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