2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % MagickCore Image Special Effects Methods %
20 % Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "magick/studio.h"
44 #include "magick/annotate.h"
45 #include "magick/artifact.h"
46 #include "magick/attribute.h"
47 #include "magick/cache.h"
48 #include "magick/cache-view.h"
49 #include "magick/color.h"
50 #include "magick/color-private.h"
51 #include "magick/composite.h"
52 #include "magick/decorate.h"
53 #include "magick/draw.h"
54 #include "magick/effect.h"
55 #include "magick/enhance.h"
56 #include "magick/exception.h"
57 #include "magick/exception-private.h"
58 #include "magick/fx.h"
59 #include "magick/fx-private.h"
60 #include "magick/gem.h"
61 #include "magick/geometry.h"
62 #include "magick/layer.h"
63 #include "magick/list.h"
64 #include "magick/log.h"
65 #include "magick/image.h"
66 #include "magick/image-private.h"
67 #include "magick/magick.h"
68 #include "magick/memory_.h"
69 #include "magick/monitor.h"
70 #include "magick/monitor-private.h"
71 #include "magick/option.h"
72 #include "magick/pixel-private.h"
73 #include "magick/property.h"
74 #include "magick/quantum.h"
75 #include "magick/quantum-private.h"
76 #include "magick/random_.h"
77 #include "magick/random-private.h"
78 #include "magick/resample.h"
79 #include "magick/resample-private.h"
80 #include "magick/resize.h"
81 #include "magick/shear.h"
82 #include "magick/splay-tree.h"
83 #include "magick/statistic.h"
84 #include "magick/string_.h"
85 #include "magick/string-private.h"
86 #include "magick/thread-private.h"
87 #include "magick/transform.h"
88 #include "magick/utility.h"
93 #define LeftShiftOperator 0xf5
94 #define RightShiftOperator 0xf6
95 #define LessThanEqualOperator 0xf7
96 #define GreaterThanEqualOperator 0xf8
97 #define EqualOperator 0xf9
98 #define NotEqualOperator 0xfa
99 #define LogicalAndOperator 0xfb
100 #define LogicalOrOperator 0xfc
101 #define ExponentialNotation 0xfd
129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133 + A c q u i r e F x I n f o %
137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
139 % AcquireFxInfo() allocates the FxInfo structure.
141 % The format of the AcquireFxInfo method is:
143 % FxInfo *AcquireFxInfo(Image *image,const char *expression)
145 % A description of each parameter follows:
147 % o image: the image.
149 % o expression: the expression.
152 MagickExport FxInfo *AcquireFxInfo(const Image *image,const char *expression)
166 fx_info=(FxInfo *) AcquireMagickMemory(sizeof(*fx_info));
167 if (fx_info == (FxInfo *) NULL)
168 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
169 (void) ResetMagickMemory(fx_info,0,sizeof(*fx_info));
170 fx_info->exception=AcquireExceptionInfo();
171 fx_info->images=image;
172 fx_info->colors=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
173 RelinquishMagickMemory);
174 fx_info->symbols=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
175 RelinquishMagickMemory);
176 fx_info->view=(CacheView **) AcquireQuantumMemory(GetImageListLength(
177 fx_info->images),sizeof(*fx_info->view));
178 if (fx_info->view == (CacheView **) NULL)
179 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
181 next=GetFirstImageInList(fx_info->images);
182 for ( ; next != (Image *) NULL; next=next->next)
184 fx_info->view[i]=AcquireCacheView(next);
187 fx_info->random_info=AcquireRandomInfo();
188 fx_info->expression=ConstantString(expression);
189 fx_info->file=stderr;
190 (void) SubstituteString(&fx_info->expression," ",""); /* compact string */
191 if ((strstr(fx_info->expression,"e+") != (char *) NULL) ||
192 (strstr(fx_info->expression,"e-") != (char *) NULL))
195 Convert scientific notation.
197 (void) SubstituteString(&fx_info->expression,"0e+","0**10^");
198 (void) SubstituteString(&fx_info->expression,"1e+","1**10^");
199 (void) SubstituteString(&fx_info->expression,"2e+","2**10^");
200 (void) SubstituteString(&fx_info->expression,"3e+","3**10^");
201 (void) SubstituteString(&fx_info->expression,"4e+","4**10^");
202 (void) SubstituteString(&fx_info->expression,"5e+","5**10^");
203 (void) SubstituteString(&fx_info->expression,"6e+","6**10^");
204 (void) SubstituteString(&fx_info->expression,"7e+","7**10^");
205 (void) SubstituteString(&fx_info->expression,"8e+","8**10^");
206 (void) SubstituteString(&fx_info->expression,"9e+","9**10^");
207 (void) SubstituteString(&fx_info->expression,"0e-","0**10^-");
208 (void) SubstituteString(&fx_info->expression,"1e-","1**10^-");
209 (void) SubstituteString(&fx_info->expression,"2e-","2**10^-");
210 (void) SubstituteString(&fx_info->expression,"3e-","3**10^-");
211 (void) SubstituteString(&fx_info->expression,"4e-","4**10^-");
212 (void) SubstituteString(&fx_info->expression,"5e-","5**10^-");
213 (void) SubstituteString(&fx_info->expression,"6e-","6**10^-");
214 (void) SubstituteString(&fx_info->expression,"7e-","7**10^-");
215 (void) SubstituteString(&fx_info->expression,"8e-","8**10^-");
216 (void) SubstituteString(&fx_info->expression,"9e-","9**10^-");
219 Force right-to-left associativity for unary negation.
221 (void) SubstituteString(&fx_info->expression,"-","-1.0*");
223 Convert complex to simple operators.
226 *fx_op=(char) LeftShiftOperator;
227 (void) SubstituteString(&fx_info->expression,"<<",fx_op);
228 *fx_op=(char) RightShiftOperator;
229 (void) SubstituteString(&fx_info->expression,">>",fx_op);
230 *fx_op=(char) LessThanEqualOperator;
231 (void) SubstituteString(&fx_info->expression,"<=",fx_op);
232 *fx_op=(char) GreaterThanEqualOperator;
233 (void) SubstituteString(&fx_info->expression,">=",fx_op);
234 *fx_op=(char) EqualOperator;
235 (void) SubstituteString(&fx_info->expression,"==",fx_op);
236 *fx_op=(char) NotEqualOperator;
237 (void) SubstituteString(&fx_info->expression,"!=",fx_op);
238 *fx_op=(char) LogicalAndOperator;
239 (void) SubstituteString(&fx_info->expression,"&&",fx_op);
240 *fx_op=(char) LogicalOrOperator;
241 (void) SubstituteString(&fx_info->expression,"||",fx_op);
242 *fx_op=(char) ExponentialNotation;
243 (void) SubstituteString(&fx_info->expression,"**",fx_op);
248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252 % A d d N o i s e I m a g e %
256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
258 % AddNoiseImage() adds random noise to the image.
260 % The format of the AddNoiseImage method is:
262 % Image *AddNoiseImage(const Image *image,const NoiseType noise_type,
263 % ExceptionInfo *exception)
264 % Image *AddNoiseImageChannel(const Image *image,const ChannelType channel,
265 % const NoiseType noise_type,ExceptionInfo *exception)
267 % A description of each parameter follows:
269 % o image: the image.
271 % o channel: the channel type.
273 % o noise_type: The type of noise: Uniform, Gaussian, Multiplicative,
274 % Impulse, Laplacian, or Poisson.
276 % o exception: return any errors or warnings in this structure.
279 MagickExport Image *AddNoiseImage(const Image *image,const NoiseType noise_type,
280 ExceptionInfo *exception)
285 noise_image=AddNoiseImageChannel(image,DefaultChannels,noise_type,exception);
289 MagickExport Image *AddNoiseImageChannel(const Image *image,
290 const ChannelType channel,const NoiseType noise_type,ExceptionInfo *exception)
292 #define AddNoiseImageTag "AddNoise/Image"
314 **restrict random_info;
320 Initialize noise image attributes.
322 assert(image != (const Image *) NULL);
323 assert(image->signature == MagickSignature);
324 if (image->debug != MagickFalse)
325 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
326 assert(exception != (ExceptionInfo *) NULL);
327 assert(exception->signature == MagickSignature);
328 noise_image=CloneImage(image,0,0,MagickTrue,exception);
329 if (noise_image == (Image *) NULL)
330 return((Image *) NULL);
331 if (SetImageStorageClass(noise_image,DirectClass) == MagickFalse)
333 InheritException(exception,&noise_image->exception);
334 noise_image=DestroyImage(noise_image);
335 return((Image *) NULL);
338 Add noise in each row.
341 option=GetImageArtifact(image,"attenuate");
342 if (option != (char *) NULL)
343 attenuate=StringToDouble(option);
346 random_info=AcquireRandomInfoThreadSet();
347 image_view=AcquireCacheView(image);
348 noise_view=AcquireCacheView(noise_image);
349 #if defined(MAGICKCORE_OPENMP_SUPPORT)
350 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
352 for (y=0; y < (ssize_t) image->rows; y++)
355 id = GetOpenMPThreadId();
360 register const IndexPacket
363 register const PixelPacket
367 *restrict noise_indexes;
375 if (status == MagickFalse)
377 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
378 q=GetCacheViewAuthenticPixels(noise_view,0,y,noise_image->columns,1,
380 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
385 indexes=GetCacheViewVirtualIndexQueue(image_view);
386 noise_indexes=GetCacheViewAuthenticIndexQueue(noise_view);
387 for (x=0; x < (ssize_t) image->columns; x++)
389 if ((channel & RedChannel) != 0)
390 SetRedPixelComponent(q,ClampToQuantum(GenerateDifferentialNoise(
391 random_info[id],GetRedPixelComponent(p),noise_type,attenuate)));
392 if ((channel & GreenChannel) != 0)
393 SetGreenPixelComponent(q,ClampToQuantum(GenerateDifferentialNoise(
394 random_info[id],GetGreenPixelComponent(p),noise_type,attenuate)));
395 if ((channel & BlueChannel) != 0)
396 SetBluePixelComponent(q,ClampToQuantum(GenerateDifferentialNoise(
397 random_info[id],GetBluePixelComponent(p),noise_type,attenuate)));
398 if ((channel & OpacityChannel) != 0)
399 SetOpacityPixelComponent(q,ClampToQuantum(GenerateDifferentialNoise(
400 random_info[id],GetOpacityPixelComponent(p),noise_type,attenuate)));
401 if (((channel & IndexChannel) != 0) &&
402 (image->colorspace == CMYKColorspace))
403 SetIndexPixelComponent(noise_indexes+x,ClampToQuantum(
404 GenerateDifferentialNoise(random_info[id],GetIndexPixelComponent(
405 indexes+x),noise_type,attenuate)));
409 sync=SyncCacheViewAuthenticPixels(noise_view,exception);
410 if (sync == MagickFalse)
412 if (image->progress_monitor != (MagickProgressMonitor) NULL)
417 #if defined(MAGICKCORE_OPENMP_SUPPORT)
418 #pragma omp critical (MagickCore_AddNoiseImage)
420 proceed=SetImageProgress(image,AddNoiseImageTag,progress++,
422 if (proceed == MagickFalse)
426 noise_view=DestroyCacheView(noise_view);
427 image_view=DestroyCacheView(image_view);
428 random_info=DestroyRandomInfoThreadSet(random_info);
429 if (status == MagickFalse)
430 noise_image=DestroyImage(noise_image);
435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
439 % B l u e S h i f t I m a g e %
443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
445 % BlueShiftImage() mutes the colors of the image to simulate a scene at
446 % nighttime in the moonlight.
448 % The format of the BlueShiftImage method is:
450 % Image *BlueShiftImage(const Image *image,const double factor,
451 % ExceptionInfo *exception)
453 % A description of each parameter follows:
455 % o image: the image.
457 % o factor: the shift factor.
459 % o exception: return any errors or warnings in this structure.
462 MagickExport Image *BlueShiftImage(const Image *image,const double factor,
463 ExceptionInfo *exception)
465 #define BlueShiftImageTag "BlueShift/Image"
484 Allocate blue shift image.
486 assert(image != (const Image *) NULL);
487 assert(image->signature == MagickSignature);
488 if (image->debug != MagickFalse)
489 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
490 assert(exception != (ExceptionInfo *) NULL);
491 assert(exception->signature == MagickSignature);
492 shift_image=CloneImage(image,image->columns,image->rows,MagickTrue,
494 if (shift_image == (Image *) NULL)
495 return((Image *) NULL);
496 if (SetImageStorageClass(shift_image,DirectClass) == MagickFalse)
498 InheritException(exception,&shift_image->exception);
499 shift_image=DestroyImage(shift_image);
500 return((Image *) NULL);
503 Blue-shift DirectClass image.
507 image_view=AcquireCacheView(image);
508 shift_view=AcquireCacheView(shift_image);
509 #if defined(MAGICKCORE_OPENMP_SUPPORT)
510 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
512 for (y=0; y < (ssize_t) image->rows; y++)
523 register const PixelPacket
532 if (status == MagickFalse)
534 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
535 q=QueueCacheViewAuthenticPixels(shift_view,0,y,shift_image->columns,1,
537 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
542 for (x=0; x < (ssize_t) image->columns; x++)
544 quantum=GetRedPixelComponent(p);
545 if (GetGreenPixelComponent(p) < quantum)
546 quantum=GetGreenPixelComponent(p);
547 if (GetBluePixelComponent(p) < quantum)
548 quantum=GetBluePixelComponent(p);
549 pixel.red=0.5*(GetRedPixelComponent(p)+factor*quantum);
550 pixel.green=0.5*(GetGreenPixelComponent(p)+factor*quantum);
551 pixel.blue=0.5*(GetBluePixelComponent(p)+factor*quantum);
552 quantum=GetRedPixelComponent(p);
553 if (GetGreenPixelComponent(p) > quantum)
554 quantum=GetGreenPixelComponent(p);
555 if (GetBluePixelComponent(p) > quantum)
556 quantum=GetBluePixelComponent(p);
557 pixel.red=0.5*(pixel.red+factor*quantum);
558 pixel.green=0.5*(pixel.green+factor*quantum);
559 pixel.blue=0.5*(pixel.blue+factor*quantum);
560 SetRedPixelComponent(q,ClampToQuantum(pixel.red));
561 SetGreenPixelComponent(q,ClampToQuantum(pixel.green));
562 SetBluePixelComponent(q,ClampToQuantum(pixel.blue));
566 sync=SyncCacheViewAuthenticPixels(shift_view,exception);
567 if (sync == MagickFalse)
569 if (image->progress_monitor != (MagickProgressMonitor) NULL)
574 #if defined(MAGICKCORE_OPENMP_SUPPORT)
575 #pragma omp critical (MagickCore_BlueShiftImage)
577 proceed=SetImageProgress(image,BlueShiftImageTag,progress++,
579 if (proceed == MagickFalse)
583 image_view=DestroyCacheView(image_view);
584 shift_view=DestroyCacheView(shift_view);
585 if (status == MagickFalse)
586 shift_image=DestroyImage(shift_image);
591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
595 % C h a r c o a l I m a g e %
599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
601 % CharcoalImage() creates a new image that is a copy of an existing one with
602 % the edge highlighted. It allocates the memory necessary for the new Image
603 % structure and returns a pointer to the new image.
605 % The format of the CharcoalImage method is:
607 % Image *CharcoalImage(const Image *image,const double radius,
608 % const double sigma,ExceptionInfo *exception)
610 % A description of each parameter follows:
612 % o image: the image.
614 % o radius: the radius of the pixel neighborhood.
616 % o sigma: the standard deviation of the Gaussian, in pixels.
618 % o exception: return any errors or warnings in this structure.
621 MagickExport Image *CharcoalImage(const Image *image,const double radius,
622 const double sigma,ExceptionInfo *exception)
629 assert(image != (Image *) NULL);
630 assert(image->signature == MagickSignature);
631 if (image->debug != MagickFalse)
632 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
633 assert(exception != (ExceptionInfo *) NULL);
634 assert(exception->signature == MagickSignature);
635 clone_image=CloneImage(image,0,0,MagickTrue,exception);
636 if (clone_image == (Image *) NULL)
637 return((Image *) NULL);
638 (void) SetImageType(clone_image,GrayscaleType);
639 edge_image=EdgeImage(clone_image,radius,exception);
640 clone_image=DestroyImage(clone_image);
641 if (edge_image == (Image *) NULL)
642 return((Image *) NULL);
643 charcoal_image=BlurImage(edge_image,radius,sigma,exception);
644 edge_image=DestroyImage(edge_image);
645 if (charcoal_image == (Image *) NULL)
646 return((Image *) NULL);
647 (void) NormalizeImage(charcoal_image);
648 (void) NegateImage(charcoal_image,MagickFalse);
649 (void) SetImageType(charcoal_image,GrayscaleType);
650 return(charcoal_image);
654 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
658 % C o l o r i z e I m a g e %
662 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
664 % ColorizeImage() blends the fill color with each pixel in the image.
665 % A percentage blend is specified with opacity. Control the application
666 % of different color components by specifying a different percentage for
667 % each component (e.g. 90/100/10 is 90% red, 100% green, and 10% blue).
669 % The format of the ColorizeImage method is:
671 % Image *ColorizeImage(const Image *image,const char *opacity,
672 % const PixelPacket colorize,ExceptionInfo *exception)
674 % A description of each parameter follows:
676 % o image: the image.
678 % o opacity: A character string indicating the level of opacity as a
681 % o colorize: A color value.
683 % o exception: return any errors or warnings in this structure.
686 MagickExport Image *ColorizeImage(const Image *image,const char *opacity,
687 const PixelPacket colorize,ExceptionInfo *exception)
689 #define ColorizeImageTag "Colorize/Image"
717 Allocate colorized image.
719 assert(image != (const Image *) NULL);
720 assert(image->signature == MagickSignature);
721 if (image->debug != MagickFalse)
722 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
723 assert(exception != (ExceptionInfo *) NULL);
724 assert(exception->signature == MagickSignature);
725 colorize_image=CloneImage(image,image->columns,image->rows,MagickTrue,
727 if (colorize_image == (Image *) NULL)
728 return((Image *) NULL);
729 if (SetImageStorageClass(colorize_image,DirectClass) == MagickFalse)
731 InheritException(exception,&colorize_image->exception);
732 colorize_image=DestroyImage(colorize_image);
733 return((Image *) NULL);
735 if (opacity == (const char *) NULL)
736 return(colorize_image);
738 Determine RGB values of the pen color.
740 flags=ParseGeometry(opacity,&geometry_info);
741 pixel.red=geometry_info.rho;
742 pixel.green=geometry_info.rho;
743 pixel.blue=geometry_info.rho;
744 pixel.opacity=(MagickRealType) OpaqueOpacity;
745 if ((flags & SigmaValue) != 0)
746 pixel.green=geometry_info.sigma;
747 if ((flags & XiValue) != 0)
748 pixel.blue=geometry_info.xi;
749 if ((flags & PsiValue) != 0)
750 pixel.opacity=geometry_info.psi;
752 Colorize DirectClass image.
756 image_view=AcquireCacheView(image);
757 colorize_view=AcquireCacheView(colorize_image);
758 #if defined(MAGICKCORE_OPENMP_SUPPORT)
759 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
761 for (y=0; y < (ssize_t) image->rows; y++)
766 register const PixelPacket
775 if (status == MagickFalse)
777 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
778 q=QueueCacheViewAuthenticPixels(colorize_view,0,y,colorize_image->columns,1,
780 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
785 for (x=0; x < (ssize_t) image->columns; x++)
787 SetRedPixelComponent(q,((GetRedPixelComponent(p)*(100.0-pixel.red)+
788 colorize.red*pixel.red)/100.0));
789 SetGreenPixelComponent(q,((GetGreenPixelComponent(p)*(100.0-pixel.green)+
790 colorize.green*pixel.green)/100.0));
791 SetBluePixelComponent(q,((GetBluePixelComponent(p)*(100.0-pixel.blue)+
792 colorize.blue*pixel.blue)/100.0));
793 SetOpacityPixelComponent(q,((GetOpacityPixelComponent(p)*(100.0-
794 pixel.opacity)+colorize.opacity*pixel.opacity)/100.0));
798 sync=SyncCacheViewAuthenticPixels(colorize_view,exception);
799 if (sync == MagickFalse)
801 if (image->progress_monitor != (MagickProgressMonitor) NULL)
806 #if defined(MAGICKCORE_OPENMP_SUPPORT)
807 #pragma omp critical (MagickCore_ColorizeImage)
809 proceed=SetImageProgress(image,ColorizeImageTag,progress++,image->rows);
810 if (proceed == MagickFalse)
814 image_view=DestroyCacheView(image_view);
815 colorize_view=DestroyCacheView(colorize_view);
816 if (status == MagickFalse)
817 colorize_image=DestroyImage(colorize_image);
818 return(colorize_image);
822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
826 % C o l o r M a t r i x I m a g e %
830 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
832 % ColorMatrixImage() applies color transformation to an image. This method
833 % permits saturation changes, hue rotation, luminance to alpha, and various
834 % other effects. Although variable-sized transformation matrices can be used,
835 % typically one uses a 5x5 matrix for an RGBA image and a 6x6 for CMYKA
836 % (or RGBA with offsets). The matrix is similar to those used by Adobe Flash
837 % except offsets are in column 6 rather than 5 (in support of CMYKA images)
838 % and offsets are normalized (divide Flash offset by 255).
840 % The format of the ColorMatrixImage method is:
842 % Image *ColorMatrixImage(const Image *image,
843 % const KernelInfo *color_matrix,ExceptionInfo *exception)
845 % A description of each parameter follows:
847 % o image: the image.
849 % o color_matrix: the color matrix.
851 % o exception: return any errors or warnings in this structure.
854 MagickExport Image *ColorMatrixImage(const Image *image,
855 const KernelInfo *color_matrix,ExceptionInfo *exception)
857 #define ColorMatrixImageTag "ColorMatrix/Image"
866 { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
867 { 0.0, 1.0, 0.0, 0.0, 0.0, 0.0 },
868 { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 },
869 { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0 },
870 { 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 },
871 { 0.0, 0.0, 0.0, 0.0, 0.0, 1.0 }
894 assert(image != (Image *) NULL);
895 assert(image->signature == MagickSignature);
896 if (image->debug != MagickFalse)
897 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
898 assert(exception != (ExceptionInfo *) NULL);
899 assert(exception->signature == MagickSignature);
901 for (v=0; v < (ssize_t) color_matrix->height; v++)
902 for (u=0; u < (ssize_t) color_matrix->width; u++)
904 if ((v < 6) && (u < 6))
905 ColorMatrix[v][u]=color_matrix->values[i];
909 Initialize color image.
911 color_image=CloneImage(image,0,0,MagickTrue,exception);
912 if (color_image == (Image *) NULL)
913 return((Image *) NULL);
914 if (SetImageStorageClass(color_image,DirectClass) == MagickFalse)
916 InheritException(exception,&color_image->exception);
917 color_image=DestroyImage(color_image);
918 return((Image *) NULL);
920 if (image->debug != MagickFalse)
923 format[MaxTextExtent],
926 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
927 " ColorMatrix image with color matrix:");
928 message=AcquireString("");
929 for (v=0; v < 6; v++)
932 (void) FormatMagickString(format,MaxTextExtent,"%.20g: ",(double) v);
933 (void) ConcatenateString(&message,format);
934 for (u=0; u < 6; u++)
936 (void) FormatMagickString(format,MaxTextExtent,"%+f ",
938 (void) ConcatenateString(&message,format);
940 (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
942 message=DestroyString(message);
949 image_view=AcquireCacheView(image);
950 color_view=AcquireCacheView(color_image);
951 #if defined(MAGICKCORE_OPENMP_SUPPORT)
952 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
954 for (y=0; y < (ssize_t) image->rows; y++)
959 register const IndexPacket
962 register const PixelPacket
969 *restrict color_indexes;
974 if (status == MagickFalse)
976 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
977 q=GetCacheViewAuthenticPixels(color_view,0,y,color_image->columns,1,
979 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
984 indexes=GetCacheViewVirtualIndexQueue(image_view);
985 color_indexes=GetCacheViewAuthenticIndexQueue(color_view);
986 for (x=0; x < (ssize_t) image->columns; x++)
994 height=color_matrix->height > 6 ? 6UL : color_matrix->height;
995 for (v=0; v < (ssize_t) height; v++)
997 pixel=ColorMatrix[v][0]*GetRedPixelComponent(p)+ColorMatrix[v][1]*
998 GetGreenPixelComponent(p)+ColorMatrix[v][2]*GetBluePixelComponent(p);
999 if (image->matte != MagickFalse)
1000 pixel+=ColorMatrix[v][3]*(QuantumRange-GetOpacityPixelComponent(p));
1001 if (image->colorspace == CMYKColorspace)
1002 pixel+=ColorMatrix[v][4]*GetIndexPixelComponent(indexes+x);
1003 pixel+=QuantumRange*ColorMatrix[v][5];
1006 case 0: SetRedPixelComponent(q,ClampToQuantum(pixel)); break;
1007 case 1: SetGreenPixelComponent(q,ClampToQuantum(pixel)); break;
1008 case 2: SetBluePixelComponent(q,ClampToQuantum(pixel)); break;
1011 if (image->matte != MagickFalse)
1012 SetOpacityPixelComponent(q,ClampToQuantum(QuantumRange-pixel));
1017 if (image->colorspace == CMYKColorspace)
1018 SetIndexPixelComponent(color_indexes+x,ClampToQuantum(pixel));
1026 if (SyncCacheViewAuthenticPixels(color_view,exception) == MagickFalse)
1028 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1033 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1034 #pragma omp critical (MagickCore_ColorMatrixImage)
1036 proceed=SetImageProgress(image,ColorMatrixImageTag,progress++,
1038 if (proceed == MagickFalse)
1042 color_view=DestroyCacheView(color_view);
1043 image_view=DestroyCacheView(image_view);
1044 if (status == MagickFalse)
1045 color_image=DestroyImage(color_image);
1046 return(color_image);
1050 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1054 + D e s t r o y F x I n f o %
1058 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1060 % DestroyFxInfo() deallocates memory associated with an FxInfo structure.
1062 % The format of the DestroyFxInfo method is:
1064 % ImageInfo *DestroyFxInfo(ImageInfo *fx_info)
1066 % A description of each parameter follows:
1068 % o fx_info: the fx info.
1071 MagickExport FxInfo *DestroyFxInfo(FxInfo *fx_info)
1076 fx_info->exception=DestroyExceptionInfo(fx_info->exception);
1077 fx_info->expression=DestroyString(fx_info->expression);
1078 fx_info->symbols=DestroySplayTree(fx_info->symbols);
1079 fx_info->colors=DestroySplayTree(fx_info->colors);
1080 for (i=(ssize_t) GetImageListLength(fx_info->images)-1; i >= 0; i--)
1081 fx_info->view[i]=DestroyCacheView(fx_info->view[i]);
1082 fx_info->view=(CacheView **) RelinquishMagickMemory(fx_info->view);
1083 fx_info->random_info=DestroyRandomInfo(fx_info->random_info);
1084 fx_info=(FxInfo *) RelinquishMagickMemory(fx_info);
1089 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1093 + F x E v a l u a t e C h a n n e l E x p r e s s i o n %
1097 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1099 % FxEvaluateChannelExpression() evaluates an expression and returns the
1102 % The format of the FxEvaluateExpression method is:
1104 % MagickRealType FxEvaluateChannelExpression(FxInfo *fx_info,
1105 % const ChannelType channel,const ssize_t x,const ssize_t y,
1106 % MagickRealType *alpha,Exceptioninfo *exception)
1107 % MagickRealType FxEvaluateExpression(FxInfo *fx_info,
1108 % MagickRealType *alpha,Exceptioninfo *exception)
1110 % A description of each parameter follows:
1112 % o fx_info: the fx info.
1114 % o channel: the channel.
1116 % o x,y: the pixel position.
1118 % o alpha: the result.
1120 % o exception: return any errors or warnings in this structure.
1124 static inline double MagickMax(const double x,const double y)
1131 static inline double MagickMin(const double x,const double y)
1138 static MagickRealType FxChannelStatistics(FxInfo *fx_info,const Image *image,
1139 ChannelType channel,const char *symbol,ExceptionInfo *exception)
1143 statistic[MaxTextExtent];
1151 for (p=symbol; (*p != '.') && (*p != '\0'); p++) ;
1153 switch (*++p) /* e.g. depth.r */
1155 case 'r': channel=RedChannel; break;
1156 case 'g': channel=GreenChannel; break;
1157 case 'b': channel=BlueChannel; break;
1158 case 'c': channel=CyanChannel; break;
1159 case 'm': channel=MagentaChannel; break;
1160 case 'y': channel=YellowChannel; break;
1161 case 'k': channel=BlackChannel; break;
1164 (void) FormatMagickString(key,MaxTextExtent,"%p.%.20g.%s",(void *) image,
1165 (double) channel,symbol);
1166 value=(const char *) GetValueFromSplayTree(fx_info->symbols,key);
1167 if (value != (const char *) NULL)
1168 return(QuantumScale*StringToDouble(value));
1169 (void) DeleteNodeFromSplayTree(fx_info->symbols,key);
1170 if (LocaleNCompare(symbol,"depth",5) == 0)
1175 depth=GetImageChannelDepth(image,channel,exception);
1176 (void) FormatMagickString(statistic,MaxTextExtent,"%.20g",(double)
1179 if (LocaleNCompare(symbol,"kurtosis",8) == 0)
1185 (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
1187 (void) FormatMagickString(statistic,MaxTextExtent,"%g",kurtosis);
1189 if (LocaleNCompare(symbol,"maxima",6) == 0)
1195 (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
1196 (void) FormatMagickString(statistic,MaxTextExtent,"%g",maxima);
1198 if (LocaleNCompare(symbol,"mean",4) == 0)
1204 (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
1206 (void) FormatMagickString(statistic,MaxTextExtent,"%g",mean);
1208 if (LocaleNCompare(symbol,"minima",6) == 0)
1214 (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
1215 (void) FormatMagickString(statistic,MaxTextExtent,"%g",minima);
1217 if (LocaleNCompare(symbol,"skewness",8) == 0)
1223 (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
1225 (void) FormatMagickString(statistic,MaxTextExtent,"%g",skewness);
1227 if (LocaleNCompare(symbol,"standard_deviation",18) == 0)
1233 (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
1235 (void) FormatMagickString(statistic,MaxTextExtent,"%g",
1236 standard_deviation);
1238 (void) AddValueToSplayTree(fx_info->symbols,ConstantString(key),
1239 ConstantString(statistic));
1240 return(QuantumScale*StringToDouble(statistic));
1243 static MagickRealType
1244 FxEvaluateSubexpression(FxInfo *,const ChannelType,const ssize_t,
1245 const ssize_t,const char *,MagickRealType *,ExceptionInfo *);
1247 static inline MagickRealType FxMax(FxInfo *fx_info,const ChannelType channel,
1248 const ssize_t x,const ssize_t y,const char *expression,
1249 ExceptionInfo *exception)
1255 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression,&beta,exception);
1256 return((MagickRealType) MagickMax((double) alpha,(double) beta));
1259 static inline MagickRealType FxMin(FxInfo *fx_info,ChannelType channel,
1260 const ssize_t x,const ssize_t y,const char *expression,
1261 ExceptionInfo *exception)
1267 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression,&beta,exception);
1268 return((MagickRealType) MagickMin((double) alpha,(double) beta));
1271 static inline const char *FxSubexpression(const char *expression,
1272 ExceptionInfo *exception)
1281 subexpression=expression;
1282 while ((*subexpression != '\0') &&
1283 ((level != 1) || (strchr(")",(int) *subexpression) == (char *) NULL)))
1285 if (strchr("(",(int) *subexpression) != (char *) NULL)
1288 if (strchr(")",(int) *subexpression) != (char *) NULL)
1292 if (*subexpression == '\0')
1293 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1294 "UnbalancedParenthesis","`%s'",expression);
1295 return(subexpression);
1298 static MagickRealType FxGetSymbol(FxInfo *fx_info,const ChannelType channel,
1299 const ssize_t x,const ssize_t y,const char *expression,
1300 ExceptionInfo *exception)
1304 subexpression[MaxTextExtent],
1305 symbol[MaxTextExtent];
1334 i=GetImageIndexInList(fx_info->images);
1338 if (isalpha((int) *(p+1)) == 0)
1340 if (strchr("suv",(int) *p) != (char *) NULL)
1347 i=GetImageIndexInList(fx_info->images);
1350 case 'u': i=0; break;
1351 case 'v': i=1; break;
1358 for (p++; *p != '\0'; )
1372 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
1374 i=(ssize_t) (alpha+0.5);
1380 if ((isalpha((int) *(p+1)) == 0) && (*p == 'p'))
1387 for (p++; *p != '\0'; )
1401 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
1412 for (p++; *p != '\0'; )
1426 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
1436 length=GetImageListLength(fx_info->images);
1438 i+=(ssize_t) length;
1440 image=GetImageFromList(fx_info->images,i);
1441 if (image == (Image *) NULL)
1443 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1444 "NoSuchImage","`%s'",expression);
1447 GetMagickPixelPacket(image,&pixel);
1448 (void) InterpolateMagickPixelPacket(image,fx_info->view[i],image->interpolate,
1449 point.x,point.y,&pixel,exception);
1450 if ((strlen(p) > 2) &&
1451 (LocaleCompare(p,"intensity") != 0) &&
1452 (LocaleCompare(p,"luminance") != 0) &&
1453 (LocaleCompare(p,"hue") != 0) &&
1454 (LocaleCompare(p,"saturation") != 0) &&
1455 (LocaleCompare(p,"lightness") != 0))
1458 name[MaxTextExtent];
1460 (void) CopyMagickString(name,p,MaxTextExtent);
1461 for (q=name+(strlen(name)-1); q > name; q--)
1471 if ((strlen(name) > 2) &&
1472 (GetValueFromSplayTree(fx_info->symbols,name) == (const char *) NULL))
1477 color=(MagickPixelPacket *) GetValueFromSplayTree(fx_info->colors,
1479 if (color != (MagickPixelPacket *) NULL)
1485 if (QueryMagickColor(name,&pixel,fx_info->exception) != MagickFalse)
1487 (void) AddValueToSplayTree(fx_info->colors,ConstantString(name),
1488 CloneMagickPixelPacket(&pixel));
1493 (void) CopyMagickString(symbol,p,MaxTextExtent);
1494 StripString(symbol);
1495 if (*symbol == '\0')
1499 case RedChannel: return(QuantumScale*pixel.red);
1500 case GreenChannel: return(QuantumScale*pixel.green);
1501 case BlueChannel: return(QuantumScale*pixel.blue);
1502 case OpacityChannel:
1507 if (pixel.matte == MagickFalse)
1509 alpha=(MagickRealType) (QuantumScale*GetAlphaPixelComponent(&pixel));
1514 if (image->colorspace != CMYKColorspace)
1516 (void) ThrowMagickException(exception,GetMagickModule(),
1517 OptionError,"ColorSeparatedImageRequired","`%s'",
1521 return(QuantumScale*pixel.index);
1523 case DefaultChannels:
1525 return(QuantumScale*MagickPixelIntensityToQuantum(&pixel));
1530 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1531 "UnableToParseExpression","`%s'",p);
1539 if (LocaleCompare(symbol,"a") == 0)
1540 return((MagickRealType) (QuantumScale*GetAlphaPixelComponent(&pixel)));
1546 if (LocaleCompare(symbol,"b") == 0)
1547 return(QuantumScale*pixel.blue);
1553 if (LocaleNCompare(symbol,"channel",7) == 0)
1561 flags=ParseGeometry(symbol+7,&channel_info);
1562 if (image->colorspace == CMYKColorspace)
1567 if ((flags & RhoValue) == 0)
1569 return(channel_info.rho);
1571 case MagentaChannel:
1573 if ((flags & SigmaValue) == 0)
1575 return(channel_info.sigma);
1579 if ((flags & XiValue) == 0)
1581 return(channel_info.xi);
1585 if ((flags & PsiValue) == 0)
1587 return(channel_info.psi);
1589 case OpacityChannel:
1591 if ((flags & ChiValue) == 0)
1593 return(channel_info.chi);
1602 if ((flags & RhoValue) == 0)
1604 return(channel_info.rho);
1608 if ((flags & SigmaValue) == 0)
1610 return(channel_info.sigma);
1614 if ((flags & XiValue) == 0)
1616 return(channel_info.xi);
1618 case OpacityChannel:
1620 if ((flags & PsiValue) == 0)
1622 return(channel_info.psi);
1626 if ((flags & ChiValue) == 0)
1628 return(channel_info.chi);
1635 if (LocaleCompare(symbol,"c") == 0)
1636 return(QuantumScale*pixel.red);
1642 if (LocaleNCompare(symbol,"depth",5) == 0)
1643 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1649 if (LocaleCompare(symbol,"g") == 0)
1650 return(QuantumScale*pixel.green);
1656 if (LocaleNCompare(symbol,"kurtosis",8) == 0)
1657 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1658 if (LocaleCompare(symbol,"k") == 0)
1660 if (image->colorspace != CMYKColorspace)
1662 (void) ThrowMagickException(exception,GetMagickModule(),
1663 OptionError,"ColorSeparatedImageRequired","`%s'",
1667 return(QuantumScale*pixel.index);
1674 if (LocaleCompare(symbol,"h") == 0)
1675 return((MagickRealType) image->rows);
1676 if (LocaleCompare(symbol,"hue") == 0)
1683 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
1684 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
1692 if ((LocaleCompare(symbol,"image.depth") == 0) ||
1693 (LocaleCompare(symbol,"image.minima") == 0) ||
1694 (LocaleCompare(symbol,"image.maxima") == 0) ||
1695 (LocaleCompare(symbol,"image.mean") == 0) ||
1696 (LocaleCompare(symbol,"image.kurtosis") == 0) ||
1697 (LocaleCompare(symbol,"image.skewness") == 0) ||
1698 (LocaleCompare(symbol,"image.standard_deviation") == 0))
1699 return(FxChannelStatistics(fx_info,image,channel,symbol+6,exception));
1700 if (LocaleCompare(symbol,"image.resolution.x") == 0)
1701 return(image->x_resolution);
1702 if (LocaleCompare(symbol,"image.resolution.y") == 0)
1703 return(image->y_resolution);
1704 if (LocaleCompare(symbol,"intensity") == 0)
1705 return(QuantumScale*MagickPixelIntensityToQuantum(&pixel));
1706 if (LocaleCompare(symbol,"i") == 0)
1707 return((MagickRealType) x);
1713 if (LocaleCompare(symbol,"j") == 0)
1714 return((MagickRealType) y);
1720 if (LocaleCompare(symbol,"lightness") == 0)
1727 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
1728 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
1731 if (LocaleCompare(symbol,"luminance") == 0)
1736 luminence=0.2126*pixel.red+0.7152*pixel.green+0.0722*pixel.blue;
1737 return(QuantumScale*luminence);
1744 if (LocaleNCompare(symbol,"maxima",6) == 0)
1745 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1746 if (LocaleNCompare(symbol,"mean",4) == 0)
1747 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1748 if (LocaleNCompare(symbol,"minima",6) == 0)
1749 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1750 if (LocaleCompare(symbol,"m") == 0)
1751 return(QuantumScale*pixel.blue);
1757 if (LocaleCompare(symbol,"n") == 0)
1758 return((MagickRealType) GetImageListLength(fx_info->images));
1764 if (LocaleCompare(symbol,"o") == 0)
1765 return(QuantumScale*pixel.opacity);
1771 if (LocaleCompare(symbol,"page.height") == 0)
1772 return((MagickRealType) image->page.height);
1773 if (LocaleCompare(symbol,"page.width") == 0)
1774 return((MagickRealType) image->page.width);
1775 if (LocaleCompare(symbol,"page.x") == 0)
1776 return((MagickRealType) image->page.x);
1777 if (LocaleCompare(symbol,"page.y") == 0)
1778 return((MagickRealType) image->page.y);
1784 if (LocaleCompare(symbol,"resolution.x") == 0)
1785 return(image->x_resolution);
1786 if (LocaleCompare(symbol,"resolution.y") == 0)
1787 return(image->y_resolution);
1788 if (LocaleCompare(symbol,"r") == 0)
1789 return(QuantumScale*pixel.red);
1795 if (LocaleCompare(symbol,"saturation") == 0)
1802 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
1803 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
1806 if (LocaleNCompare(symbol,"skewness",8) == 0)
1807 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1808 if (LocaleNCompare(symbol,"standard_deviation",18) == 0)
1809 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1815 if (LocaleCompare(symbol,"t") == 0)
1816 return((MagickRealType) GetImageIndexInList(fx_info->images));
1822 if (LocaleCompare(symbol,"w") == 0)
1823 return((MagickRealType) image->columns);
1829 if (LocaleCompare(symbol,"y") == 0)
1830 return(QuantumScale*pixel.green);
1836 if (LocaleCompare(symbol,"z") == 0)
1841 depth=(MagickRealType) GetImageChannelDepth(image,channel,
1842 fx_info->exception);
1850 value=(const char *) GetValueFromSplayTree(fx_info->symbols,symbol);
1851 if (value != (const char *) NULL)
1852 return((MagickRealType) StringToDouble(value));
1853 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1854 "UnableToParseExpression","`%s'",symbol);
1858 static const char *FxOperatorPrecedence(const char *expression,
1859 ExceptionInfo *exception)
1863 UndefinedPrecedence,
1865 BitwiseComplementPrecedence,
1867 ExponentialNotationPrecedence,
1871 RelationalPrecedence,
1872 EquivalencyPrecedence,
1873 BitwiseAndPrecedence,
1874 BitwiseOrPrecedence,
1875 LogicalAndPrecedence,
1876 LogicalOrPrecedence,
1878 AssignmentPrecedence,
1898 subexpression=(const char *) NULL;
1899 target=NullPrecedence;
1900 while (*expression != '\0')
1902 precedence=UndefinedPrecedence;
1903 if ((isspace((int) ((char) *expression)) != 0) || (c == (int) '@'))
1908 switch (*expression)
1913 if (LocaleNCompare(expression,"atan2",5) == 0)
1923 if ((LocaleNCompare(expression,"j0",2) == 0) ||
1924 (LocaleNCompare(expression,"j1",2) == 0))
1933 while (isxdigit((int) ((unsigned char) *(expression+1))) != 0)
1940 if ((c == (int) '{') || (c == (int) '['))
1943 if ((c == (int) '}') || (c == (int) ']'))
1946 switch ((unsigned char) *expression)
1951 precedence=BitwiseComplementPrecedence;
1957 precedence=ExponentPrecedence;
1962 if (((c != 0) && ((isdigit((int) ((char) c)) != 0) ||
1963 (strchr(")",c) != (char *) NULL))) &&
1964 (((islower((int) ((char) *expression)) != 0) ||
1965 (strchr("(",(int) *expression) != (char *) NULL)) ||
1966 ((isdigit((int) ((char) c)) == 0) &&
1967 (isdigit((int) ((char) *expression)) != 0))) &&
1968 (strchr("xy",(int) *expression) == (char *) NULL))
1969 precedence=MultiplyPrecedence;
1976 precedence=MultiplyPrecedence;
1982 if ((strchr("(+-/*%:&^|<>~,",c) == (char *) NULL) ||
1984 precedence=AdditionPrecedence;
1987 case LeftShiftOperator:
1988 case RightShiftOperator:
1990 precedence=ShiftPrecedence;
1994 case LessThanEqualOperator:
1995 case GreaterThanEqualOperator:
1998 precedence=RelationalPrecedence;
2002 case NotEqualOperator:
2004 precedence=EquivalencyPrecedence;
2009 precedence=BitwiseAndPrecedence;
2014 precedence=BitwiseOrPrecedence;
2017 case LogicalAndOperator:
2019 precedence=LogicalAndPrecedence;
2022 case LogicalOrOperator:
2024 precedence=LogicalOrPrecedence;
2027 case ExponentialNotation:
2029 precedence=ExponentialNotationPrecedence;
2035 precedence=TernaryPrecedence;
2040 precedence=AssignmentPrecedence;
2045 precedence=CommaPrecedence;
2050 precedence=SeparatorPrecedence;
2054 if ((precedence == BitwiseComplementPrecedence) ||
2055 (precedence == TernaryPrecedence) ||
2056 (precedence == AssignmentPrecedence))
2058 if (precedence > target)
2061 Right-to-left associativity.
2064 subexpression=expression;
2068 if (precedence >= target)
2071 Left-to-right associativity.
2074 subexpression=expression;
2076 if (strchr("(",(int) *expression) != (char *) NULL)
2077 expression=FxSubexpression(expression,exception);
2078 c=(int) (*expression++);
2080 return(subexpression);
2083 static MagickRealType FxEvaluateSubexpression(FxInfo *fx_info,
2084 const ChannelType channel,const ssize_t x,const ssize_t y,
2085 const char *expression,MagickRealType *beta,ExceptionInfo *exception)
2089 subexpression[MaxTextExtent];
2099 if (exception->severity != UndefinedException)
2101 while (isspace((int) *expression) != 0)
2103 if (*expression == '\0')
2105 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2106 "MissingExpression","`%s'",expression);
2109 *subexpression='\0';
2110 p=FxOperatorPrecedence(expression,exception);
2111 if (p != (const char *) NULL)
2113 (void) CopyMagickString(subexpression,expression,(size_t)
2115 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,beta,
2117 switch ((unsigned char) *p)
2121 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2122 *beta=(MagickRealType) (~(size_t) *beta);
2127 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2128 return(*beta == 0.0 ? 1.0 : 0.0);
2132 *beta=pow((double) alpha,(double) FxEvaluateSubexpression(fx_info,
2133 channel,x,y,++p,beta,exception));
2137 case ExponentialNotation:
2139 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2140 return(alpha*(*beta));
2144 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2147 if (exception->severity == UndefinedException)
2148 (void) ThrowMagickException(exception,GetMagickModule(),
2149 OptionError,"DivideByZero","`%s'",expression);
2152 return(alpha/(*beta));
2156 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2157 *beta=fabs(floor(((double) *beta)+0.5));
2160 (void) ThrowMagickException(exception,GetMagickModule(),
2161 OptionError,"DivideByZero","`%s'",expression);
2164 return(fmod((double) alpha,(double) *beta));
2168 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2169 return(alpha+(*beta));
2173 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2174 return(alpha-(*beta));
2176 case LeftShiftOperator:
2178 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2179 *beta=(MagickRealType) ((size_t) (alpha+0.5) << (size_t)
2183 case RightShiftOperator:
2185 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2186 *beta=(MagickRealType) ((size_t) (alpha+0.5) >> (size_t)
2192 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2193 return(alpha < *beta ? 1.0 : 0.0);
2195 case LessThanEqualOperator:
2197 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2198 return(alpha <= *beta ? 1.0 : 0.0);
2202 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2203 return(alpha > *beta ? 1.0 : 0.0);
2205 case GreaterThanEqualOperator:
2207 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2208 return(alpha >= *beta ? 1.0 : 0.0);
2212 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2213 return(fabs(alpha-(*beta)) <= MagickEpsilon ? 1.0 : 0.0);
2215 case NotEqualOperator:
2217 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2218 return(fabs(alpha-(*beta)) > MagickEpsilon ? 1.0 : 0.0);
2222 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2223 *beta=(MagickRealType) ((size_t) (alpha+0.5) & (size_t)
2229 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2230 *beta=(MagickRealType) ((size_t) (alpha+0.5) | (size_t)
2234 case LogicalAndOperator:
2236 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2237 *beta=(alpha > 0.0) && (gamma > 0.0) ? 1.0 : 0.0;
2240 case LogicalOrOperator:
2242 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2243 *beta=(alpha > 0.0) || (gamma > 0.0) ? 1.0 : 0.0;
2251 (void) CopyMagickString(subexpression,++p,MaxTextExtent);
2253 p=StringToken(":",&q);
2254 if (q == (char *) NULL)
2256 (void) ThrowMagickException(exception,GetMagickModule(),
2257 OptionError,"UnableToParseExpression","`%s'",subexpression);
2260 if (fabs((double) alpha) > MagickEpsilon)
2261 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,beta,exception);
2263 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,q,beta,exception);
2269 numeric[MaxTextExtent];
2272 while (isalpha((int) ((unsigned char) *q)) != 0)
2276 (void) ThrowMagickException(exception,GetMagickModule(),
2277 OptionError,"UnableToParseExpression","`%s'",subexpression);
2280 ClearMagickException(exception);
2281 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2282 (void) FormatMagickString(numeric,MaxTextExtent,"%g",(double)
2284 (void) DeleteNodeFromSplayTree(fx_info->symbols,subexpression);
2285 (void) AddValueToSplayTree(fx_info->symbols,ConstantString(
2286 subexpression),ConstantString(numeric));
2291 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2296 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2301 gamma=alpha*FxEvaluateSubexpression(fx_info,channel,x,y,p,beta,
2307 if (strchr("(",(int) *expression) != (char *) NULL)
2309 (void) CopyMagickString(subexpression,expression+1,MaxTextExtent);
2310 subexpression[strlen(subexpression)-1]='\0';
2311 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,beta,
2315 switch (*expression)
2319 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta,
2325 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta,
2331 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta,
2333 return((MagickRealType) (~(size_t) (gamma+0.5)));
2338 if (LocaleNCompare(expression,"abs",3) == 0)
2340 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2342 return((MagickRealType) fabs((double) alpha));
2344 if (LocaleNCompare(expression,"acos",4) == 0)
2346 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2348 return((MagickRealType) acos((double) alpha));
2350 #if defined(MAGICKCORE_HAVE_J1)
2351 if (LocaleNCompare(expression,"airy",4) == 0)
2353 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2357 gamma=2.0*j1((double) (MagickPI*alpha))/(MagickPI*alpha);
2358 return(gamma*gamma);
2361 if (LocaleNCompare(expression,"asin",4) == 0)
2363 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2365 return((MagickRealType) asin((double) alpha));
2367 if (LocaleNCompare(expression,"alt",3) == 0)
2369 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2371 return(((ssize_t) alpha) & 0x01 ? -1.0 : 1.0);
2373 if (LocaleNCompare(expression,"atan2",5) == 0)
2375 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2377 return((MagickRealType) atan2((double) alpha,(double) *beta));
2379 if (LocaleNCompare(expression,"atan",4) == 0)
2381 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2383 return((MagickRealType) atan((double) alpha));
2385 if (LocaleCompare(expression,"a") == 0)
2386 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2392 if (LocaleCompare(expression,"b") == 0)
2393 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2399 if (LocaleNCompare(expression,"ceil",4) == 0)
2401 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2403 return((MagickRealType) ceil((double) alpha));
2405 if (LocaleNCompare(expression,"cosh",4) == 0)
2407 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2409 return((MagickRealType) cosh((double) alpha));
2411 if (LocaleNCompare(expression,"cos",3) == 0)
2413 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2415 return((MagickRealType) cos((double) alpha));
2417 if (LocaleCompare(expression,"c") == 0)
2418 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2424 if (LocaleNCompare(expression,"debug",5) == 0)
2429 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2431 if (fx_info->images->colorspace == CMYKColorspace)
2434 case CyanChannel: type="cyan"; break;
2435 case MagentaChannel: type="magenta"; break;
2436 case YellowChannel: type="yellow"; break;
2437 case OpacityChannel: type="opacity"; break;
2438 case BlackChannel: type="black"; break;
2439 default: type="unknown"; break;
2444 case RedChannel: type="red"; break;
2445 case GreenChannel: type="green"; break;
2446 case BlueChannel: type="blue"; break;
2447 case OpacityChannel: type="opacity"; break;
2448 default: type="unknown"; break;
2450 (void) CopyMagickString(subexpression,expression+6,MaxTextExtent);
2451 if (strlen(subexpression) > 1)
2452 subexpression[strlen(subexpression)-1]='\0';
2453 if (fx_info->file != (FILE *) NULL)
2454 (void) fprintf(fx_info->file,"%s[%.20g,%.20g].%s: %s=%.*g\n",
2455 fx_info->images->filename,(double) x,(double) y,type,
2456 subexpression,GetMagickPrecision(),(double) alpha);
2464 if (LocaleCompare(expression,"epsilon") == 0)
2465 return((MagickRealType) MagickEpsilon);
2466 if (LocaleNCompare(expression,"exp",3) == 0)
2468 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2470 return((MagickRealType) exp((double) alpha));
2472 if (LocaleCompare(expression,"e") == 0)
2473 return((MagickRealType) 2.7182818284590452354);
2479 if (LocaleNCompare(expression,"floor",5) == 0)
2481 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2483 return((MagickRealType) floor((double) alpha));
2490 if (LocaleCompare(expression,"g") == 0)
2491 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2497 if (LocaleCompare(expression,"h") == 0)
2498 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2499 if (LocaleCompare(expression,"hue") == 0)
2500 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2501 if (LocaleNCompare(expression,"hypot",5) == 0)
2503 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2505 return((MagickRealType) hypot((double) alpha,(double) *beta));
2512 if (LocaleCompare(expression,"k") == 0)
2513 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2519 if (LocaleCompare(expression,"intensity") == 0)
2520 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2521 if (LocaleNCompare(expression,"int",3) == 0)
2523 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2525 return((MagickRealType) floor(alpha));
2527 if (LocaleCompare(expression,"i") == 0)
2528 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2534 if (LocaleCompare(expression,"j") == 0)
2535 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2536 #if defined(MAGICKCORE_HAVE_J0)
2537 if (LocaleNCompare(expression,"j0",2) == 0)
2539 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta,
2541 return((MagickRealType) j0((double) alpha));
2544 #if defined(MAGICKCORE_HAVE_J1)
2545 if (LocaleNCompare(expression,"j1",2) == 0)
2547 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta,
2549 return((MagickRealType) j1((double) alpha));
2552 #if defined(MAGICKCORE_HAVE_J1)
2553 if (LocaleNCompare(expression,"jinc",4) == 0)
2555 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2559 gamma=(MagickRealType) (2.0*j1((double) (MagickPI*alpha))/
2569 if (LocaleNCompare(expression,"ln",2) == 0)
2571 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta,
2573 return((MagickRealType) log((double) alpha));
2575 if (LocaleNCompare(expression,"logtwo",6) == 0)
2577 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,beta,
2579 return((MagickRealType) log10((double) alpha))/log10(2.0);
2581 if (LocaleNCompare(expression,"log",3) == 0)
2583 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2585 return((MagickRealType) log10((double) alpha));
2587 if (LocaleCompare(expression,"lightness") == 0)
2588 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2594 if (LocaleCompare(expression,"MaxRGB") == 0)
2595 return((MagickRealType) QuantumRange);
2596 if (LocaleNCompare(expression,"maxima",6) == 0)
2598 if (LocaleNCompare(expression,"max",3) == 0)
2599 return(FxMax(fx_info,channel,x,y,expression+3,exception));
2600 if (LocaleNCompare(expression,"minima",6) == 0)
2602 if (LocaleNCompare(expression,"min",3) == 0)
2603 return(FxMin(fx_info,channel,x,y,expression+3,exception));
2604 if (LocaleNCompare(expression,"mod",3) == 0)
2606 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2608 return((MagickRealType) fmod((double) alpha,(double) *beta));
2610 if (LocaleCompare(expression,"m") == 0)
2611 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2617 if (LocaleCompare(expression,"n") == 0)
2618 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2624 if (LocaleCompare(expression,"Opaque") == 0)
2626 if (LocaleCompare(expression,"o") == 0)
2627 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2633 if (LocaleCompare(expression,"pi") == 0)
2634 return((MagickRealType) MagickPI);
2635 if (LocaleNCompare(expression,"pow",3) == 0)
2637 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2639 return((MagickRealType) pow((double) alpha,(double) *beta));
2641 if (LocaleCompare(expression,"p") == 0)
2642 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2648 if (LocaleCompare(expression,"QuantumRange") == 0)
2649 return((MagickRealType) QuantumRange);
2650 if (LocaleCompare(expression,"QuantumScale") == 0)
2651 return((MagickRealType) QuantumScale);
2657 if (LocaleNCompare(expression,"rand",4) == 0)
2658 return((MagickRealType) GetPseudoRandomValue(fx_info->random_info));
2659 if (LocaleNCompare(expression,"round",5) == 0)
2661 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2663 return((MagickRealType) floor((double) alpha+0.5));
2665 if (LocaleCompare(expression,"r") == 0)
2666 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2672 if (LocaleCompare(expression,"saturation") == 0)
2673 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2674 if (LocaleNCompare(expression,"sign",4) == 0)
2676 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2678 return(alpha < 0.0 ? -1.0 : 1.0);
2680 if (LocaleNCompare(expression,"sinc",4) == 0)
2682 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2686 gamma=(MagickRealType) (sin((double) (MagickPI*alpha))/
2690 if (LocaleNCompare(expression,"sinh",4) == 0)
2692 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2694 return((MagickRealType) sinh((double) alpha));
2696 if (LocaleNCompare(expression,"sin",3) == 0)
2698 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2700 return((MagickRealType) sin((double) alpha));
2702 if (LocaleNCompare(expression,"sqrt",4) == 0)
2704 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2706 return((MagickRealType) sqrt((double) alpha));
2708 if (LocaleCompare(expression,"s") == 0)
2709 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2715 if (LocaleNCompare(expression,"tanh",4) == 0)
2717 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2719 return((MagickRealType) tanh((double) alpha));
2721 if (LocaleNCompare(expression,"tan",3) == 0)
2723 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2725 return((MagickRealType) tan((double) alpha));
2727 if (LocaleCompare(expression,"Transparent") == 0)
2729 if (LocaleNCompare(expression,"trunc",5) == 0)
2731 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2734 return((MagickRealType) floor((double) alpha));
2735 return((MagickRealType) ceil((double) alpha));
2737 if (LocaleCompare(expression,"t") == 0)
2738 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2744 if (LocaleCompare(expression,"u") == 0)
2745 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2751 if (LocaleCompare(expression,"v") == 0)
2752 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2758 if (LocaleCompare(expression,"w") == 0)
2759 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2765 if (LocaleCompare(expression,"y") == 0)
2766 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2772 if (LocaleCompare(expression,"z") == 0)
2773 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2779 q=(char *) expression;
2780 alpha=strtod(expression,&q);
2781 if (q == expression)
2782 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2786 MagickExport MagickBooleanType FxEvaluateExpression(FxInfo *fx_info,
2787 MagickRealType *alpha,ExceptionInfo *exception)
2792 status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
2796 MagickExport MagickBooleanType FxPreprocessExpression(FxInfo *fx_info,
2797 MagickRealType *alpha,ExceptionInfo *exception)
2806 fx_info->file=(FILE *) NULL;
2807 status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
2812 MagickExport MagickBooleanType FxEvaluateChannelExpression(FxInfo *fx_info,
2813 const ChannelType channel,const ssize_t x,const ssize_t y,
2814 MagickRealType *alpha,ExceptionInfo *exception)
2820 *alpha=FxEvaluateSubexpression(fx_info,channel,x,y,fx_info->expression,&beta,
2822 return(exception->severity == OptionError ? MagickFalse : MagickTrue);
2826 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2836 % FxImage() applies a mathematical expression to the specified image.
2838 % The format of the FxImage method is:
2840 % Image *FxImage(const Image *image,const char *expression,
2841 % ExceptionInfo *exception)
2842 % Image *FxImageChannel(const Image *image,const ChannelType channel,
2843 % const char *expression,ExceptionInfo *exception)
2845 % A description of each parameter follows:
2847 % o image: the image.
2849 % o channel: the channel.
2851 % o expression: A mathematical expression.
2853 % o exception: return any errors or warnings in this structure.
2857 static FxInfo **DestroyFxThreadSet(FxInfo **fx_info)
2862 assert(fx_info != (FxInfo **) NULL);
2863 for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
2864 if (fx_info[i] != (FxInfo *) NULL)
2865 fx_info[i]=DestroyFxInfo(fx_info[i]);
2866 fx_info=(FxInfo **) RelinquishMagickMemory(fx_info);
2870 static FxInfo **AcquireFxThreadSet(const Image *image,const char *expression,
2871 ExceptionInfo *exception)
2888 number_threads=GetOpenMPMaximumThreads();
2889 fx_info=(FxInfo **) AcquireQuantumMemory(number_threads,sizeof(*fx_info));
2890 if (fx_info == (FxInfo **) NULL)
2891 return((FxInfo **) NULL);
2892 (void) ResetMagickMemory(fx_info,0,number_threads*sizeof(*fx_info));
2893 if (*expression != '@')
2894 fx_expression=ConstantString(expression);
2896 fx_expression=FileToString(expression+1,~0,exception);
2897 for (i=0; i < (ssize_t) number_threads; i++)
2899 fx_info[i]=AcquireFxInfo(image,fx_expression);
2900 if (fx_info[i] == (FxInfo *) NULL)
2901 return(DestroyFxThreadSet(fx_info));
2902 (void) FxPreprocessExpression(fx_info[i],&alpha,fx_info[i]->exception);
2904 fx_expression=DestroyString(fx_expression);
2908 MagickExport Image *FxImage(const Image *image,const char *expression,
2909 ExceptionInfo *exception)
2914 fx_image=FxImageChannel(image,GrayChannel,expression,exception);
2918 MagickExport Image *FxImageChannel(const Image *image,const ChannelType channel,
2919 const char *expression,ExceptionInfo *exception)
2921 #define FxImageTag "Fx/Image"
2944 assert(image != (Image *) NULL);
2945 assert(image->signature == MagickSignature);
2946 if (image->debug != MagickFalse)
2947 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2948 fx_image=CloneImage(image,0,0,MagickTrue,exception);
2949 if (fx_image == (Image *) NULL)
2950 return((Image *) NULL);
2951 if (SetImageStorageClass(fx_image,DirectClass) == MagickFalse)
2953 InheritException(exception,&fx_image->exception);
2954 fx_image=DestroyImage(fx_image);
2955 return((Image *) NULL);
2957 fx_info=AcquireFxThreadSet(image,expression,exception);
2958 if (fx_info == (FxInfo **) NULL)
2960 fx_image=DestroyImage(fx_image);
2961 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2963 status=FxPreprocessExpression(fx_info[0],&alpha,exception);
2964 if (status == MagickFalse)
2966 fx_image=DestroyImage(fx_image);
2967 fx_info=DestroyFxThreadSet(fx_info);
2968 return((Image *) NULL);
2975 fx_view=AcquireCacheView(fx_image);
2976 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2977 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2979 for (y=0; y < (ssize_t) fx_image->rows; y++)
2982 id = GetOpenMPThreadId();
2987 register IndexPacket
2988 *restrict fx_indexes;
2993 register PixelPacket
2996 if (status == MagickFalse)
2998 q=GetCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception);
2999 if (q == (PixelPacket *) NULL)
3004 fx_indexes=GetCacheViewAuthenticIndexQueue(fx_view);
3006 for (x=0; x < (ssize_t) fx_image->columns; x++)
3008 if ((channel & RedChannel) != 0)
3010 (void) FxEvaluateChannelExpression(fx_info[id],RedChannel,x,y,
3012 SetRedPixelComponent(q,ClampToQuantum((MagickRealType) QuantumRange*
3015 if ((channel & GreenChannel) != 0)
3017 (void) FxEvaluateChannelExpression(fx_info[id],GreenChannel,x,y,
3019 SetGreenPixelComponent(q,ClampToQuantum((MagickRealType) QuantumRange*
3022 if ((channel & BlueChannel) != 0)
3024 (void) FxEvaluateChannelExpression(fx_info[id],BlueChannel,x,y,
3026 SetBluePixelComponent(q,ClampToQuantum((MagickRealType) QuantumRange*
3029 if ((channel & OpacityChannel) != 0)
3031 (void) FxEvaluateChannelExpression(fx_info[id],OpacityChannel,x,y,
3033 if (image->matte == MagickFalse)
3034 SetOpacityPixelComponent(q,ClampToQuantum((MagickRealType)
3035 QuantumRange*alpha));
3037 SetOpacityPixelComponent(q,ClampToQuantum((MagickRealType)
3038 (QuantumRange-QuantumRange*alpha)));
3040 if (((channel & IndexChannel) != 0) &&
3041 (fx_image->colorspace == CMYKColorspace))
3043 (void) FxEvaluateChannelExpression(fx_info[id],IndexChannel,x,y,
3045 SetIndexPixelComponent(fx_indexes+x,ClampToQuantum((MagickRealType)
3046 QuantumRange*alpha));
3050 if (SyncCacheViewAuthenticPixels(fx_view,exception) == MagickFalse)
3052 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3057 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3058 #pragma omp critical (MagickCore_FxImageChannel)
3060 proceed=SetImageProgress(image,FxImageTag,progress++,image->rows);
3061 if (proceed == MagickFalse)
3065 fx_view=DestroyCacheView(fx_view);
3066 fx_info=DestroyFxThreadSet(fx_info);
3067 if (status == MagickFalse)
3068 fx_image=DestroyImage(fx_image);
3073 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3077 % I m p l o d e I m a g e %
3081 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3083 % ImplodeImage() creates a new image that is a copy of an existing
3084 % one with the image pixels "implode" by the specified percentage. It
3085 % allocates the memory necessary for the new Image structure and returns a
3086 % pointer to the new image.
3088 % The format of the ImplodeImage method is:
3090 % Image *ImplodeImage(const Image *image,const double amount,
3091 % ExceptionInfo *exception)
3093 % A description of each parameter follows:
3095 % o implode_image: Method ImplodeImage returns a pointer to the image
3096 % after it is implode. A null image is returned if there is a memory
3099 % o image: the image.
3101 % o amount: Define the extent of the implosion.
3103 % o exception: return any errors or warnings in this structure.
3106 MagickExport Image *ImplodeImage(const Image *image,const double amount,
3107 ExceptionInfo *exception)
3109 #define ImplodeImageTag "Implode/Image"
3138 Initialize implode image attributes.
3140 assert(image != (Image *) NULL);
3141 assert(image->signature == MagickSignature);
3142 if (image->debug != MagickFalse)
3143 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3144 assert(exception != (ExceptionInfo *) NULL);
3145 assert(exception->signature == MagickSignature);
3146 implode_image=CloneImage(image,0,0,MagickTrue,exception);
3147 if (implode_image == (Image *) NULL)
3148 return((Image *) NULL);
3149 if (SetImageStorageClass(implode_image,DirectClass) == MagickFalse)
3151 InheritException(exception,&implode_image->exception);
3152 implode_image=DestroyImage(implode_image);
3153 return((Image *) NULL);
3155 if (implode_image->background_color.opacity != OpaqueOpacity)
3156 implode_image->matte=MagickTrue;
3158 Compute scaling factor.
3162 center.x=0.5*image->columns;
3163 center.y=0.5*image->rows;
3165 if (image->columns > image->rows)
3166 scale.y=(double) image->columns/(double) image->rows;
3168 if (image->columns < image->rows)
3170 scale.x=(double) image->rows/(double) image->columns;
3178 GetMagickPixelPacket(implode_image,&zero);
3179 image_view=AcquireCacheView(image);
3180 implode_view=AcquireCacheView(implode_image);
3181 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3182 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
3184 for (y=0; y < (ssize_t) image->rows; y++)
3195 register IndexPacket
3196 *restrict implode_indexes;
3201 register PixelPacket
3204 if (status == MagickFalse)
3206 q=GetCacheViewAuthenticPixels(implode_view,0,y,implode_image->columns,1,
3208 if (q == (PixelPacket *) NULL)
3213 implode_indexes=GetCacheViewAuthenticIndexQueue(implode_view);
3214 delta.y=scale.y*(double) (y-center.y);
3216 for (x=0; x < (ssize_t) image->columns; x++)
3219 Determine if the pixel is within an ellipse.
3221 delta.x=scale.x*(double) (x-center.x);
3222 distance=delta.x*delta.x+delta.y*delta.y;
3223 if (distance < (radius*radius))
3233 factor=pow(sin((double) (MagickPI*sqrt((double) distance)/
3234 radius/2)),-amount);
3235 (void) InterpolateMagickPixelPacket(image,image_view,
3236 UndefinedInterpolatePixel,(double) (factor*delta.x/scale.x+
3237 center.x),(double) (factor*delta.y/scale.y+center.y),&pixel,
3239 SetPixelPacket(implode_image,&pixel,q,implode_indexes+x);
3243 if (SyncCacheViewAuthenticPixels(implode_view,exception) == MagickFalse)
3245 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3250 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3251 #pragma omp critical (MagickCore_ImplodeImage)
3253 proceed=SetImageProgress(image,ImplodeImageTag,progress++,image->rows);
3254 if (proceed == MagickFalse)
3258 implode_view=DestroyCacheView(implode_view);
3259 image_view=DestroyCacheView(image_view);
3260 if (status == MagickFalse)
3261 implode_image=DestroyImage(implode_image);
3262 return(implode_image);
3266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3270 % M o r p h I m a g e s %
3274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3276 % The MorphImages() method requires a minimum of two images. The first
3277 % image is transformed into the second by a number of intervening images
3278 % as specified by frames.
3280 % The format of the MorphImage method is:
3282 % Image *MorphImages(const Image *image,const size_t number_frames,
3283 % ExceptionInfo *exception)
3285 % A description of each parameter follows:
3287 % o image: the image.
3289 % o number_frames: Define the number of in-between image to generate.
3290 % The more in-between frames, the smoother the morph.
3292 % o exception: return any errors or warnings in this structure.
3295 MagickExport Image *MorphImages(const Image *image,
3296 const size_t number_frames,ExceptionInfo *exception)
3298 #define MorphImageTag "Morph/Image"
3314 register const Image
3324 Clone first frame in sequence.
3326 assert(image != (Image *) NULL);
3327 assert(image->signature == MagickSignature);
3328 if (image->debug != MagickFalse)
3329 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3330 assert(exception != (ExceptionInfo *) NULL);
3331 assert(exception->signature == MagickSignature);
3332 morph_images=CloneImage(image,0,0,MagickTrue,exception);
3333 if (morph_images == (Image *) NULL)
3334 return((Image *) NULL);
3335 if (GetNextImageInList(image) == (Image *) NULL)
3340 for (i=1; i < (ssize_t) number_frames; i++)
3342 morph_image=CloneImage(image,0,0,MagickTrue,exception);
3343 if (morph_image == (Image *) NULL)
3345 morph_images=DestroyImageList(morph_images);
3346 return((Image *) NULL);
3348 AppendImageToList(&morph_images,morph_image);
3349 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3354 proceed=SetImageProgress(image,MorphImageTag,(MagickOffsetType) i,
3356 if (proceed == MagickFalse)
3360 return(GetFirstImageInList(morph_images));
3363 Morph image sequence.
3368 for ( ; GetNextImageInList(next) != (Image *) NULL; next=GetNextImageInList(next))
3370 for (i=0; i < (ssize_t) number_frames; i++)
3376 beta=(MagickRealType) (i+1.0)/(MagickRealType) (number_frames+1.0);
3378 morph_image=ResizeImage(next,(size_t) (alpha*next->columns+beta*
3379 GetNextImageInList(next)->columns+0.5),(size_t) (alpha*
3380 next->rows+beta*GetNextImageInList(next)->rows+0.5),
3381 next->filter,next->blur,exception);
3382 if (morph_image == (Image *) NULL)
3384 morph_images=DestroyImageList(morph_images);
3385 return((Image *) NULL);
3387 if (SetImageStorageClass(morph_image,DirectClass) == MagickFalse)
3389 InheritException(exception,&morph_image->exception);
3390 morph_image=DestroyImage(morph_image);
3391 return((Image *) NULL);
3393 AppendImageToList(&morph_images,morph_image);
3394 morph_images=GetLastImageInList(morph_images);
3395 morph_image=ResizeImage(GetNextImageInList(next),morph_images->columns,
3396 morph_images->rows,GetNextImageInList(next)->filter,
3397 GetNextImageInList(next)->blur,exception);
3398 if (morph_image == (Image *) NULL)
3400 morph_images=DestroyImageList(morph_images);
3401 return((Image *) NULL);
3403 image_view=AcquireCacheView(morph_image);
3404 morph_view=AcquireCacheView(morph_images);
3405 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3406 #pragma omp parallel for schedule(dynamic,4) shared(status)
3408 for (y=0; y < (ssize_t) morph_images->rows; y++)
3413 register const PixelPacket
3419 register PixelPacket
3422 if (status == MagickFalse)
3424 p=GetCacheViewVirtualPixels(image_view,0,y,morph_image->columns,1,
3426 q=GetCacheViewAuthenticPixels(morph_view,0,y,morph_images->columns,1,
3428 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
3433 for (x=0; x < (ssize_t) morph_images->columns; x++)
3435 SetRedPixelComponent(q,ClampToQuantum(alpha*
3436 GetRedPixelComponent(q)+beta*GetRedPixelComponent(p)));
3437 SetGreenPixelComponent(q,ClampToQuantum(alpha*
3438 GetGreenPixelComponent(q)+beta*GetGreenPixelComponent(p)));
3439 SetBluePixelComponent(q,ClampToQuantum(alpha*
3440 GetBluePixelComponent(q)+beta*GetBluePixelComponent(p)));
3441 SetOpacityPixelComponent(q,ClampToQuantum(alpha*
3442 GetOpacityPixelComponent(q)+beta*GetOpacityPixelComponent(p)));
3446 sync=SyncCacheViewAuthenticPixels(morph_view,exception);
3447 if (sync == MagickFalse)
3450 morph_view=DestroyCacheView(morph_view);
3451 image_view=DestroyCacheView(image_view);
3452 morph_image=DestroyImage(morph_image);
3454 if (i < (ssize_t) number_frames)
3457 Clone last frame in sequence.
3459 morph_image=CloneImage(GetNextImageInList(next),0,0,MagickTrue,exception);
3460 if (morph_image == (Image *) NULL)
3462 morph_images=DestroyImageList(morph_images);
3463 return((Image *) NULL);
3465 AppendImageToList(&morph_images,morph_image);
3466 morph_images=GetLastImageInList(morph_images);
3467 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3472 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3473 #pragma omp critical (MagickCore_MorphImages)
3475 proceed=SetImageProgress(image,MorphImageTag,scene,
3476 GetImageListLength(image));
3477 if (proceed == MagickFalse)
3482 if (GetNextImageInList(next) != (Image *) NULL)
3484 morph_images=DestroyImageList(morph_images);
3485 return((Image *) NULL);
3487 return(GetFirstImageInList(morph_images));
3491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3495 % P l a s m a I m a g e %
3499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3501 % PlasmaImage() initializes an image with plasma fractal values. The image
3502 % must be initialized with a base color and the random number generator
3503 % seeded before this method is called.
3505 % The format of the PlasmaImage method is:
3507 % MagickBooleanType PlasmaImage(Image *image,const SegmentInfo *segment,
3508 % size_t attenuate,size_t depth)
3510 % A description of each parameter follows:
3512 % o image: the image.
3514 % o segment: Define the region to apply plasma fractals values.
3516 % o attenuate: Define the plasma attenuation factor.
3518 % o depth: Limit the plasma recursion depth.
3522 static inline Quantum PlasmaPixel(RandomInfo *random_info,
3523 const MagickRealType pixel,const MagickRealType noise)
3528 plasma=ClampToQuantum(pixel+noise*GetPseudoRandomValue(random_info)-
3533 MagickExport MagickBooleanType PlasmaImageProxy(Image *image,
3534 CacheView *image_view,RandomInfo *random_info,const SegmentInfo *segment,
3535 size_t attenuate,size_t depth)
3553 if (((segment->x2-segment->x1) == 0.0) && ((segment->y2-segment->y1) == 0.0))
3561 Divide the area into quadrants and recurse.
3565 x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5);
3566 y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5);
3567 local_info=(*segment);
3568 local_info.x2=(double) x_mid;
3569 local_info.y2=(double) y_mid;
3570 (void) PlasmaImageProxy(image,image_view,random_info,&local_info,
3572 local_info=(*segment);
3573 local_info.y1=(double) y_mid;
3574 local_info.x2=(double) x_mid;
3575 (void) PlasmaImageProxy(image,image_view,random_info,&local_info,
3577 local_info=(*segment);
3578 local_info.x1=(double) x_mid;
3579 local_info.y2=(double) y_mid;
3580 (void) PlasmaImageProxy(image,image_view,random_info,&local_info,
3582 local_info=(*segment);
3583 local_info.x1=(double) x_mid;
3584 local_info.y1=(double) y_mid;
3585 return(PlasmaImageProxy(image,image_view,random_info,&local_info,
3588 x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5);
3589 y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5);
3590 if ((segment->x1 == (double) x_mid) && (segment->x2 == (double) x_mid) &&
3591 (segment->y1 == (double) y_mid) && (segment->y2 == (double) y_mid))
3592 return(MagickFalse);
3594 Average pixels and apply plasma.
3596 exception=(&image->exception);
3597 plasma=(MagickRealType) QuantumRange/(2.0*attenuate);
3598 if ((segment->x1 != (double) x_mid) || (segment->x2 != (double) x_mid))
3600 register PixelPacket
3606 x=(ssize_t) ceil(segment->x1-0.5);
3607 (void) GetOneCacheViewVirtualPixel(image_view,x,(ssize_t)
3608 ceil(segment->y1-0.5),&u,exception);
3609 (void) GetOneCacheViewVirtualPixel(image_view,x,(ssize_t)
3610 ceil(segment->y2-0.5),&v,exception);
3611 q=QueueCacheViewAuthenticPixels(image_view,x,y_mid,1,1,exception);
3612 if (q == (PixelPacket *) NULL)
3614 SetRedPixelComponent(q,PlasmaPixel(random_info,(MagickRealType)
3615 (u.red+v.red)/2.0,plasma));
3616 SetGreenPixelComponent(q,PlasmaPixel(random_info,(MagickRealType)
3617 (u.green+v.green)/2.0,plasma));
3618 SetBluePixelComponent(q,PlasmaPixel(random_info,(MagickRealType)
3619 (u.blue+v.blue)/2.0,plasma));
3620 (void) SyncCacheViewAuthenticPixels(image_view,exception);
3621 if (segment->x1 != segment->x2)
3626 x=(ssize_t) ceil(segment->x2-0.5);
3627 (void) GetOneCacheViewVirtualPixel(image_view,x,(ssize_t)
3628 ceil(segment->y1-0.5),&u,exception);
3629 (void) GetOneCacheViewVirtualPixel(image_view,x,(ssize_t)
3630 ceil(segment->y2-0.5),&v,exception);
3631 q=QueueCacheViewAuthenticPixels(image_view,x,y_mid,1,1,exception);
3632 if (q == (PixelPacket *) NULL)
3634 SetRedPixelComponent(q,PlasmaPixel(random_info,(MagickRealType)
3635 (u.red+v.red)/2.0,plasma));
3636 SetGreenPixelComponent(q,PlasmaPixel(random_info,(MagickRealType)
3637 (u.green+v.green)/2.0,plasma));
3638 SetBluePixelComponent(q,PlasmaPixel(random_info,(MagickRealType)
3639 (u.blue+v.blue)/2.0,plasma));
3640 (void) SyncCacheViewAuthenticPixels(image_view,exception);
3643 if ((segment->y1 != (double) y_mid) || (segment->y2 != (double) y_mid))
3645 if ((segment->x1 != (double) x_mid) || (segment->y2 != (double) y_mid))
3647 register PixelPacket
3653 y=(ssize_t) ceil(segment->y2-0.5);
3654 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
3655 ceil(segment->x1-0.5),y,&u,exception);
3656 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
3657 ceil(segment->x2-0.5),y,&v,exception);
3658 q=QueueCacheViewAuthenticPixels(image_view,x_mid,y,1,1,exception);
3659 if (q == (PixelPacket *) NULL)
3661 SetRedPixelComponent(q,PlasmaPixel(random_info,(MagickRealType)
3662 (u.red+v.red)/2.0,plasma));
3663 SetGreenPixelComponent(q,PlasmaPixel(random_info,(MagickRealType)
3664 (u.green+v.green)/2.0,plasma));
3665 SetBluePixelComponent(q,PlasmaPixel(random_info,(MagickRealType)
3666 (u.blue+v.blue)/2.0,plasma));
3667 (void) SyncCacheViewAuthenticPixels(image_view,exception);
3669 if (segment->y1 != segment->y2)
3671 register PixelPacket
3677 y=(ssize_t) ceil(segment->y1-0.5);
3678 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
3679 ceil(segment->x1-0.5),y,&u,exception);
3680 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
3681 ceil(segment->x2-0.5),y,&v,exception);
3682 q=QueueCacheViewAuthenticPixels(image_view,x_mid,y,1,1,exception);
3683 if (q == (PixelPacket *) NULL)
3685 SetRedPixelComponent(q,PlasmaPixel(random_info,(MagickRealType)
3686 (u.red+v.red)/2.0,plasma));
3687 SetGreenPixelComponent(q,PlasmaPixel(random_info,(MagickRealType)
3688 (u.green+v.green)/2.0,plasma));
3689 SetBluePixelComponent(q,PlasmaPixel(random_info,(MagickRealType)
3690 (u.blue+v.blue)/2.0,plasma));
3691 (void) SyncCacheViewAuthenticPixels(image_view,exception);
3694 if ((segment->x1 != segment->x2) || (segment->y1 != segment->y2))
3696 register PixelPacket
3702 x=(ssize_t) ceil(segment->x1-0.5);
3703 y=(ssize_t) ceil(segment->y1-0.5);
3704 (void) GetOneVirtualPixel(image,x,y,&u,exception);
3705 x=(ssize_t) ceil(segment->x2-0.5);
3706 y=(ssize_t) ceil(segment->y2-0.5);
3707 (void) GetOneCacheViewVirtualPixel(image_view,x,y,&v,exception);
3708 q=QueueCacheViewAuthenticPixels(image_view,x_mid,y_mid,1,1,exception);
3709 if (q == (PixelPacket *) NULL)
3711 SetRedPixelComponent(q,PlasmaPixel(random_info,(MagickRealType)
3712 (u.red+v.red)/2.0,plasma));
3713 SetGreenPixelComponent(q,PlasmaPixel(random_info,(MagickRealType)
3714 (u.green+v.green)/2.0,plasma));
3715 SetBluePixelComponent(q,PlasmaPixel(random_info,(MagickRealType)
3716 (u.blue+v.blue)/2.0,plasma));
3717 (void) SyncCacheViewAuthenticPixels(image_view,exception);
3719 if (((segment->x2-segment->x1) < 3.0) && ((segment->y2-segment->y1) < 3.0))
3721 return(MagickFalse);
3724 MagickExport MagickBooleanType PlasmaImage(Image *image,
3725 const SegmentInfo *segment,size_t attenuate,size_t depth)
3736 if (image->debug != MagickFalse)
3737 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3738 assert(image != (Image *) NULL);
3739 assert(image->signature == MagickSignature);
3740 if (image->debug != MagickFalse)
3741 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3742 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
3743 return(MagickFalse);
3744 image_view=AcquireCacheView(image);
3745 random_info=AcquireRandomInfo();
3746 status=PlasmaImageProxy(image,image_view,random_info,segment,attenuate,depth);
3747 random_info=DestroyRandomInfo(random_info);
3748 image_view=DestroyCacheView(image_view);
3753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3757 % P o l a r o i d I m a g e %
3761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3763 % PolaroidImage() simulates a Polaroid picture.
3765 % The format of the AnnotateImage method is:
3767 % Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
3768 % const double angle,ExceptionInfo exception)
3770 % A description of each parameter follows:
3772 % o image: the image.
3774 % o draw_info: the draw info.
3776 % o angle: Apply the effect along this angle.
3778 % o exception: return any errors or warnings in this structure.
3781 MagickExport Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
3782 const double angle,ExceptionInfo *exception)
3803 Simulate a Polaroid picture.
3805 assert(image != (Image *) NULL);
3806 assert(image->signature == MagickSignature);
3807 if (image->debug != MagickFalse)
3808 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3809 assert(exception != (ExceptionInfo *) NULL);
3810 assert(exception->signature == MagickSignature);
3811 quantum=(ssize_t) MagickMax(MagickMax((double) image->columns,(double)
3812 image->rows)/25.0,10.0);
3813 height=image->rows+2*quantum;
3814 caption_image=(Image *) NULL;
3815 value=GetImageProperty(image,"Caption");
3816 if (value != (const char *) NULL)
3820 geometry[MaxTextExtent];
3835 Generate caption image.
3837 caption_image=CloneImage(image,image->columns,1,MagickTrue,exception);
3838 if (caption_image == (Image *) NULL)
3839 return((Image *) NULL);
3840 annotate_info=CloneDrawInfo((const ImageInfo *) NULL,draw_info);
3841 caption=InterpretImageProperties((ImageInfo *) NULL,(Image *) image,
3843 (void) CloneString(&annotate_info->text,caption);
3844 count=FormatMagickCaption(caption_image,annotate_info,MagickTrue,&metrics,
3846 status=SetImageExtent(caption_image,image->columns,(size_t)
3847 ((count+1)*(metrics.ascent-metrics.descent)+0.5));
3848 if (status == MagickFalse)
3849 caption_image=DestroyImage(caption_image);
3852 caption_image->background_color=image->border_color;
3853 (void) SetImageBackgroundColor(caption_image);
3854 (void) CloneString(&annotate_info->text,caption);
3855 (void) FormatMagickString(geometry,MaxTextExtent,"+0+%g",
3857 if (annotate_info->gravity == UndefinedGravity)
3858 (void) CloneString(&annotate_info->geometry,AcquireString(
3860 (void) AnnotateImage(caption_image,annotate_info);
3861 height+=caption_image->rows;
3863 annotate_info=DestroyDrawInfo(annotate_info);
3864 caption=DestroyString(caption);
3866 picture_image=CloneImage(image,image->columns+2*quantum,height,MagickTrue,
3868 if (picture_image == (Image *) NULL)
3870 if (caption_image != (Image *) NULL)
3871 caption_image=DestroyImage(caption_image);
3872 return((Image *) NULL);
3874 picture_image->background_color=image->border_color;
3875 (void) SetImageBackgroundColor(picture_image);
3876 (void) CompositeImage(picture_image,OverCompositeOp,image,quantum,quantum);
3877 if (caption_image != (Image *) NULL)
3879 (void) CompositeImage(picture_image,OverCompositeOp,caption_image,
3880 quantum,(ssize_t) (image->rows+3*quantum/2));
3881 caption_image=DestroyImage(caption_image);
3883 (void) QueryColorDatabase("none",&picture_image->background_color,exception);
3884 (void) SetImageAlphaChannel(picture_image,OpaqueAlphaChannel);
3885 rotate_image=RotateImage(picture_image,90.0,exception);
3886 picture_image=DestroyImage(picture_image);
3887 if (rotate_image == (Image *) NULL)
3888 return((Image *) NULL);
3889 picture_image=rotate_image;
3890 bend_image=WaveImage(picture_image,0.01*picture_image->rows,2.0*
3891 picture_image->columns,exception);
3892 picture_image=DestroyImage(picture_image);
3893 if (bend_image == (Image *) NULL)
3894 return((Image *) NULL);
3895 InheritException(&bend_image->exception,exception);
3896 picture_image=bend_image;
3897 rotate_image=RotateImage(picture_image,-90.0,exception);
3898 picture_image=DestroyImage(picture_image);
3899 if (rotate_image == (Image *) NULL)
3900 return((Image *) NULL);
3901 picture_image=rotate_image;
3902 picture_image->background_color=image->background_color;
3903 polaroid_image=ShadowImage(picture_image,80.0,2.0,quantum/3,quantum/3,
3905 if (polaroid_image == (Image *) NULL)
3907 picture_image=DestroyImage(picture_image);
3908 return(picture_image);
3910 flop_image=FlopImage(polaroid_image,exception);
3911 polaroid_image=DestroyImage(polaroid_image);
3912 if (flop_image == (Image *) NULL)
3914 picture_image=DestroyImage(picture_image);
3915 return(picture_image);
3917 polaroid_image=flop_image;
3918 (void) CompositeImage(polaroid_image,OverCompositeOp,picture_image,
3919 (ssize_t) (-0.01*picture_image->columns/2.0),0L);
3920 picture_image=DestroyImage(picture_image);
3921 (void) QueryColorDatabase("none",&polaroid_image->background_color,exception);
3922 rotate_image=RotateImage(polaroid_image,angle,exception);
3923 polaroid_image=DestroyImage(polaroid_image);
3924 if (rotate_image == (Image *) NULL)
3925 return((Image *) NULL);
3926 polaroid_image=rotate_image;
3927 trim_image=TrimImage(polaroid_image,exception);
3928 polaroid_image=DestroyImage(polaroid_image);
3929 if (trim_image == (Image *) NULL)
3930 return((Image *) NULL);
3931 polaroid_image=trim_image;
3932 return(polaroid_image);
3936 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3940 % S e p i a T o n e I m a g e %
3944 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3946 % MagickSepiaToneImage() applies a special effect to the image, similar to the
3947 % effect achieved in a photo darkroom by sepia toning. Threshold ranges from
3948 % 0 to QuantumRange and is a measure of the extent of the sepia toning. A
3949 % threshold of 80% is a good starting point for a reasonable tone.
3951 % The format of the SepiaToneImage method is:
3953 % Image *SepiaToneImage(const Image *image,const double threshold,
3954 % ExceptionInfo *exception)
3956 % A description of each parameter follows:
3958 % o image: the image.
3960 % o threshold: the tone threshold.
3962 % o exception: return any errors or warnings in this structure.
3965 MagickExport Image *SepiaToneImage(const Image *image,const double threshold,
3966 ExceptionInfo *exception)
3968 #define SepiaToneImageTag "SepiaTone/Image"
3987 Initialize sepia-toned image attributes.
3989 assert(image != (const Image *) NULL);
3990 assert(image->signature == MagickSignature);
3991 if (image->debug != MagickFalse)
3992 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3993 assert(exception != (ExceptionInfo *) NULL);
3994 assert(exception->signature == MagickSignature);
3995 sepia_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
3996 if (sepia_image == (Image *) NULL)
3997 return((Image *) NULL);
3998 if (SetImageStorageClass(sepia_image,DirectClass) == MagickFalse)
4000 InheritException(exception,&sepia_image->exception);
4001 sepia_image=DestroyImage(sepia_image);
4002 return((Image *) NULL);
4005 Tone each row of the image.
4009 image_view=AcquireCacheView(image);
4010 sepia_view=AcquireCacheView(sepia_image);
4011 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4012 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
4014 for (y=0; y < (ssize_t) image->rows; y++)
4016 register const PixelPacket
4022 register PixelPacket
4025 if (status == MagickFalse)
4027 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4028 q=QueueCacheViewAuthenticPixels(sepia_view,0,y,sepia_image->columns,1,
4030 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
4035 for (x=0; x < (ssize_t) image->columns; x++)
4041 intensity=(MagickRealType) PixelIntensityToQuantum(p);
4042 tone=intensity > threshold ? (MagickRealType) QuantumRange : intensity+
4043 (MagickRealType) QuantumRange-threshold;
4044 SetRedPixelComponent(q,ClampToQuantum(tone));
4045 tone=intensity > (7.0*threshold/6.0) ? (MagickRealType) QuantumRange :
4046 intensity+(MagickRealType) QuantumRange-7.0*threshold/6.0;
4047 SetGreenPixelComponent(q,ClampToQuantum(tone));
4048 tone=intensity < (threshold/6.0) ? 0 : intensity-threshold/6.0;
4049 SetBluePixelComponent(q,ClampToQuantum(tone));
4051 if ((MagickRealType) GetGreenPixelComponent(q) < tone)
4052 SetGreenPixelComponent(q,ClampToQuantum(tone));
4053 if ((MagickRealType) GetBluePixelComponent(q) < tone)
4054 SetBluePixelComponent(q,ClampToQuantum(tone));
4058 if (SyncCacheViewAuthenticPixels(sepia_view,exception) == MagickFalse)
4060 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4065 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4066 #pragma omp critical (MagickCore_SepiaToneImage)
4068 proceed=SetImageProgress(image,SepiaToneImageTag,progress++,
4070 if (proceed == MagickFalse)
4074 sepia_view=DestroyCacheView(sepia_view);
4075 image_view=DestroyCacheView(image_view);
4076 (void) NormalizeImage(sepia_image);
4077 (void) ContrastImage(sepia_image,MagickTrue);
4078 if (status == MagickFalse)
4079 sepia_image=DestroyImage(sepia_image);
4080 return(sepia_image);
4084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4088 % S h a d o w I m a g e %
4092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4094 % ShadowImage() simulates a shadow from the specified image and returns it.
4096 % The format of the ShadowImage method is:
4098 % Image *ShadowImage(const Image *image,const double opacity,
4099 % const double sigma,const ssize_t x_offset,const ssize_t y_offset,
4100 % ExceptionInfo *exception)
4102 % A description of each parameter follows:
4104 % o image: the image.
4106 % o opacity: percentage transparency.
4108 % o sigma: the standard deviation of the Gaussian, in pixels.
4110 % o x_offset: the shadow x-offset.
4112 % o y_offset: the shadow y-offset.
4114 % o exception: return any errors or warnings in this structure.
4117 MagickExport Image *ShadowImage(const Image *image,const double opacity,
4118 const double sigma,const ssize_t x_offset,const ssize_t y_offset,
4119 ExceptionInfo *exception)
4121 #define ShadowImageTag "Shadow/Image"
4143 assert(image != (Image *) NULL);
4144 assert(image->signature == MagickSignature);
4145 if (image->debug != MagickFalse)
4146 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4147 assert(exception != (ExceptionInfo *) NULL);
4148 assert(exception->signature == MagickSignature);
4149 clone_image=CloneImage(image,0,0,MagickTrue,exception);
4150 if (clone_image == (Image *) NULL)
4151 return((Image *) NULL);
4152 (void) SetImageVirtualPixelMethod(clone_image,EdgeVirtualPixelMethod);
4153 clone_image->compose=OverCompositeOp;
4154 border_info.width=(size_t) floor(2.0*sigma+0.5);
4155 border_info.height=(size_t) floor(2.0*sigma+0.5);
4158 (void) QueryColorDatabase("none",&clone_image->border_color,exception);
4159 border_image=BorderImage(clone_image,&border_info,exception);
4160 clone_image=DestroyImage(clone_image);
4161 if (border_image == (Image *) NULL)
4162 return((Image *) NULL);
4163 if (border_image->matte == MagickFalse)
4164 (void) SetImageAlphaChannel(border_image,OpaqueAlphaChannel);
4170 image_view=AcquireCacheView(border_image);
4171 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4172 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
4174 for (y=0; y < (ssize_t) border_image->rows; y++)
4179 register PixelPacket
4182 if (status == MagickFalse)
4184 q=GetCacheViewAuthenticPixels(image_view,0,y,border_image->columns,1,
4186 if (q == (PixelPacket *) NULL)
4191 for (x=0; x < (ssize_t) border_image->columns; x++)
4193 SetRedPixelComponent(q,border_image->background_color.red);
4194 SetGreenPixelComponent(q,border_image->background_color.green);
4195 SetBluePixelComponent(q,border_image->background_color.blue);
4196 if (border_image->matte == MagickFalse)
4197 SetOpacityPixelComponent(q,border_image->background_color.opacity);
4199 SetOpacityPixelComponent(q,ClampToQuantum((MagickRealType)
4200 (QuantumRange-GetAlphaPixelComponent(q)*opacity/100.0)));
4203 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4205 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4210 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4211 #pragma omp critical (MagickCore_ShadowImage)
4213 proceed=SetImageProgress(image,ShadowImageTag,progress++,
4214 border_image->rows);
4215 if (proceed == MagickFalse)
4219 image_view=DestroyCacheView(image_view);
4220 shadow_image=BlurImageChannel(border_image,AlphaChannel,0.0,sigma,exception);
4221 border_image=DestroyImage(border_image);
4222 if (shadow_image == (Image *) NULL)
4223 return((Image *) NULL);
4224 if (shadow_image->page.width == 0)
4225 shadow_image->page.width=shadow_image->columns;
4226 if (shadow_image->page.height == 0)
4227 shadow_image->page.height=shadow_image->rows;
4228 shadow_image->page.width+=x_offset-(ssize_t) border_info.width;
4229 shadow_image->page.height+=y_offset-(ssize_t) border_info.height;
4230 shadow_image->page.x+=x_offset-(ssize_t) border_info.width;
4231 shadow_image->page.y+=y_offset-(ssize_t) border_info.height;
4232 return(shadow_image);
4236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4240 % S k e t c h I m a g e %
4244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4246 % SketchImage() simulates a pencil sketch. We convolve the image with a
4247 % Gaussian operator of the given radius and standard deviation (sigma). For
4248 % reasonable results, radius should be larger than sigma. Use a radius of 0
4249 % and SketchImage() selects a suitable radius for you. Angle gives the angle
4252 % The format of the SketchImage method is:
4254 % Image *SketchImage(const Image *image,const double radius,
4255 % const double sigma,const double angle,ExceptionInfo *exception)
4257 % A description of each parameter follows:
4259 % o image: the image.
4261 % o radius: the radius of the Gaussian, in pixels, not counting
4264 % o sigma: the standard deviation of the Gaussian, in pixels.
4266 % o angle: Apply the effect along this angle.
4268 % o exception: return any errors or warnings in this structure.
4271 MagickExport Image *SketchImage(const Image *image,const double radius,
4272 const double sigma,const double angle,ExceptionInfo *exception)
4291 **restrict random_info;
4299 random_image=CloneImage(image,image->columns << 1,image->rows << 1,
4300 MagickTrue,exception);
4301 if (random_image == (Image *) NULL)
4302 return((Image *) NULL);
4304 GetMagickPixelPacket(random_image,&zero);
4305 random_info=AcquireRandomInfoThreadSet();
4306 random_view=AcquireCacheView(random_image);
4307 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4308 #pragma omp parallel for schedule(dynamic,4) shared(status)
4310 for (y=0; y < (ssize_t) random_image->rows; y++)
4313 id = GetOpenMPThreadId();
4318 register IndexPacket
4324 register PixelPacket
4327 if (status == MagickFalse)
4329 q=QueueCacheViewAuthenticPixels(random_view,0,y,random_image->columns,1,
4331 if (q == (PixelPacket *) NULL)
4336 indexes=GetCacheViewAuthenticIndexQueue(random_view);
4338 for (x=0; x < (ssize_t) random_image->columns; x++)
4340 pixel.red=(MagickRealType) (QuantumRange*
4341 GetPseudoRandomValue(random_info[id]));
4342 pixel.green=pixel.red;
4343 pixel.blue=pixel.red;
4344 if (image->colorspace == CMYKColorspace)
4345 pixel.index=pixel.red;
4346 SetPixelPacket(random_image,&pixel,q,indexes+x);
4349 if (SyncCacheViewAuthenticPixels(random_view,exception) == MagickFalse)
4352 random_view=DestroyCacheView(random_view);
4353 random_info=DestroyRandomInfoThreadSet(random_info);
4354 if (status == MagickFalse)
4356 random_image=DestroyImage(random_image);
4357 return(random_image);
4359 blur_image=MotionBlurImage(random_image,radius,sigma,angle,exception);
4360 random_image=DestroyImage(random_image);
4361 if (blur_image == (Image *) NULL)
4362 return((Image *) NULL);
4363 dodge_image=EdgeImage(blur_image,radius,exception);
4364 blur_image=DestroyImage(blur_image);
4365 if (dodge_image == (Image *) NULL)
4366 return((Image *) NULL);
4367 (void) NormalizeImage(dodge_image);
4368 (void) NegateImage(dodge_image,MagickFalse);
4369 (void) TransformImage(&dodge_image,(char *) NULL,"50%");
4370 sketch_image=CloneImage(image,0,0,MagickTrue,exception);
4371 if (sketch_image == (Image *) NULL)
4373 dodge_image=DestroyImage(dodge_image);
4374 return((Image *) NULL);
4376 (void) CompositeImage(sketch_image,ColorDodgeCompositeOp,dodge_image,0,0);
4377 dodge_image=DestroyImage(dodge_image);
4378 blend_image=CloneImage(image,0,0,MagickTrue,exception);
4379 if (blend_image == (Image *) NULL)
4381 sketch_image=DestroyImage(sketch_image);
4382 return((Image *) NULL);
4384 (void) SetImageArtifact(blend_image,"compose:args","20x80");
4385 (void) CompositeImage(sketch_image,BlendCompositeOp,blend_image,0,0);
4386 blend_image=DestroyImage(blend_image);
4387 return(sketch_image);
4391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4395 % S o l a r i z e I m a g e %
4399 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4401 % SolarizeImage() applies a special effect to the image, similar to the effect
4402 % achieved in a photo darkroom by selectively exposing areas of photo
4403 % sensitive paper to light. Threshold ranges from 0 to QuantumRange and is a
4404 % measure of the extent of the solarization.
4406 % The format of the SolarizeImage method is:
4408 % MagickBooleanType SolarizeImage(Image *image,const double threshold)
4410 % A description of each parameter follows:
4412 % o image: the image.
4414 % o threshold: Define the extent of the solarization.
4417 MagickExport MagickBooleanType SolarizeImage(Image *image,
4418 const double threshold)
4420 #define SolarizeImageTag "Solarize/Image"
4437 assert(image != (Image *) NULL);
4438 assert(image->signature == MagickSignature);
4439 if (image->debug != MagickFalse)
4440 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4441 if (image->storage_class == PseudoClass)
4449 for (i=0; i < (ssize_t) image->colors; i++)
4451 if ((MagickRealType) image->colormap[i].red > threshold)
4452 image->colormap[i].red=(Quantum) QuantumRange-image->colormap[i].red;
4453 if ((MagickRealType) image->colormap[i].green > threshold)
4454 image->colormap[i].green=(Quantum) QuantumRange-
4455 image->colormap[i].green;
4456 if ((MagickRealType) image->colormap[i].blue > threshold)
4457 image->colormap[i].blue=(Quantum) QuantumRange-
4458 image->colormap[i].blue;
4466 exception=(&image->exception);
4467 image_view=AcquireCacheView(image);
4468 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4469 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
4471 for (y=0; y < (ssize_t) image->rows; y++)
4476 register PixelPacket
4479 if (status == MagickFalse)
4481 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
4483 if (q == (PixelPacket *) NULL)
4488 for (x=0; x < (ssize_t) image->columns; x++)
4490 if ((MagickRealType) GetRedPixelComponent(q) > threshold)
4491 SetRedPixelComponent(q,QuantumRange-GetRedPixelComponent(q));
4492 if ((MagickRealType) GetGreenPixelComponent(q) > threshold)
4493 SetGreenPixelComponent(q,QuantumRange-GetGreenPixelComponent(q));
4494 if ((MagickRealType) GetBluePixelComponent(q) > threshold)
4495 SetBluePixelComponent(q,QuantumRange-GetBluePixelComponent(q));
4498 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4500 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4505 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4506 #pragma omp critical (MagickCore_SolarizeImage)
4508 proceed=SetImageProgress(image,SolarizeImageTag,progress++,image->rows);
4509 if (proceed == MagickFalse)
4513 image_view=DestroyCacheView(image_view);
4518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4522 % S t e g a n o I m a g e %
4526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4528 % SteganoImage() hides a digital watermark within the image. Recover
4529 % the hidden watermark later to prove that the authenticity of an image.
4530 % Offset defines the start position within the image to hide the watermark.
4532 % The format of the SteganoImage method is:
4534 % Image *SteganoImage(const Image *image,Image *watermark,
4535 % ExceptionInfo *exception)
4537 % A description of each parameter follows:
4539 % o image: the image.
4541 % o watermark: the watermark image.
4543 % o exception: return any errors or warnings in this structure.
4546 MagickExport Image *SteganoImage(const Image *image,const Image *watermark,
4547 ExceptionInfo *exception)
4549 #define GetBit(alpha,i) ((((size_t) (alpha) >> (size_t) (i)) & 0x01) != 0)
4550 #define SetBit(alpha,i,set) (alpha)=(Quantum) ((set) != 0 ? (size_t) (alpha) \
4551 | (one << (size_t) (i)) : (size_t) (alpha) & ~(one << (size_t) (i)))
4552 #define SteganoImageTag "Stegano/Image"
4570 register PixelPacket
4587 Initialize steganographic image attributes.
4589 assert(image != (const Image *) NULL);
4590 assert(image->signature == MagickSignature);
4591 if (image->debug != MagickFalse)
4592 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4593 assert(watermark != (const Image *) NULL);
4594 assert(watermark->signature == MagickSignature);
4595 assert(exception != (ExceptionInfo *) NULL);
4596 assert(exception->signature == MagickSignature);
4598 stegano_image=CloneImage(image,0,0,MagickTrue,exception);
4599 if (stegano_image == (Image *) NULL)
4600 return((Image *) NULL);
4601 if (SetImageStorageClass(stegano_image,DirectClass) == MagickFalse)
4603 InheritException(exception,&stegano_image->exception);
4604 stegano_image=DestroyImage(stegano_image);
4605 return((Image *) NULL);
4607 stegano_image->depth=MAGICKCORE_QUANTUM_DEPTH;
4609 Hide watermark in low-order bits of image.
4614 depth=stegano_image->depth;
4617 watermark_view=AcquireCacheView(watermark);
4618 stegano_view=AcquireCacheView(stegano_image);
4619 for (i=(ssize_t) depth-1; (i >= 0) && (j < (ssize_t) depth); i--)
4621 for (y=0; (y < (ssize_t) watermark->rows) && (j < (ssize_t) depth); y++)
4623 for (x=0; (x < (ssize_t) watermark->columns) && (j < (ssize_t) depth); x++)
4625 (void) GetOneCacheViewVirtualPixel(watermark_view,x,y,&pixel,exception);
4626 if ((k/(ssize_t) stegano_image->columns) >= (ssize_t) stegano_image->rows)
4628 q=GetCacheViewAuthenticPixels(stegano_view,k % (ssize_t)
4629 stegano_image->columns,k/(ssize_t) stegano_image->columns,1,1,
4631 if (q == (PixelPacket *) NULL)
4637 SetBit(GetRedPixelComponent(q),j,GetBit(PixelIntensityToQuantum(
4643 SetBit(GetGreenPixelComponent(q),j,GetBit(PixelIntensityToQuantum(
4649 SetBit(GetBluePixelComponent(q),j,GetBit(PixelIntensityToQuantum(
4654 if (SyncCacheViewAuthenticPixels(stegano_view,exception) == MagickFalse)
4660 if (k == (ssize_t) (stegano_image->columns*stegano_image->columns))
4662 if (k == image->offset)
4666 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4671 proceed=SetImageProgress(image,SteganoImageTag,(MagickOffsetType)
4673 if (proceed == MagickFalse)
4677 stegano_view=DestroyCacheView(stegano_view);
4678 watermark_view=DestroyCacheView(watermark_view);
4679 if (stegano_image->storage_class == PseudoClass)
4680 (void) SyncImage(stegano_image);
4681 if (status == MagickFalse)
4683 stegano_image=DestroyImage(stegano_image);
4684 return((Image *) NULL);
4686 return(stegano_image);
4690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4694 % S t e r e o A n a g l y p h I m a g e %
4698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4700 % StereoAnaglyphImage() combines two images and produces a single image that
4701 % is the composite of a left and right image of a stereo pair. Special
4702 % red-green stereo glasses are required to view this effect.
4704 % The format of the StereoAnaglyphImage method is:
4706 % Image *StereoImage(const Image *left_image,const Image *right_image,
4707 % ExceptionInfo *exception)
4708 % Image *StereoAnaglyphImage(const Image *left_image,
4709 % const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
4710 % ExceptionInfo *exception)
4712 % A description of each parameter follows:
4714 % o left_image: the left image.
4716 % o right_image: the right image.
4718 % o exception: return any errors or warnings in this structure.
4720 % o x_offset: amount, in pixels, by which the left image is offset to the
4721 % right of the right image.
4723 % o y_offset: amount, in pixels, by which the left image is offset to the
4724 % bottom of the right image.
4728 MagickExport Image *StereoImage(const Image *left_image,
4729 const Image *right_image,ExceptionInfo *exception)
4731 return(StereoAnaglyphImage(left_image,right_image,0,0,exception));
4734 MagickExport Image *StereoAnaglyphImage(const Image *left_image,
4735 const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
4736 ExceptionInfo *exception)
4738 #define StereoImageTag "Stereo/Image"
4752 assert(left_image != (const Image *) NULL);
4753 assert(left_image->signature == MagickSignature);
4754 if (left_image->debug != MagickFalse)
4755 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4756 left_image->filename);
4757 assert(right_image != (const Image *) NULL);
4758 assert(right_image->signature == MagickSignature);
4759 assert(exception != (ExceptionInfo *) NULL);
4760 assert(exception->signature == MagickSignature);
4761 assert(right_image != (const Image *) NULL);
4763 if ((left_image->columns != right_image->columns) ||
4764 (left_image->rows != right_image->rows))
4765 ThrowImageException(ImageError,"LeftAndRightImageSizesDiffer");
4767 Initialize stereo image attributes.
4769 stereo_image=CloneImage(left_image,left_image->columns,left_image->rows,
4770 MagickTrue,exception);
4771 if (stereo_image == (Image *) NULL)
4772 return((Image *) NULL);
4773 if (SetImageStorageClass(stereo_image,DirectClass) == MagickFalse)
4775 InheritException(exception,&stereo_image->exception);
4776 stereo_image=DestroyImage(stereo_image);
4777 return((Image *) NULL);
4780 Copy left image to red channel and right image to blue channel.
4783 for (y=0; y < (ssize_t) stereo_image->rows; y++)
4785 register const PixelPacket
4792 register PixelPacket
4795 p=GetVirtualPixels(left_image,-x_offset,y-y_offset,image->columns,1,
4797 q=GetVirtualPixels(right_image,0,y,right_image->columns,1,exception);
4798 r=QueueAuthenticPixels(stereo_image,0,y,stereo_image->columns,1,exception);
4799 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL) ||
4800 (r == (PixelPacket *) NULL))
4802 for (x=0; x < (ssize_t) stereo_image->columns; x++)
4804 SetRedPixelComponent(r,GetRedPixelComponent(p));
4805 SetGreenPixelComponent(r,GetGreenPixelComponent(q));
4806 SetBluePixelComponent(r,GetBluePixelComponent(q));
4807 SetOpacityPixelComponent(r,(GetOpacityPixelComponent(p)+q->opacity)/2);
4812 if (SyncAuthenticPixels(stereo_image,exception) == MagickFalse)
4814 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4819 proceed=SetImageProgress(image,StereoImageTag,(MagickOffsetType) y,
4820 stereo_image->rows);
4821 if (proceed == MagickFalse)
4825 if (status == MagickFalse)
4827 stereo_image=DestroyImage(stereo_image);
4828 return((Image *) NULL);
4830 return(stereo_image);
4834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4838 % S w i r l I m a g e %
4842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4844 % SwirlImage() swirls the pixels about the center of the image, where
4845 % degrees indicates the sweep of the arc through which each pixel is moved.
4846 % You get a more dramatic effect as the degrees move from 1 to 360.
4848 % The format of the SwirlImage method is:
4850 % Image *SwirlImage(const Image *image,double degrees,
4851 % ExceptionInfo *exception)
4853 % A description of each parameter follows:
4855 % o image: the image.
4857 % o degrees: Define the tightness of the swirling effect.
4859 % o exception: return any errors or warnings in this structure.
4862 MagickExport Image *SwirlImage(const Image *image,double degrees,
4863 ExceptionInfo *exception)
4865 #define SwirlImageTag "Swirl/Image"
4894 Initialize swirl image attributes.
4896 assert(image != (const Image *) NULL);
4897 assert(image->signature == MagickSignature);
4898 if (image->debug != MagickFalse)
4899 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4900 assert(exception != (ExceptionInfo *) NULL);
4901 assert(exception->signature == MagickSignature);
4902 swirl_image=CloneImage(image,0,0,MagickTrue,exception);
4903 if (swirl_image == (Image *) NULL)
4904 return((Image *) NULL);
4905 if (SetImageStorageClass(swirl_image,DirectClass) == MagickFalse)
4907 InheritException(exception,&swirl_image->exception);
4908 swirl_image=DestroyImage(swirl_image);
4909 return((Image *) NULL);
4911 if (swirl_image->background_color.opacity != OpaqueOpacity)
4912 swirl_image->matte=MagickTrue;
4914 Compute scaling factor.
4916 center.x=(double) image->columns/2.0;
4917 center.y=(double) image->rows/2.0;
4918 radius=MagickMax(center.x,center.y);
4921 if (image->columns > image->rows)
4922 scale.y=(double) image->columns/(double) image->rows;
4924 if (image->columns < image->rows)
4925 scale.x=(double) image->rows/(double) image->columns;
4926 degrees=(double) DegreesToRadians(degrees);
4932 GetMagickPixelPacket(swirl_image,&zero);
4933 image_view=AcquireCacheView(image);
4934 swirl_view=AcquireCacheView(swirl_image);
4935 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4936 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
4938 for (y=0; y < (ssize_t) image->rows; y++)
4949 register IndexPacket
4950 *restrict swirl_indexes;
4955 register PixelPacket
4958 if (status == MagickFalse)
4960 q=GetCacheViewAuthenticPixels(swirl_view,0,y,swirl_image->columns,1,
4962 if (q == (PixelPacket *) NULL)
4967 swirl_indexes=GetCacheViewAuthenticIndexQueue(swirl_view);
4968 delta.y=scale.y*(double) (y-center.y);
4970 for (x=0; x < (ssize_t) image->columns; x++)
4973 Determine if the pixel is within an ellipse.
4975 delta.x=scale.x*(double) (x-center.x);
4976 distance=delta.x*delta.x+delta.y*delta.y;
4977 if (distance < (radius*radius))
4987 factor=1.0-sqrt((double) distance)/radius;
4988 sine=sin((double) (degrees*factor*factor));
4989 cosine=cos((double) (degrees*factor*factor));
4990 (void) InterpolateMagickPixelPacket(image,image_view,
4991 UndefinedInterpolatePixel,(double) ((cosine*delta.x-sine*delta.y)/
4992 scale.x+center.x),(double) ((sine*delta.x+cosine*delta.y)/scale.y+
4993 center.y),&pixel,exception);
4994 SetPixelPacket(swirl_image,&pixel,q,swirl_indexes+x);
4998 if (SyncCacheViewAuthenticPixels(swirl_view,exception) == MagickFalse)
5000 if (image->progress_monitor != (MagickProgressMonitor) NULL)
5005 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5006 #pragma omp critical (MagickCore_SwirlImage)
5008 proceed=SetImageProgress(image,SwirlImageTag,progress++,image->rows);
5009 if (proceed == MagickFalse)
5013 swirl_view=DestroyCacheView(swirl_view);
5014 image_view=DestroyCacheView(image_view);
5015 if (status == MagickFalse)
5016 swirl_image=DestroyImage(swirl_image);
5017 return(swirl_image);
5021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5025 % T i n t I m a g e %
5029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5031 % TintImage() applies a color vector to each pixel in the image. The length
5032 % of the vector is 0 for black and white and at its maximum for the midtones.
5033 % The vector weighting function is f(x)=(1-(4.0*((x-0.5)*(x-0.5))))
5035 % The format of the TintImage method is:
5037 % Image *TintImage(const Image *image,const char *opacity,
5038 % const PixelPacket tint,ExceptionInfo *exception)
5040 % A description of each parameter follows:
5042 % o image: the image.
5044 % o opacity: A color value used for tinting.
5046 % o tint: A color value used for tinting.
5048 % o exception: return any errors or warnings in this structure.
5051 MagickExport Image *TintImage(const Image *image,const char *opacity,
5052 const PixelPacket tint,ExceptionInfo *exception)
5054 #define TintImageTag "Tint/Image"
5083 Allocate tint image.
5085 assert(image != (const Image *) NULL);
5086 assert(image->signature == MagickSignature);
5087 if (image->debug != MagickFalse)
5088 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5089 assert(exception != (ExceptionInfo *) NULL);
5090 assert(exception->signature == MagickSignature);
5091 tint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
5092 if (tint_image == (Image *) NULL)
5093 return((Image *) NULL);
5094 if (SetImageStorageClass(tint_image,DirectClass) == MagickFalse)
5096 InheritException(exception,&tint_image->exception);
5097 tint_image=DestroyImage(tint_image);
5098 return((Image *) NULL);
5100 if (opacity == (const char *) NULL)
5103 Determine RGB values of the color.
5105 flags=ParseGeometry(opacity,&geometry_info);
5106 pixel.red=geometry_info.rho;
5107 if ((flags & SigmaValue) != 0)
5108 pixel.green=geometry_info.sigma;
5110 pixel.green=pixel.red;
5111 if ((flags & XiValue) != 0)
5112 pixel.blue=geometry_info.xi;
5114 pixel.blue=pixel.red;
5115 if ((flags & PsiValue) != 0)
5116 pixel.opacity=geometry_info.psi;
5118 pixel.opacity=(MagickRealType) OpaqueOpacity;
5119 color_vector.red=(MagickRealType) (pixel.red*tint.red/100.0-
5120 PixelIntensity(&tint));
5121 color_vector.green=(MagickRealType) (pixel.green*tint.green/100.0-
5122 PixelIntensity(&tint));
5123 color_vector.blue=(MagickRealType) (pixel.blue*tint.blue/100.0-
5124 PixelIntensity(&tint));
5130 image_view=AcquireCacheView(image);
5131 tint_view=AcquireCacheView(tint_image);
5132 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5133 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
5135 for (y=0; y < (ssize_t) image->rows; y++)
5137 register const PixelPacket
5140 register PixelPacket
5146 if (status == MagickFalse)
5148 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
5149 q=QueueCacheViewAuthenticPixels(tint_view,0,y,tint_image->columns,1,
5151 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
5156 for (x=0; x < (ssize_t) image->columns; x++)
5164 weight=QuantumScale*GetRedPixelComponent(p)-0.5;
5165 pixel.red=(MagickRealType) GetRedPixelComponent(p)+color_vector.red*(1.0-(4.0*
5167 SetRedPixelComponent(q,ClampToQuantum(pixel.red));
5168 weight=QuantumScale*GetGreenPixelComponent(p)-0.5;
5169 pixel.green=(MagickRealType) GetGreenPixelComponent(p)+color_vector.green*(1.0-(4.0*
5171 SetGreenPixelComponent(q,ClampToQuantum(pixel.green));
5172 weight=QuantumScale*GetBluePixelComponent(p)-0.5;
5173 pixel.blue=(MagickRealType) GetBluePixelComponent(p)+color_vector.blue*(1.0-(4.0*
5175 SetBluePixelComponent(q,ClampToQuantum(pixel.blue));
5176 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
5180 if (SyncCacheViewAuthenticPixels(tint_view,exception) == MagickFalse)
5182 if (image->progress_monitor != (MagickProgressMonitor) NULL)
5187 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5188 #pragma omp critical (MagickCore_TintImage)
5190 proceed=SetImageProgress(image,TintImageTag,progress++,image->rows);
5191 if (proceed == MagickFalse)
5195 tint_view=DestroyCacheView(tint_view);
5196 image_view=DestroyCacheView(image_view);
5197 if (status == MagickFalse)
5198 tint_image=DestroyImage(tint_image);
5203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5207 % V i g n e t t e I m a g e %
5211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5213 % VignetteImage() softens the edges of the image in vignette style.
5215 % The format of the VignetteImage method is:
5217 % Image *VignetteImage(const Image *image,const double radius,
5218 % const double sigma,const ssize_t x,const ssize_t y,ExceptionInfo *exception)
5220 % A description of each parameter follows:
5222 % o image: the image.
5224 % o radius: the radius of the pixel neighborhood.
5226 % o sigma: the standard deviation of the Gaussian, in pixels.
5228 % o x, y: Define the x and y ellipse offset.
5230 % o exception: return any errors or warnings in this structure.
5233 MagickExport Image *VignetteImage(const Image *image,const double radius,
5234 const double sigma,const ssize_t x,const ssize_t y,ExceptionInfo *exception)
5237 ellipse[MaxTextExtent];
5248 assert(image != (Image *) NULL);
5249 assert(image->signature == MagickSignature);
5250 if (image->debug != MagickFalse)
5251 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5252 assert(exception != (ExceptionInfo *) NULL);
5253 assert(exception->signature == MagickSignature);
5254 canvas_image=CloneImage(image,0,0,MagickTrue,exception);
5255 if (canvas_image == (Image *) NULL)
5256 return((Image *) NULL);
5257 if (SetImageStorageClass(canvas_image,DirectClass) == MagickFalse)
5259 InheritException(exception,&canvas_image->exception);
5260 canvas_image=DestroyImage(canvas_image);
5261 return((Image *) NULL);
5263 canvas_image->matte=MagickTrue;
5264 oval_image=CloneImage(canvas_image,canvas_image->columns,
5265 canvas_image->rows,MagickTrue,exception);
5266 if (oval_image == (Image *) NULL)
5268 canvas_image=DestroyImage(canvas_image);
5269 return((Image *) NULL);
5271 (void) QueryColorDatabase("#000000",&oval_image->background_color,exception);
5272 (void) SetImageBackgroundColor(oval_image);
5273 draw_info=CloneDrawInfo((const ImageInfo *) NULL,(const DrawInfo *) NULL);
5274 (void) QueryColorDatabase("#ffffff",&draw_info->fill,exception);
5275 (void) QueryColorDatabase("#ffffff",&draw_info->stroke,exception);
5276 (void) FormatMagickString(ellipse,MaxTextExtent,
5277 "ellipse %g,%g,%g,%g,0.0,360.0",image->columns/2.0,
5278 image->rows/2.0,image->columns/2.0-x,image->rows/2.0-y);
5279 draw_info->primitive=AcquireString(ellipse);
5280 (void) DrawImage(oval_image,draw_info);
5281 draw_info=DestroyDrawInfo(draw_info);
5282 blur_image=BlurImage(oval_image,radius,sigma,exception);
5283 oval_image=DestroyImage(oval_image);
5284 if (blur_image == (Image *) NULL)
5286 canvas_image=DestroyImage(canvas_image);
5287 return((Image *) NULL);
5289 blur_image->matte=MagickFalse;
5290 (void) CompositeImage(canvas_image,CopyOpacityCompositeOp,blur_image,0,0);
5291 blur_image=DestroyImage(blur_image);
5292 vignette_image=MergeImageLayers(canvas_image,FlattenLayer,exception);
5293 canvas_image=DestroyImage(canvas_image);
5294 return(vignette_image);
5298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5302 % W a v e I m a g e %
5306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5308 % WaveImage() creates a "ripple" effect in the image by shifting the pixels
5309 % vertically along a sine wave whose amplitude and wavelength is specified
5310 % by the given parameters.
5312 % The format of the WaveImage method is:
5314 % Image *WaveImage(const Image *image,const double amplitude,
5315 % const double wave_length,ExceptionInfo *exception)
5317 % A description of each parameter follows:
5319 % o image: the image.
5321 % o amplitude, wave_length: Define the amplitude and wave length of the
5324 % o exception: return any errors or warnings in this structure.
5327 MagickExport Image *WaveImage(const Image *image,const double amplitude,
5328 const double wave_length,ExceptionInfo *exception)
5330 #define WaveImageTag "Wave/Image"
5358 Initialize wave image attributes.
5360 assert(image != (Image *) NULL);
5361 assert(image->signature == MagickSignature);
5362 if (image->debug != MagickFalse)
5363 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5364 assert(exception != (ExceptionInfo *) NULL);
5365 assert(exception->signature == MagickSignature);
5366 wave_image=CloneImage(image,image->columns,(size_t) (image->rows+2.0*
5367 fabs(amplitude)),MagickTrue,exception);
5368 if (wave_image == (Image *) NULL)
5369 return((Image *) NULL);
5370 if (SetImageStorageClass(wave_image,DirectClass) == MagickFalse)
5372 InheritException(exception,&wave_image->exception);
5373 wave_image=DestroyImage(wave_image);
5374 return((Image *) NULL);
5376 if (wave_image->background_color.opacity != OpaqueOpacity)
5377 wave_image->matte=MagickTrue;
5381 sine_map=(MagickRealType *) AcquireQuantumMemory((size_t) wave_image->columns,
5383 if (sine_map == (MagickRealType *) NULL)
5385 wave_image=DestroyImage(wave_image);
5386 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
5388 for (i=0; i < (ssize_t) wave_image->columns; i++)
5389 sine_map[i]=fabs(amplitude)+amplitude*sin((double) ((2.0*MagickPI*i)/
5396 GetMagickPixelPacket(wave_image,&zero);
5397 image_view=AcquireCacheView(image);
5398 wave_view=AcquireCacheView(wave_image);
5399 (void) SetCacheViewVirtualPixelMethod(image_view,
5400 BackgroundVirtualPixelMethod);
5401 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5402 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
5404 for (y=0; y < (ssize_t) wave_image->rows; y++)
5409 register IndexPacket
5412 register PixelPacket
5418 if (status == MagickFalse)
5420 q=QueueCacheViewAuthenticPixels(wave_view,0,y,wave_image->columns,1,
5422 if (q == (PixelPacket *) NULL)
5427 indexes=GetCacheViewAuthenticIndexQueue(wave_view);
5429 for (x=0; x < (ssize_t) wave_image->columns; x++)
5431 (void) InterpolateMagickPixelPacket(image,image_view,
5432 UndefinedInterpolatePixel,(double) x,(double) (y-sine_map[x]),&pixel,
5434 SetPixelPacket(wave_image,&pixel,q,indexes+x);
5437 if (SyncCacheViewAuthenticPixels(wave_view,exception) == MagickFalse)
5439 if (image->progress_monitor != (MagickProgressMonitor) NULL)
5444 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5445 #pragma omp critical (MagickCore_WaveImage)
5447 proceed=SetImageProgress(image,WaveImageTag,progress++,image->rows);
5448 if (proceed == MagickFalse)
5452 wave_view=DestroyCacheView(wave_view);
5453 image_view=DestroyCacheView(image_view);
5454 sine_map=(MagickRealType *) RelinquishMagickMemory(sine_map);
5455 if (status == MagickFalse)
5456 wave_image=DestroyImage(wave_image);