2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % MagickCore Image Special Effects Methods %
20 % Copyright 1999-2010 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
132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
136 + A c q u i r e F x I n f o %
140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
142 % AcquireFxInfo() allocates the FxInfo structure.
144 % The format of the AcquireFxInfo method is:
146 % FxInfo *AcquireFxInfo(Image *image,const char *expression)
147 % A description of each parameter follows:
149 % o image: the image.
151 % o expression: the expression.
154 MagickExport FxInfo *AcquireFxInfo(const Image *image,const char *expression)
165 fx_info=(FxInfo *) AcquireAlignedMemory(1,sizeof(*fx_info));
166 if (fx_info == (FxInfo *) NULL)
167 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
168 (void) ResetMagickMemory(fx_info,0,sizeof(*fx_info));
169 fx_info->exception=AcquireExceptionInfo();
170 fx_info->images=image;
171 fx_info->matte=image->matte;
172 fx_info->colors=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
173 RelinquishMagickMemory);
174 fx_info->symbols=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
175 RelinquishMagickMemory);
176 fx_info->resample_filter=(ResampleFilter **) AcquireQuantumMemory(
177 GetImageListLength(fx_info->images),sizeof(*fx_info->resample_filter));
178 if (fx_info->resample_filter == (ResampleFilter **) NULL)
179 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
180 for (i=0; i < (ssize_t) GetImageListLength(fx_info->images); i++)
182 fx_info->resample_filter[i]=AcquireResampleFilter(GetImageFromList(
183 fx_info->images,i),fx_info->exception);
184 SetResampleFilter(fx_info->resample_filter[i],PointFilter,1.0);
186 fx_info->random_info=AcquireRandomInfo();
187 fx_info->expression=ConstantString(expression);
188 fx_info->file=stderr;
189 (void) SubstituteString(&fx_info->expression," ",""); /* compact string */
190 if ((strstr(fx_info->expression,"e+") != (char *) NULL) ||
191 (strstr(fx_info->expression,"e-") != (char *) NULL))
194 Convert scientific notation.
196 (void) SubstituteString(&fx_info->expression,"0e+","0**10^");
197 (void) SubstituteString(&fx_info->expression,"1e+","1**10^");
198 (void) SubstituteString(&fx_info->expression,"2e+","2**10^");
199 (void) SubstituteString(&fx_info->expression,"3e+","3**10^");
200 (void) SubstituteString(&fx_info->expression,"4e+","4**10^");
201 (void) SubstituteString(&fx_info->expression,"5e+","5**10^");
202 (void) SubstituteString(&fx_info->expression,"6e+","6**10^");
203 (void) SubstituteString(&fx_info->expression,"7e+","7**10^");
204 (void) SubstituteString(&fx_info->expression,"8e+","8**10^");
205 (void) SubstituteString(&fx_info->expression,"9e+","9**10^");
206 (void) SubstituteString(&fx_info->expression,"0e-","0**10^-");
207 (void) SubstituteString(&fx_info->expression,"1e-","1**10^-");
208 (void) SubstituteString(&fx_info->expression,"2e-","2**10^-");
209 (void) SubstituteString(&fx_info->expression,"3e-","3**10^-");
210 (void) SubstituteString(&fx_info->expression,"4e-","4**10^-");
211 (void) SubstituteString(&fx_info->expression,"5e-","5**10^-");
212 (void) SubstituteString(&fx_info->expression,"6e-","6**10^-");
213 (void) SubstituteString(&fx_info->expression,"7e-","7**10^-");
214 (void) SubstituteString(&fx_info->expression,"8e-","8**10^-");
215 (void) SubstituteString(&fx_info->expression,"9e-","9**10^-");
218 Convert complex to simple operators.
221 *fx_op=(char) LeftShiftOperator;
222 (void) SubstituteString(&fx_info->expression,"<<",fx_op);
223 *fx_op=(char) RightShiftOperator;
224 (void) SubstituteString(&fx_info->expression,">>",fx_op);
225 *fx_op=(char) LessThanEqualOperator;
226 (void) SubstituteString(&fx_info->expression,"<=",fx_op);
227 *fx_op=(char) GreaterThanEqualOperator;
228 (void) SubstituteString(&fx_info->expression,">=",fx_op);
229 *fx_op=(char) EqualOperator;
230 (void) SubstituteString(&fx_info->expression,"==",fx_op);
231 *fx_op=(char) NotEqualOperator;
232 (void) SubstituteString(&fx_info->expression,"!=",fx_op);
233 *fx_op=(char) LogicalAndOperator;
234 (void) SubstituteString(&fx_info->expression,"&&",fx_op);
235 *fx_op=(char) LogicalOrOperator;
236 (void) SubstituteString(&fx_info->expression,"||",fx_op);
237 *fx_op=(char) ExponentialNotation;
238 (void) SubstituteString(&fx_info->expression,"**",fx_op);
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
247 % A d d N o i s e I m a g e %
251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
253 % AddNoiseImage() adds random noise to the image.
255 % The format of the AddNoiseImage method is:
257 % Image *AddNoiseImage(const Image *image,const NoiseType noise_type,
258 % ExceptionInfo *exception)
259 % Image *AddNoiseImageChannel(const Image *image,const ChannelType channel,
260 % const NoiseType noise_type,ExceptionInfo *exception)
262 % A description of each parameter follows:
264 % o image: the image.
266 % o channel: the channel type.
268 % o noise_type: The type of noise: Uniform, Gaussian, Multiplicative,
269 % Impulse, Laplacian, or Poisson.
271 % o exception: return any errors or warnings in this structure.
274 MagickExport Image *AddNoiseImage(const Image *image,const NoiseType noise_type,
275 ExceptionInfo *exception)
280 noise_image=AddNoiseImageChannel(image,DefaultChannels,noise_type,exception);
284 MagickExport Image *AddNoiseImageChannel(const Image *image,
285 const ChannelType channel,const NoiseType noise_type,ExceptionInfo *exception)
287 #define AddNoiseImageTag "AddNoise/Image"
309 **restrict random_info;
315 Initialize noise image attributes.
317 assert(image != (const Image *) NULL);
318 assert(image->signature == MagickSignature);
319 if (image->debug != MagickFalse)
320 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
321 assert(exception != (ExceptionInfo *) NULL);
322 assert(exception->signature == MagickSignature);
323 noise_image=CloneImage(image,0,0,MagickTrue,exception);
324 if (noise_image == (Image *) NULL)
325 return((Image *) NULL);
326 if (SetImageStorageClass(noise_image,DirectClass) == MagickFalse)
328 InheritException(exception,&noise_image->exception);
329 noise_image=DestroyImage(noise_image);
330 return((Image *) NULL);
333 Add noise in each row.
336 option=GetImageArtifact(image,"attenuate");
337 if (option != (char *) NULL)
338 attenuate=StringToDouble(option);
341 random_info=AcquireRandomInfoThreadSet();
342 image_view=AcquireCacheView(image);
343 noise_view=AcquireCacheView(noise_image);
344 #if defined(MAGICKCORE_OPENMP_SUPPORT)
345 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
347 for (y=0; y < (ssize_t) image->rows; y++)
355 register const IndexPacket
358 register const PixelPacket
362 *restrict noise_indexes;
370 if (status == MagickFalse)
372 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
373 q=GetCacheViewAuthenticPixels(noise_view,0,y,noise_image->columns,1,
375 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
380 indexes=GetCacheViewVirtualIndexQueue(image_view);
381 noise_indexes=GetCacheViewAuthenticIndexQueue(noise_view);
382 id=GetOpenMPThreadId();
383 for (x=0; x < (ssize_t) image->columns; x++)
385 if ((channel & RedChannel) != 0)
386 q->red=ClampToQuantum(GenerateDifferentialNoise(random_info[id],
387 p->red,noise_type,attenuate));
388 if ((channel & GreenChannel) != 0)
389 q->green=ClampToQuantum(GenerateDifferentialNoise(random_info[id],
390 p->green,noise_type,attenuate));
391 if ((channel & BlueChannel) != 0)
392 q->blue=ClampToQuantum(GenerateDifferentialNoise(random_info[id],
393 p->blue,noise_type,attenuate));
394 if ((channel & OpacityChannel) != 0)
395 q->opacity=ClampToQuantum(GenerateDifferentialNoise(random_info[id],
396 p->opacity,noise_type,attenuate));
397 if (((channel & IndexChannel) != 0) &&
398 (image->colorspace == CMYKColorspace))
399 noise_indexes[x]=(IndexPacket) ClampToQuantum(GenerateDifferentialNoise(
400 random_info[id],indexes[x],noise_type,attenuate));
404 sync=SyncCacheViewAuthenticPixels(noise_view,exception);
405 if (sync == MagickFalse)
407 if (image->progress_monitor != (MagickProgressMonitor) NULL)
412 #if defined(MAGICKCORE_OPENMP_SUPPORT)
413 #pragma omp critical (MagickCore_AddNoiseImage)
415 proceed=SetImageProgress(image,AddNoiseImageTag,progress++,
417 if (proceed == MagickFalse)
421 noise_view=DestroyCacheView(noise_view);
422 image_view=DestroyCacheView(image_view);
423 random_info=DestroyRandomInfoThreadSet(random_info);
424 if (status == MagickFalse)
425 noise_image=DestroyImage(noise_image);
430 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
434 % B l u e S h i f t I m a g e %
438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
440 % BlueShiftImage() mutes the colors of the image to simulate a scene at
441 % nighttime in the moonlight.
443 % The format of the BlueShiftImage method is:
445 % Image *BlueShiftImage(const Image *image,const double factor,
446 % ExceptionInfo *exception)
448 % A description of each parameter follows:
450 % o image: the image.
452 % o factor: the shift factor.
454 % o exception: return any errors or warnings in this structure.
457 MagickExport Image *BlueShiftImage(const Image *image,const double factor,
458 ExceptionInfo *exception)
460 #define BlueShiftImageTag "BlueShift/Image"
479 Allocate blue shift image.
481 assert(image != (const Image *) NULL);
482 assert(image->signature == MagickSignature);
483 if (image->debug != MagickFalse)
484 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
485 assert(exception != (ExceptionInfo *) NULL);
486 assert(exception->signature == MagickSignature);
487 shift_image=CloneImage(image,image->columns,image->rows,MagickTrue,
489 if (shift_image == (Image *) NULL)
490 return((Image *) NULL);
491 if (SetImageStorageClass(shift_image,DirectClass) == MagickFalse)
493 InheritException(exception,&shift_image->exception);
494 shift_image=DestroyImage(shift_image);
495 return((Image *) NULL);
498 Blue-shift DirectClass image.
502 image_view=AcquireCacheView(image);
503 shift_view=AcquireCacheView(shift_image);
504 #if defined(MAGICKCORE_OPENMP_SUPPORT)
505 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
507 for (y=0; y < (ssize_t) image->rows; y++)
518 register const PixelPacket
527 if (status == MagickFalse)
529 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
530 q=QueueCacheViewAuthenticPixels(shift_view,0,y,shift_image->columns,1,
532 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
537 for (x=0; x < (ssize_t) image->columns; x++)
539 quantum=GetRedPixelComponent(p);
540 if (p->green < quantum)
541 quantum=GetGreenPixelComponent(p);
542 if (p->blue < quantum)
543 quantum=GetBluePixelComponent(p);
544 pixel.red=0.5*(p->red+factor*quantum);
545 pixel.green=0.5*(p->green+factor*quantum);
546 pixel.blue=0.5*(p->blue+factor*quantum);
547 quantum=GetRedPixelComponent(p);
548 if (p->green > quantum)
549 quantum=GetGreenPixelComponent(p);
550 if (p->blue > quantum)
551 quantum=GetBluePixelComponent(p);
552 pixel.red=0.5*(pixel.red+factor*quantum);
553 pixel.green=0.5*(pixel.green+factor*quantum);
554 pixel.blue=0.5*(pixel.blue+factor*quantum);
555 SetRedPixelComponent(q,ClampRedPixelComponent(&pixel));
556 SetGreenPixelComponent(q,ClampGreenPixelComponent(&pixel));
557 SetBluePixelComponent(q,ClampBluePixelComponent(&pixel));
561 sync=SyncCacheViewAuthenticPixels(shift_view,exception);
562 if (sync == MagickFalse)
564 if (image->progress_monitor != (MagickProgressMonitor) NULL)
569 #if defined(MAGICKCORE_OPENMP_SUPPORT)
570 #pragma omp critical (MagickCore_BlueShiftImage)
572 proceed=SetImageProgress(image,BlueShiftImageTag,progress++,
574 if (proceed == MagickFalse)
578 image_view=DestroyCacheView(image_view);
579 shift_view=DestroyCacheView(shift_view);
580 if (status == MagickFalse)
581 shift_image=DestroyImage(shift_image);
586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
590 % C h a r c o a l I m a g e %
594 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
596 % CharcoalImage() creates a new image that is a copy of an existing one with
597 % the edge highlighted. It allocates the memory necessary for the new Image
598 % structure and returns a pointer to the new image.
600 % The format of the CharcoalImage method is:
602 % Image *CharcoalImage(const Image *image,const double radius,
603 % const double sigma,ExceptionInfo *exception)
605 % A description of each parameter follows:
607 % o image: the image.
609 % o radius: the radius of the pixel neighborhood.
611 % o sigma: the standard deviation of the Gaussian, in pixels.
613 % o exception: return any errors or warnings in this structure.
616 MagickExport Image *CharcoalImage(const Image *image,const double radius,
617 const double sigma,ExceptionInfo *exception)
624 assert(image != (Image *) NULL);
625 assert(image->signature == MagickSignature);
626 if (image->debug != MagickFalse)
627 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
628 assert(exception != (ExceptionInfo *) NULL);
629 assert(exception->signature == MagickSignature);
630 clone_image=CloneImage(image,0,0,MagickTrue,exception);
631 if (clone_image == (Image *) NULL)
632 return((Image *) NULL);
633 (void) SetImageType(clone_image,GrayscaleType);
634 edge_image=EdgeImage(clone_image,radius,exception);
635 clone_image=DestroyImage(clone_image);
636 if (edge_image == (Image *) NULL)
637 return((Image *) NULL);
638 charcoal_image=BlurImage(edge_image,radius,sigma,exception);
639 edge_image=DestroyImage(edge_image);
640 if (charcoal_image == (Image *) NULL)
641 return((Image *) NULL);
642 (void) NormalizeImage(charcoal_image);
643 (void) NegateImage(charcoal_image,MagickFalse);
644 (void) SetImageType(charcoal_image,GrayscaleType);
645 return(charcoal_image);
649 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
653 % C o l o r i z e I m a g e %
657 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
659 % ColorizeImage() blends the fill color with each pixel in the image.
660 % A percentage blend is specified with opacity. Control the application
661 % of different color components by specifying a different percentage for
662 % each component (e.g. 90/100/10 is 90% red, 100% green, and 10% blue).
664 % The format of the ColorizeImage method is:
666 % Image *ColorizeImage(const Image *image,const char *opacity,
667 % const PixelPacket colorize,ExceptionInfo *exception)
669 % A description of each parameter follows:
671 % o image: the image.
673 % o opacity: A character string indicating the level of opacity as a
676 % o colorize: A color value.
678 % o exception: return any errors or warnings in this structure.
681 MagickExport Image *ColorizeImage(const Image *image,const char *opacity,
682 const PixelPacket colorize,ExceptionInfo *exception)
684 #define ColorizeImageTag "Colorize/Image"
712 Allocate colorized image.
714 assert(image != (const Image *) NULL);
715 assert(image->signature == MagickSignature);
716 if (image->debug != MagickFalse)
717 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
718 assert(exception != (ExceptionInfo *) NULL);
719 assert(exception->signature == MagickSignature);
720 colorize_image=CloneImage(image,image->columns,image->rows,MagickTrue,
722 if (colorize_image == (Image *) NULL)
723 return((Image *) NULL);
724 if (SetImageStorageClass(colorize_image,DirectClass) == MagickFalse)
726 InheritException(exception,&colorize_image->exception);
727 colorize_image=DestroyImage(colorize_image);
728 return((Image *) NULL);
730 if (opacity == (const char *) NULL)
731 return(colorize_image);
733 Determine RGB values of the pen color.
735 flags=ParseGeometry(opacity,&geometry_info);
736 pixel.red=geometry_info.rho;
737 pixel.green=geometry_info.rho;
738 pixel.blue=geometry_info.rho;
739 pixel.opacity=(MagickRealType) OpaqueOpacity;
740 if ((flags & SigmaValue) != 0)
741 pixel.green=geometry_info.sigma;
742 if ((flags & XiValue) != 0)
743 pixel.blue=geometry_info.xi;
744 if ((flags & PsiValue) != 0)
745 pixel.opacity=geometry_info.psi;
747 Colorize DirectClass image.
751 image_view=AcquireCacheView(image);
752 colorize_view=AcquireCacheView(colorize_image);
753 #if defined(MAGICKCORE_OPENMP_SUPPORT)
754 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
756 for (y=0; y < (ssize_t) image->rows; y++)
761 register const PixelPacket
770 if (status == MagickFalse)
772 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
773 q=QueueCacheViewAuthenticPixels(colorize_view,0,y,colorize_image->columns,1,
775 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
780 for (x=0; x < (ssize_t) image->columns; x++)
782 q->red=(Quantum) ((p->red*(100.0-pixel.red)+
783 colorize.red*pixel.red)/100.0);
784 q->green=(Quantum) ((p->green*(100.0-pixel.green)+
785 colorize.green*pixel.green)/100.0);
786 q->blue=(Quantum) ((p->blue*(100.0-pixel.blue)+
787 colorize.blue*pixel.blue)/100.0);
788 q->opacity=(Quantum) ((p->opacity*(100.0-pixel.opacity)+
789 colorize.opacity*pixel.opacity)/100.0);
793 sync=SyncCacheViewAuthenticPixels(colorize_view,exception);
794 if (sync == MagickFalse)
796 if (image->progress_monitor != (MagickProgressMonitor) NULL)
801 #if defined(MAGICKCORE_OPENMP_SUPPORT)
802 #pragma omp critical (MagickCore_ColorizeImage)
804 proceed=SetImageProgress(image,ColorizeImageTag,progress++,image->rows);
805 if (proceed == MagickFalse)
809 image_view=DestroyCacheView(image_view);
810 colorize_view=DestroyCacheView(colorize_view);
811 if (status == MagickFalse)
812 colorize_image=DestroyImage(colorize_image);
813 return(colorize_image);
817 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
821 % C o l o r M a t r i x I m a g e %
825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
827 % ColorMatrixImage() applies color transformation to an image. This method
828 % permits saturation changes, hue rotation, luminance to alpha, and various
829 % other effects. Although variable-sized transformation matrices can be used,
830 % typically one uses a 5x5 matrix for an RGBA image and a 6x6 for CMYKA
831 % (or RGBA with offsets). The matrix is similar to those used by Adobe Flash
832 % except offsets are in column 6 rather than 5 (in support of CMYKA images)
833 % and offsets are normalized (divide Flash offset by 255).
835 % The format of the ColorMatrixImage method is:
837 % Image *ColorMatrixImage(const Image *image,
838 % const KernelInfo *color_matrix,ExceptionInfo *exception)
840 % A description of each parameter follows:
842 % o image: the image.
844 % o color_matrix: the color matrix.
846 % o exception: return any errors or warnings in this structure.
849 MagickExport Image *ColorMatrixImage(const Image *image,
850 const KernelInfo *color_matrix,ExceptionInfo *exception)
852 #define ColorMatrixImageTag "ColorMatrix/Image"
861 { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
862 { 0.0, 1.0, 0.0, 0.0, 0.0, 0.0 },
863 { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 },
864 { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0 },
865 { 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 },
866 { 0.0, 0.0, 0.0, 0.0, 0.0, 1.0 }
889 assert(image != (Image *) NULL);
890 assert(image->signature == MagickSignature);
891 if (image->debug != MagickFalse)
892 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
893 assert(exception != (ExceptionInfo *) NULL);
894 assert(exception->signature == MagickSignature);
896 for (v=0; v < (ssize_t) color_matrix->height; v++)
897 for (u=0; u < (ssize_t) color_matrix->width; u++)
899 if ((v < 6) && (u < 6))
900 ColorMatrix[v][u]=color_matrix->values[i];
904 Initialize color image.
906 color_image=CloneImage(image,0,0,MagickTrue,exception);
907 if (color_image == (Image *) NULL)
908 return((Image *) NULL);
909 if (SetImageStorageClass(color_image,DirectClass) == MagickFalse)
911 InheritException(exception,&color_image->exception);
912 color_image=DestroyImage(color_image);
913 return((Image *) NULL);
915 if (image->debug != MagickFalse)
918 format[MaxTextExtent],
921 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
922 " ColorMatrix image with color matrix:");
923 message=AcquireString("");
924 for (v=0; v < 6; v++)
927 (void) FormatMagickString(format,MaxTextExtent,"%.20g: ",(double) v);
928 (void) ConcatenateString(&message,format);
929 for (u=0; u < 6; u++)
931 (void) FormatMagickString(format,MaxTextExtent,"%+f ",
933 (void) ConcatenateString(&message,format);
935 (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
937 message=DestroyString(message);
944 image_view=AcquireCacheView(image);
945 color_view=AcquireCacheView(color_image);
946 #if defined(MAGICKCORE_OPENMP_SUPPORT)
947 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
949 for (y=0; y < (ssize_t) image->rows; y++)
954 register const IndexPacket
957 register const PixelPacket
964 *restrict color_indexes;
969 if (status == MagickFalse)
971 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
972 q=GetCacheViewAuthenticPixels(color_view,0,y,color_image->columns,1,
974 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
979 indexes=GetCacheViewVirtualIndexQueue(image_view);
980 color_indexes=GetCacheViewAuthenticIndexQueue(color_view);
981 for (x=0; x < (ssize_t) image->columns; x++)
989 height=color_matrix->height > 6 ? 6UL : color_matrix->height;
990 for (v=0; v < (ssize_t) height; v++)
992 pixel=ColorMatrix[v][0]*p->red+ColorMatrix[v][1]*p->green+
993 ColorMatrix[v][2]*p->blue;
994 if (image->matte != MagickFalse)
995 pixel+=ColorMatrix[v][3]*(QuantumRange-p->opacity);
996 if (image->colorspace == CMYKColorspace)
997 pixel+=ColorMatrix[v][4]*indexes[x];
998 pixel+=QuantumRange*ColorMatrix[v][5];
1001 case 0: q->red=ClampToQuantum(pixel); break;
1002 case 1: q->green=ClampToQuantum(pixel); break;
1003 case 2: q->blue=ClampToQuantum(pixel); break;
1006 if (image->matte != MagickFalse)
1007 q->opacity=ClampToQuantum(QuantumRange-pixel);
1012 if (image->colorspace == CMYKColorspace)
1013 color_indexes[x]=ClampToQuantum(pixel);
1021 if (SyncCacheViewAuthenticPixels(color_view,exception) == MagickFalse)
1023 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1028 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1029 #pragma omp critical (MagickCore_ColorMatrixImage)
1031 proceed=SetImageProgress(image,ColorMatrixImageTag,progress++,
1033 if (proceed == MagickFalse)
1037 color_view=DestroyCacheView(color_view);
1038 image_view=DestroyCacheView(image_view);
1039 if (status == MagickFalse)
1040 color_image=DestroyImage(color_image);
1041 return(color_image);
1045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1049 + D e s t r o y F x I n f o %
1053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1055 % DestroyFxInfo() deallocates memory associated with an FxInfo structure.
1057 % The format of the DestroyFxInfo method is:
1059 % ImageInfo *DestroyFxInfo(ImageInfo *fx_info)
1061 % A description of each parameter follows:
1063 % o fx_info: the fx info.
1066 MagickExport FxInfo *DestroyFxInfo(FxInfo *fx_info)
1071 fx_info->exception=DestroyExceptionInfo(fx_info->exception);
1072 fx_info->expression=DestroyString(fx_info->expression);
1073 fx_info->symbols=DestroySplayTree(fx_info->symbols);
1074 fx_info->colors=DestroySplayTree(fx_info->colors);
1075 for (i=0; i < (ssize_t) GetImageListLength(fx_info->images); i++)
1076 fx_info->resample_filter[i]=DestroyResampleFilter(
1077 fx_info->resample_filter[i]);
1078 fx_info->resample_filter=(ResampleFilter **) RelinquishMagickMemory(
1079 fx_info->resample_filter);
1080 fx_info->random_info=DestroyRandomInfo(fx_info->random_info);
1081 fx_info=(FxInfo *) RelinquishMagickMemory(fx_info);
1086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1090 + 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 %
1094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1096 % FxEvaluateChannelExpression() evaluates an expression and returns the
1099 % The format of the FxEvaluateExpression method is:
1101 % MagickRealType FxEvaluateChannelExpression(FxInfo *fx_info,
1102 % const ChannelType channel,const ssize_t x,const ssize_t y,
1103 % MagickRealType *alpha,Exceptioninfo *exception)
1104 % MagickRealType FxEvaluateExpression(FxInfo *fx_info,
1105 % MagickRealType *alpha,Exceptioninfo *exception)
1107 % A description of each parameter follows:
1109 % o fx_info: the fx info.
1111 % o channel: the channel.
1113 % o x,y: the pixel position.
1115 % o alpha: the result.
1117 % o exception: return any errors or warnings in this structure.
1121 static inline double MagickMax(const double x,const double y)
1128 static inline double MagickMin(const double x,const double y)
1135 static MagickRealType FxChannelStatistics(FxInfo *fx_info,const Image *image,
1136 ChannelType channel,const char *symbol,ExceptionInfo *exception)
1140 statistic[MaxTextExtent];
1148 for (p=symbol; (*p != '.') && (*p != '\0'); p++) ;
1150 switch (*++p) /* e.g. depth.r */
1152 case 'r': channel=RedChannel; break;
1153 case 'g': channel=GreenChannel; break;
1154 case 'b': channel=BlueChannel; break;
1155 case 'c': channel=CyanChannel; break;
1156 case 'm': channel=MagentaChannel; break;
1157 case 'y': channel=YellowChannel; break;
1158 case 'k': channel=BlackChannel; break;
1161 (void) FormatMagickString(key,MaxTextExtent,"%p.%.20g.%s",(void *) image,
1162 (double) channel,symbol);
1163 value=(const char *) GetValueFromSplayTree(fx_info->symbols,key);
1164 if (value != (const char *) NULL)
1165 return(QuantumScale*StringToDouble(value));
1166 (void) DeleteNodeFromSplayTree(fx_info->symbols,key);
1167 if (LocaleNCompare(symbol,"depth",5) == 0)
1172 depth=GetImageChannelDepth(image,channel,exception);
1173 (void) FormatMagickString(statistic,MaxTextExtent,"%.20g",(double)
1176 if (LocaleNCompare(symbol,"kurtosis",8) == 0)
1182 (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
1184 (void) FormatMagickString(statistic,MaxTextExtent,"%g",kurtosis);
1186 if (LocaleNCompare(symbol,"maxima",6) == 0)
1192 (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
1193 (void) FormatMagickString(statistic,MaxTextExtent,"%g",maxima);
1195 if (LocaleNCompare(symbol,"mean",4) == 0)
1201 (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
1203 (void) FormatMagickString(statistic,MaxTextExtent,"%g",mean);
1205 if (LocaleNCompare(symbol,"minima",6) == 0)
1211 (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
1212 (void) FormatMagickString(statistic,MaxTextExtent,"%g",minima);
1214 if (LocaleNCompare(symbol,"skewness",8) == 0)
1220 (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
1222 (void) FormatMagickString(statistic,MaxTextExtent,"%g",skewness);
1224 if (LocaleNCompare(symbol,"standard_deviation",18) == 0)
1230 (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
1232 (void) FormatMagickString(statistic,MaxTextExtent,"%g",
1233 standard_deviation);
1235 (void) AddValueToSplayTree(fx_info->symbols,ConstantString(key),
1236 ConstantString(statistic));
1237 return(QuantumScale*StringToDouble(statistic));
1240 static MagickRealType
1241 FxEvaluateSubexpression(FxInfo *,const ChannelType,const ssize_t,
1242 const ssize_t,const char *,MagickRealType *,ExceptionInfo *);
1244 static inline MagickRealType FxMax(FxInfo *fx_info,const ChannelType channel,
1245 const ssize_t x,const ssize_t y,const char *expression,
1246 ExceptionInfo *exception)
1252 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression,&beta,exception);
1253 return((MagickRealType) MagickMax((double) alpha,(double) beta));
1256 static inline MagickRealType FxMin(FxInfo *fx_info,ChannelType channel,
1257 const ssize_t x,const ssize_t y,const char *expression,
1258 ExceptionInfo *exception)
1264 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression,&beta,exception);
1265 return((MagickRealType) MagickMin((double) alpha,(double) beta));
1268 static inline const char *FxSubexpression(const char *expression,
1269 ExceptionInfo *exception)
1278 subexpression=expression;
1279 while ((*subexpression != '\0') &&
1280 ((level != 1) || (strchr(")",(int) *subexpression) == (char *) NULL)))
1282 if (strchr("(",(int) *subexpression) != (char *) NULL)
1285 if (strchr(")",(int) *subexpression) != (char *) NULL)
1289 if (*subexpression == '\0')
1290 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1291 "UnbalancedParenthesis","`%s'",expression);
1292 return(subexpression);
1295 static MagickRealType FxGetSymbol(FxInfo *fx_info,const ChannelType channel,
1296 const ssize_t x,const ssize_t y,const char *expression,
1297 ExceptionInfo *exception)
1301 subexpression[MaxTextExtent],
1302 symbol[MaxTextExtent];
1331 i=GetImageIndexInList(fx_info->images);
1335 if (isalpha((int) *(p+1)) == 0)
1337 if (strchr("suv",(int) *p) != (char *) NULL)
1344 i=GetImageIndexInList(fx_info->images);
1347 case 'u': i=0; break;
1348 case 'v': i=1; break;
1355 for (p++; *p != '\0'; )
1369 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
1371 i=(ssize_t) (alpha+0.5);
1377 if ((isalpha((int) *(p+1)) == 0) && (*p == 'p'))
1384 for (p++; *p != '\0'; )
1398 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
1409 for (p++; *p != '\0'; )
1423 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
1433 length=GetImageListLength(fx_info->images);
1435 i+=(ssize_t) length;
1437 image=GetImageFromList(fx_info->images,i);
1438 if (image == (Image *) NULL)
1440 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1441 "NoSuchImage","`%s'",expression);
1444 (void) ResamplePixelColor(fx_info->resample_filter[i],point.x,point.y,&pixel);
1445 if ((strlen(p) > 2) &&
1446 (LocaleCompare(p,"intensity") != 0) &&
1447 (LocaleCompare(p,"luminance") != 0) &&
1448 (LocaleCompare(p,"hue") != 0) &&
1449 (LocaleCompare(p,"saturation") != 0) &&
1450 (LocaleCompare(p,"lightness") != 0))
1453 name[MaxTextExtent];
1455 (void) CopyMagickString(name,p,MaxTextExtent);
1456 for (q=name+(strlen(name)-1); q > name; q--)
1466 if ((strlen(name) > 2) &&
1467 (GetValueFromSplayTree(fx_info->symbols,name) == (const char *) NULL))
1472 color=(MagickPixelPacket *) GetValueFromSplayTree(fx_info->colors,
1474 if (color != (MagickPixelPacket *) NULL)
1480 if (QueryMagickColor(name,&pixel,fx_info->exception) != MagickFalse)
1482 (void) AddValueToSplayTree(fx_info->colors,ConstantString(name),
1483 CloneMagickPixelPacket(&pixel));
1488 (void) CopyMagickString(symbol,p,MaxTextExtent);
1489 StripString(symbol);
1490 if (*symbol == '\0')
1494 case RedChannel: return(QuantumScale*pixel.red);
1495 case GreenChannel: return(QuantumScale*pixel.green);
1496 case BlueChannel: return(QuantumScale*pixel.blue);
1497 case OpacityChannel:
1499 if (pixel.matte == MagickFalse)
1501 fx_info->matte=MagickFalse;
1504 return((MagickRealType) (QuantumScale*GetAlphaPixelComponent(&pixel)));
1508 if (image->colorspace != CMYKColorspace)
1510 (void) ThrowMagickException(exception,GetMagickModule(),
1511 OptionError,"ColorSeparatedImageRequired","`%s'",
1515 return(QuantumScale*pixel.index);
1520 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1521 "UnableToParseExpression","`%s'",p);
1529 if (LocaleCompare(symbol,"a") == 0)
1530 return((MagickRealType) (QuantumScale*GetAlphaPixelComponent(&pixel)));
1536 if (LocaleCompare(symbol,"b") == 0)
1537 return(QuantumScale*pixel.blue);
1543 if (LocaleNCompare(symbol,"channel",7) == 0)
1551 flags=ParseGeometry(symbol+7,&channel_info);
1552 if (image->colorspace == CMYKColorspace)
1557 if ((flags & RhoValue) == 0)
1559 return(channel_info.rho);
1561 case MagentaChannel:
1563 if ((flags & SigmaValue) == 0)
1565 return(channel_info.sigma);
1569 if ((flags & XiValue) == 0)
1571 return(channel_info.xi);
1575 if ((flags & PsiValue) == 0)
1577 return(channel_info.psi);
1579 case OpacityChannel:
1581 if ((flags & ChiValue) == 0)
1583 return(channel_info.chi);
1592 if ((flags & RhoValue) == 0)
1594 return(channel_info.rho);
1598 if ((flags & SigmaValue) == 0)
1600 return(channel_info.sigma);
1604 if ((flags & XiValue) == 0)
1606 return(channel_info.xi);
1608 case OpacityChannel:
1610 if ((flags & PsiValue) == 0)
1612 return(channel_info.psi);
1616 if ((flags & ChiValue) == 0)
1618 return(channel_info.chi);
1625 if (LocaleCompare(symbol,"c") == 0)
1626 return(QuantumScale*pixel.red);
1632 if (LocaleNCompare(symbol,"depth",5) == 0)
1633 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1639 if (LocaleCompare(symbol,"g") == 0)
1640 return(QuantumScale*pixel.green);
1646 if (LocaleNCompare(symbol,"kurtosis",8) == 0)
1647 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1648 if (LocaleCompare(symbol,"k") == 0)
1650 if (image->colorspace != CMYKColorspace)
1652 (void) ThrowMagickException(exception,GetMagickModule(),
1653 OptionError,"ColorSeparatedImageRequired","`%s'",
1657 return(QuantumScale*pixel.index);
1664 if (LocaleCompare(symbol,"h") == 0)
1665 return((MagickRealType) image->rows);
1666 if (LocaleCompare(symbol,"hue") == 0)
1673 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
1674 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
1682 if ((LocaleCompare(symbol,"image.depth") == 0) ||
1683 (LocaleCompare(symbol,"image.minima") == 0) ||
1684 (LocaleCompare(symbol,"image.maxima") == 0) ||
1685 (LocaleCompare(symbol,"image.mean") == 0) ||
1686 (LocaleCompare(symbol,"image.kurtosis") == 0) ||
1687 (LocaleCompare(symbol,"image.skewness") == 0) ||
1688 (LocaleCompare(symbol,"image.standard_deviation") == 0))
1689 return(FxChannelStatistics(fx_info,image,channel,symbol+6,exception));
1690 if (LocaleCompare(symbol,"image.resolution.x") == 0)
1691 return(image->x_resolution);
1692 if (LocaleCompare(symbol,"image.resolution.y") == 0)
1693 return(image->y_resolution);
1694 if (LocaleCompare(symbol,"intensity") == 0)
1695 return(QuantumScale*MagickPixelIntensityToQuantum(&pixel));
1696 if (LocaleCompare(symbol,"i") == 0)
1697 return((MagickRealType) x);
1703 if (LocaleCompare(symbol,"j") == 0)
1704 return((MagickRealType) y);
1710 if (LocaleCompare(symbol,"lightness") == 0)
1717 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
1718 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
1721 if (LocaleCompare(symbol,"luminance") == 0)
1726 luminence=0.2126*pixel.red+0.7152*pixel.green+0.0722*pixel.blue;
1727 return(QuantumScale*luminence);
1734 if (LocaleNCompare(symbol,"maxima",6) == 0)
1735 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1736 if (LocaleNCompare(symbol,"mean",4) == 0)
1737 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1738 if (LocaleNCompare(symbol,"minima",6) == 0)
1739 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1740 if (LocaleCompare(symbol,"m") == 0)
1741 return(QuantumScale*pixel.blue);
1747 if (LocaleCompare(symbol,"n") == 0)
1748 return((MagickRealType) GetImageListLength(fx_info->images));
1754 if (LocaleCompare(symbol,"o") == 0)
1755 return(QuantumScale*pixel.opacity);
1761 if (LocaleCompare(symbol,"page.height") == 0)
1762 return((MagickRealType) image->page.height);
1763 if (LocaleCompare(symbol,"page.width") == 0)
1764 return((MagickRealType) image->page.width);
1765 if (LocaleCompare(symbol,"page.x") == 0)
1766 return((MagickRealType) image->page.x);
1767 if (LocaleCompare(symbol,"page.y") == 0)
1768 return((MagickRealType) image->page.y);
1774 if (LocaleCompare(symbol,"resolution.x") == 0)
1775 return(image->x_resolution);
1776 if (LocaleCompare(symbol,"resolution.y") == 0)
1777 return(image->y_resolution);
1778 if (LocaleCompare(symbol,"r") == 0)
1779 return(QuantumScale*pixel.red);
1785 if (LocaleCompare(symbol,"saturation") == 0)
1792 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
1793 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
1796 if (LocaleNCompare(symbol,"skewness",8) == 0)
1797 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1798 if (LocaleNCompare(symbol,"standard_deviation",18) == 0)
1799 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1805 if (LocaleCompare(symbol,"t") == 0)
1806 return((MagickRealType) fx_info->images->scene);
1812 if (LocaleCompare(symbol,"w") == 0)
1813 return((MagickRealType) image->columns);
1819 if (LocaleCompare(symbol,"y") == 0)
1820 return(QuantumScale*pixel.green);
1826 if (LocaleCompare(symbol,"z") == 0)
1831 depth=(MagickRealType) GetImageChannelDepth(image,channel,
1832 fx_info->exception);
1840 value=(const char *) GetValueFromSplayTree(fx_info->symbols,symbol);
1841 if (value != (const char *) NULL)
1842 return((MagickRealType) StringToDouble(value));
1843 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1844 "UnableToParseExpression","`%s'",symbol);
1848 static const char *FxOperatorPrecedence(const char *expression,
1849 ExceptionInfo *exception)
1853 UndefinedPrecedence,
1855 BitwiseComplementPrecedence,
1857 ExponentialNotationPrecedence,
1861 RelationalPrecedence,
1862 EquivalencyPrecedence,
1863 BitwiseAndPrecedence,
1864 BitwiseOrPrecedence,
1865 LogicalAndPrecedence,
1866 LogicalOrPrecedence,
1868 AssignmentPrecedence,
1888 subexpression=(const char *) NULL;
1889 target=NullPrecedence;
1890 while (*expression != '\0')
1892 precedence=UndefinedPrecedence;
1893 if ((isspace((int) ((char) *expression)) != 0) || (c == (int) '@'))
1898 switch (*expression)
1903 if (LocaleNCompare(expression,"atan2",5) == 0)
1913 if ((LocaleNCompare(expression,"j0",2) == 0) ||
1914 (LocaleNCompare(expression,"j1",2) == 0))
1923 while (isxdigit((int) ((unsigned char) *(expression+1))) != 0)
1930 if ((c == (int) '{') || (c == (int) '['))
1933 if ((c == (int) '}') || (c == (int) ']'))
1936 switch ((unsigned char) *expression)
1941 precedence=BitwiseComplementPrecedence;
1947 precedence=ExponentPrecedence;
1952 if (((c != 0) && ((isdigit((int) ((char) c)) != 0) ||
1953 (strchr(")",c) != (char *) NULL))) &&
1954 (((islower((int) ((char) *expression)) != 0) ||
1955 (strchr("(",(int) *expression) != (char *) NULL)) ||
1956 ((isdigit((int) ((char) c)) == 0) &&
1957 (isdigit((int) ((char) *expression)) != 0))) &&
1958 (strchr("xy",(int) *expression) == (char *) NULL))
1959 precedence=MultiplyPrecedence;
1966 precedence=MultiplyPrecedence;
1972 if ((strchr("(+-/*%:&^|<>~,",c) == (char *) NULL) ||
1974 precedence=AdditionPrecedence;
1977 case LeftShiftOperator:
1978 case RightShiftOperator:
1980 precedence=ShiftPrecedence;
1984 case LessThanEqualOperator:
1985 case GreaterThanEqualOperator:
1988 precedence=RelationalPrecedence;
1992 case NotEqualOperator:
1994 precedence=EquivalencyPrecedence;
1999 precedence=BitwiseAndPrecedence;
2004 precedence=BitwiseOrPrecedence;
2007 case LogicalAndOperator:
2009 precedence=LogicalAndPrecedence;
2012 case LogicalOrOperator:
2014 precedence=LogicalOrPrecedence;
2017 case ExponentialNotation:
2019 precedence=ExponentialNotationPrecedence;
2025 precedence=TernaryPrecedence;
2030 precedence=AssignmentPrecedence;
2035 precedence=CommaPrecedence;
2040 precedence=SeparatorPrecedence;
2044 if ((precedence == BitwiseComplementPrecedence) ||
2045 (precedence == TernaryPrecedence) ||
2046 (precedence == AssignmentPrecedence))
2048 if (precedence > target)
2051 Right-to-left associativity.
2054 subexpression=expression;
2058 if (precedence >= target)
2061 Left-to-right associativity.
2064 subexpression=expression;
2066 if (strchr("(",(int) *expression) != (char *) NULL)
2067 expression=FxSubexpression(expression,exception);
2068 c=(int) (*expression++);
2070 return(subexpression);
2073 static MagickRealType FxEvaluateSubexpression(FxInfo *fx_info,
2074 const ChannelType channel,const ssize_t x,const ssize_t y,
2075 const char *expression,MagickRealType *beta,ExceptionInfo *exception)
2079 subexpression[MaxTextExtent];
2089 if (exception->severity != UndefinedException)
2091 while (isspace((int) *expression) != 0)
2093 if (*expression == '\0')
2095 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2096 "MissingExpression","`%s'",expression);
2099 *subexpression='\0';
2100 p=FxOperatorPrecedence(expression,exception);
2101 if (p != (const char *) NULL)
2103 (void) CopyMagickString(subexpression,expression,(size_t)
2105 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,beta,
2107 switch ((unsigned char) *p)
2111 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2112 *beta=(MagickRealType) (~(size_t) *beta);
2117 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2118 return(*beta == 0.0 ? 1.0 : 0.0);
2122 *beta=pow((double) alpha,(double) FxEvaluateSubexpression(fx_info,
2123 channel,x,y,++p,beta,exception));
2127 case ExponentialNotation:
2129 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2130 return(alpha*(*beta));
2134 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2137 if (exception->severity == UndefinedException)
2138 (void) ThrowMagickException(exception,GetMagickModule(),
2139 OptionError,"DivideByZero","`%s'",expression);
2142 return(alpha/(*beta));
2146 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2147 *beta=fabs(floor(((double) *beta)+0.5));
2150 (void) ThrowMagickException(exception,GetMagickModule(),
2151 OptionError,"DivideByZero","`%s'",expression);
2154 return(fmod((double) alpha,(double) *beta));
2158 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2159 return(alpha+(*beta));
2163 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2164 return(alpha-(*beta));
2166 case LeftShiftOperator:
2168 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2169 *beta=(MagickRealType) ((size_t) (alpha+0.5) << (size_t)
2173 case RightShiftOperator:
2175 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2176 *beta=(MagickRealType) ((size_t) (alpha+0.5) >> (size_t)
2182 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2183 return(alpha < *beta ? 1.0 : 0.0);
2185 case LessThanEqualOperator:
2187 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2188 return(alpha <= *beta ? 1.0 : 0.0);
2192 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2193 return(alpha > *beta ? 1.0 : 0.0);
2195 case GreaterThanEqualOperator:
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(fabs(alpha-(*beta)) <= MagickEpsilon ? 1.0 : 0.0);
2205 case NotEqualOperator:
2207 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2208 return(fabs(alpha-(*beta)) > MagickEpsilon ? 1.0 : 0.0);
2212 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2213 *beta=(MagickRealType) ((size_t) (alpha+0.5) & (size_t)
2219 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2220 *beta=(MagickRealType) ((size_t) (alpha+0.5) | (size_t)
2224 case LogicalAndOperator:
2226 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2227 *beta=(alpha > 0.0) && (gamma > 0.0) ? 1.0 : 0.0;
2230 case LogicalOrOperator:
2232 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2233 *beta=(alpha > 0.0) || (gamma > 0.0) ? 1.0 : 0.0;
2241 (void) CopyMagickString(subexpression,++p,MaxTextExtent);
2243 p=StringToken(":",&q);
2244 if (q == (char *) NULL)
2246 (void) ThrowMagickException(exception,GetMagickModule(),
2247 OptionError,"UnableToParseExpression","`%s'",subexpression);
2250 if (fabs((double) alpha) > MagickEpsilon)
2251 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,beta,exception);
2253 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,q,beta,exception);
2259 numeric[MaxTextExtent];
2262 while (isalpha((int) ((unsigned char) *q)) != 0)
2266 (void) ThrowMagickException(exception,GetMagickModule(),
2267 OptionError,"UnableToParseExpression","`%s'",subexpression);
2270 ClearMagickException(exception);
2271 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2272 (void) FormatMagickString(numeric,MaxTextExtent,"%g",(double)
2274 (void) DeleteNodeFromSplayTree(fx_info->symbols,subexpression);
2275 (void) AddValueToSplayTree(fx_info->symbols,ConstantString(
2276 subexpression),ConstantString(numeric));
2281 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2286 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2291 gamma=alpha*FxEvaluateSubexpression(fx_info,channel,x,y,p,beta,
2297 if (strchr("(",(int) *expression) != (char *) NULL)
2299 (void) CopyMagickString(subexpression,expression+1,MaxTextExtent);
2300 subexpression[strlen(subexpression)-1]='\0';
2301 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,beta,
2305 switch (*expression)
2309 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta,
2315 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta,
2321 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta,
2323 return((MagickRealType) (~(size_t) (gamma+0.5)));
2328 if (LocaleNCompare(expression,"abs",3) == 0)
2330 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2332 return((MagickRealType) fabs((double) alpha));
2334 if (LocaleNCompare(expression,"acos",4) == 0)
2336 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2338 return((MagickRealType) acos((double) alpha));
2340 #if defined(MAGICKCORE_HAVE_J1)
2341 if (LocaleNCompare(expression,"airy",4) == 0)
2343 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2347 gamma=2.0*j1((double) (MagickPI*alpha))/(MagickPI*alpha);
2348 return(gamma*gamma);
2351 if (LocaleNCompare(expression,"asin",4) == 0)
2353 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2355 return((MagickRealType) asin((double) alpha));
2357 if (LocaleNCompare(expression,"alt",3) == 0)
2359 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2361 return(((ssize_t) alpha) & 0x01 ? -1.0 : 1.0);
2363 if (LocaleNCompare(expression,"atan2",5) == 0)
2365 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2367 return((MagickRealType) atan2((double) alpha,(double) *beta));
2369 if (LocaleNCompare(expression,"atan",4) == 0)
2371 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2373 return((MagickRealType) atan((double) alpha));
2375 if (LocaleCompare(expression,"a") == 0)
2376 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2382 if (LocaleCompare(expression,"b") == 0)
2383 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2389 if (LocaleNCompare(expression,"ceil",4) == 0)
2391 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2393 return((MagickRealType) ceil((double) alpha));
2395 if (LocaleNCompare(expression,"cosh",4) == 0)
2397 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2399 return((MagickRealType) cosh((double) alpha));
2401 if (LocaleNCompare(expression,"cos",3) == 0)
2403 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2405 return((MagickRealType) cos((double) alpha));
2407 if (LocaleCompare(expression,"c") == 0)
2408 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2414 if (LocaleNCompare(expression,"debug",5) == 0)
2419 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2421 if (fx_info->images->colorspace == CMYKColorspace)
2424 case CyanChannel: type="cyan"; break;
2425 case MagentaChannel: type="magenta"; break;
2426 case YellowChannel: type="yellow"; break;
2427 case OpacityChannel: type="opacity"; break;
2428 case BlackChannel: type="black"; break;
2429 default: type="unknown"; break;
2434 case RedChannel: type="red"; break;
2435 case GreenChannel: type="green"; break;
2436 case BlueChannel: type="blue"; break;
2437 case OpacityChannel: type="opacity"; break;
2438 default: type="unknown"; break;
2440 (void) CopyMagickString(subexpression,expression+6,MaxTextExtent);
2441 if (strlen(subexpression) > 1)
2442 subexpression[strlen(subexpression)-1]='\0';
2443 if (fx_info->file != (FILE *) NULL)
2444 (void) fprintf(fx_info->file,"%s[%.20g,%.20g].%s: %s=%.*g\n",
2445 fx_info->images->filename,(double) x,(double) y,type,
2446 subexpression,GetMagickPrecision(),(double) alpha);
2454 if (LocaleCompare(expression,"epsilon") == 0)
2455 return((MagickRealType) MagickEpsilon);
2456 if (LocaleNCompare(expression,"exp",3) == 0)
2458 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2460 return((MagickRealType) exp((double) alpha));
2462 if (LocaleCompare(expression,"e") == 0)
2463 return((MagickRealType) 2.7182818284590452354);
2469 if (LocaleNCompare(expression,"floor",5) == 0)
2471 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2473 return((MagickRealType) floor((double) alpha));
2480 if (LocaleCompare(expression,"g") == 0)
2481 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2487 if (LocaleCompare(expression,"h") == 0)
2488 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2489 if (LocaleCompare(expression,"hue") == 0)
2490 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2491 if (LocaleNCompare(expression,"hypot",5) == 0)
2493 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2495 return((MagickRealType) hypot((double) alpha,(double) *beta));
2502 if (LocaleCompare(expression,"k") == 0)
2503 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2509 if (LocaleCompare(expression,"intensity") == 0)
2510 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2511 if (LocaleNCompare(expression,"int",3) == 0)
2513 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2515 return((MagickRealType) floor(alpha+0.5));
2517 if (LocaleCompare(expression,"i") == 0)
2518 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2524 if (LocaleCompare(expression,"j") == 0)
2525 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2526 #if defined(MAGICKCORE_HAVE_J0)
2527 if (LocaleNCompare(expression,"j0",2) == 0)
2529 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta,
2531 return((MagickRealType) j0((double) alpha));
2534 #if defined(MAGICKCORE_HAVE_J1)
2535 if (LocaleNCompare(expression,"j1",2) == 0)
2537 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta,
2539 return((MagickRealType) j1((double) alpha));
2542 #if defined(MAGICKCORE_HAVE_J1)
2543 if (LocaleNCompare(expression,"jinc",4) == 0)
2545 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2549 gamma=(MagickRealType) (2.0*j1((double) (MagickPI*alpha))/
2559 if (LocaleNCompare(expression,"ln",2) == 0)
2561 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta,
2563 return((MagickRealType) log((double) alpha));
2565 if (LocaleNCompare(expression,"logtwo",4) == 0)
2567 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2569 return((MagickRealType) log10((double) alpha))/log10(2.0);
2571 if (LocaleNCompare(expression,"log",3) == 0)
2573 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2575 return((MagickRealType) log10((double) alpha));
2577 if (LocaleCompare(expression,"lightness") == 0)
2578 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2584 if (LocaleCompare(expression,"MaxRGB") == 0)
2585 return((MagickRealType) QuantumRange);
2586 if (LocaleNCompare(expression,"maxima",6) == 0)
2588 if (LocaleNCompare(expression,"max",3) == 0)
2589 return(FxMax(fx_info,channel,x,y,expression+3,exception));
2590 if (LocaleNCompare(expression,"minima",6) == 0)
2592 if (LocaleNCompare(expression,"min",3) == 0)
2593 return(FxMin(fx_info,channel,x,y,expression+3,exception));
2594 if (LocaleNCompare(expression,"mod",3) == 0)
2596 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2598 return((MagickRealType) fmod((double) alpha,(double) *beta));
2600 if (LocaleCompare(expression,"m") == 0)
2601 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2607 if (LocaleCompare(expression,"n") == 0)
2608 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2614 if (LocaleCompare(expression,"Opaque") == 0)
2616 if (LocaleCompare(expression,"o") == 0)
2617 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2623 if (LocaleCompare(expression,"pi") == 0)
2624 return((MagickRealType) MagickPI);
2625 if (LocaleNCompare(expression,"pow",3) == 0)
2627 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2629 return((MagickRealType) pow((double) alpha,(double) *beta));
2631 if (LocaleCompare(expression,"p") == 0)
2632 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2638 if (LocaleCompare(expression,"QuantumRange") == 0)
2639 return((MagickRealType) QuantumRange);
2640 if (LocaleCompare(expression,"QuantumScale") == 0)
2641 return((MagickRealType) QuantumScale);
2647 if (LocaleNCompare(expression,"rand",4) == 0)
2648 return((MagickRealType) GetPseudoRandomValue(fx_info->random_info));
2649 if (LocaleNCompare(expression,"round",5) == 0)
2651 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2654 return((MagickRealType) floor((double) alpha+0.5));
2655 return((MagickRealType) ceil((double) alpha-0.5));
2657 if (LocaleCompare(expression,"r") == 0)
2658 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2664 if (LocaleCompare(expression,"saturation") == 0)
2665 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2666 if (LocaleNCompare(expression,"sign",4) == 0)
2668 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2670 return(alpha < 0.0 ? -1.0 : 1.0);
2672 if (LocaleNCompare(expression,"sinc",4) == 0)
2674 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2678 gamma=(MagickRealType) (sin((double) (MagickPI*alpha))/
2682 if (LocaleNCompare(expression,"sinh",4) == 0)
2684 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2686 return((MagickRealType) sinh((double) alpha));
2688 if (LocaleNCompare(expression,"sin",3) == 0)
2690 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2692 return((MagickRealType) sin((double) alpha));
2694 if (LocaleNCompare(expression,"sqrt",4) == 0)
2696 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2698 return((MagickRealType) sqrt((double) alpha));
2700 if (LocaleCompare(expression,"s") == 0)
2701 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2707 if (LocaleNCompare(expression,"tanh",4) == 0)
2709 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2711 return((MagickRealType) tanh((double) alpha));
2713 if (LocaleNCompare(expression,"tan",3) == 0)
2715 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2717 return((MagickRealType) tan((double) alpha));
2719 if (LocaleCompare(expression,"Transparent") == 0)
2721 if (LocaleCompare(expression,"t") == 0)
2722 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2728 if (LocaleCompare(expression,"u") == 0)
2729 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2735 if (LocaleCompare(expression,"v") == 0)
2736 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2742 if (LocaleCompare(expression,"w") == 0)
2743 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2749 if (LocaleCompare(expression,"y") == 0)
2750 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2756 if (LocaleCompare(expression,"z") == 0)
2757 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2763 q=(char *) expression;
2764 alpha=strtod(expression,&q);
2765 if (q == expression)
2766 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2770 MagickExport MagickBooleanType FxEvaluateExpression(FxInfo *fx_info,
2771 MagickRealType *alpha,ExceptionInfo *exception)
2776 status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
2780 MagickExport MagickBooleanType FxPreprocessExpression(FxInfo *fx_info,
2781 MagickRealType *alpha,ExceptionInfo *exception)
2790 fx_info->file=(FILE *) NULL;
2791 status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
2796 MagickExport MagickBooleanType FxEvaluateChannelExpression(FxInfo *fx_info,
2797 const ChannelType channel,const ssize_t x,const ssize_t y,
2798 MagickRealType *alpha,ExceptionInfo *exception)
2804 *alpha=FxEvaluateSubexpression(fx_info,channel,x,y,fx_info->expression,&beta,
2806 return(exception->severity == OptionError ? MagickFalse : MagickTrue);
2810 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2818 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2820 % FxImage() applies a mathematical expression to the specified image.
2822 % The format of the FxImage method is:
2824 % Image *FxImage(const Image *image,const char *expression,
2825 % ExceptionInfo *exception)
2826 % Image *FxImageChannel(const Image *image,const ChannelType channel,
2827 % const char *expression,ExceptionInfo *exception)
2829 % A description of each parameter follows:
2831 % o image: the image.
2833 % o channel: the channel.
2835 % o expression: A mathematical expression.
2837 % o exception: return any errors or warnings in this structure.
2841 static FxInfo **DestroyFxThreadSet(FxInfo **fx_info)
2846 assert(fx_info != (FxInfo **) NULL);
2847 for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
2848 if (fx_info[i] != (FxInfo *) NULL)
2849 fx_info[i]=DestroyFxInfo(fx_info[i]);
2850 fx_info=(FxInfo **) RelinquishAlignedMemory(fx_info);
2854 static FxInfo **AcquireFxThreadSet(const Image *image,const char *expression,
2855 ExceptionInfo *exception)
2872 number_threads=GetOpenMPMaximumThreads();
2873 fx_info=(FxInfo **) AcquireAlignedMemory(number_threads,sizeof(*fx_info));
2874 if (fx_info == (FxInfo **) NULL)
2875 return((FxInfo **) NULL);
2876 (void) ResetMagickMemory(fx_info,0,number_threads*sizeof(*fx_info));
2877 if (*expression != '@')
2878 fx_expression=ConstantString(expression);
2880 fx_expression=FileToString(expression+1,~0,exception);
2881 for (i=0; i < (ssize_t) number_threads; i++)
2883 fx_info[i]=AcquireFxInfo(image,fx_expression);
2884 if (fx_info[i] == (FxInfo *) NULL)
2885 return(DestroyFxThreadSet(fx_info));
2886 (void) FxPreprocessExpression(fx_info[i],&alpha,fx_info[i]->exception);
2888 fx_expression=DestroyString(fx_expression);
2892 MagickExport Image *FxImage(const Image *image,const char *expression,
2893 ExceptionInfo *exception)
2898 fx_image=FxImageChannel(image,GrayChannel,expression,exception);
2902 MagickExport Image *FxImageChannel(const Image *image,const ChannelType channel,
2903 const char *expression,ExceptionInfo *exception)
2905 #define FxImageTag "Fx/Image"
2928 assert(image != (Image *) NULL);
2929 assert(image->signature == MagickSignature);
2930 if (image->debug != MagickFalse)
2931 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2932 fx_image=CloneImage(image,0,0,MagickTrue,exception);
2933 if (fx_image == (Image *) NULL)
2934 return((Image *) NULL);
2935 if (SetImageStorageClass(fx_image,DirectClass) == MagickFalse)
2937 InheritException(exception,&fx_image->exception);
2938 fx_image=DestroyImage(fx_image);
2939 return((Image *) NULL);
2941 fx_info=AcquireFxThreadSet(image,expression,exception);
2942 if (fx_info == (FxInfo **) NULL)
2944 fx_image=DestroyImage(fx_image);
2945 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2947 status=FxPreprocessExpression(fx_info[0],&alpha,exception);
2948 if (status == MagickFalse)
2950 fx_image=DestroyImage(fx_image);
2951 fx_info=DestroyFxThreadSet(fx_info);
2952 return((Image *) NULL);
2959 fx_view=AcquireCacheView(fx_image);
2960 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2961 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2963 for (y=0; y < (ssize_t) fx_image->rows; y++)
2971 register IndexPacket
2972 *restrict fx_indexes;
2977 register PixelPacket
2980 if (status == MagickFalse)
2982 q=GetCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception);
2983 if (q == (PixelPacket *) NULL)
2988 fx_indexes=GetCacheViewAuthenticIndexQueue(fx_view);
2989 id=GetOpenMPThreadId();
2991 for (x=0; x < (ssize_t) fx_image->columns; x++)
2993 if ((channel & RedChannel) != 0)
2995 (void) FxEvaluateChannelExpression(fx_info[id],RedChannel,x,y,
2997 q->red=ClampToQuantum((MagickRealType) QuantumRange*alpha);
2999 if ((channel & GreenChannel) != 0)
3001 (void) FxEvaluateChannelExpression(fx_info[id],GreenChannel,x,y,
3003 q->green=ClampToQuantum((MagickRealType) QuantumRange*alpha);
3005 if ((channel & BlueChannel) != 0)
3007 (void) FxEvaluateChannelExpression(fx_info[id],BlueChannel,x,y,
3009 q->blue=ClampToQuantum((MagickRealType) QuantumRange*alpha);
3011 if ((channel & OpacityChannel) != 0)
3013 (void) FxEvaluateChannelExpression(fx_info[id],OpacityChannel,x,y,
3015 if (image->matte == MagickFalse)
3016 q->opacity=ClampToQuantum((MagickRealType) QuantumRange*alpha);
3018 q->opacity=ClampToQuantum((MagickRealType) (QuantumRange-
3019 QuantumRange*alpha));
3021 if (((channel & IndexChannel) != 0) &&
3022 (fx_image->colorspace == CMYKColorspace))
3024 (void) FxEvaluateChannelExpression(fx_info[id],IndexChannel,x,y,
3026 fx_indexes[x]=(IndexPacket) ClampToQuantum((MagickRealType)
3027 QuantumRange*alpha);
3031 if (SyncCacheViewAuthenticPixels(fx_view,exception) == MagickFalse)
3033 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3038 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3039 #pragma omp critical (MagickCore_FxImageChannel)
3041 proceed=SetImageProgress(image,FxImageTag,progress++,image->rows);
3042 if (proceed == MagickFalse)
3046 fx_image->matte=fx_info[0]->matte;
3047 fx_view=DestroyCacheView(fx_view);
3048 fx_info=DestroyFxThreadSet(fx_info);
3049 if (status == MagickFalse)
3050 fx_image=DestroyImage(fx_image);
3055 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3059 % I m p l o d e I m a g e %
3063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3065 % ImplodeImage() creates a new image that is a copy of an existing
3066 % one with the image pixels "implode" by the specified percentage. It
3067 % allocates the memory necessary for the new Image structure and returns a
3068 % pointer to the new image.
3070 % The format of the ImplodeImage method is:
3072 % Image *ImplodeImage(const Image *image,const double amount,
3073 % ExceptionInfo *exception)
3075 % A description of each parameter follows:
3077 % o implode_image: Method ImplodeImage returns a pointer to the image
3078 % after it is implode. A null image is returned if there is a memory
3081 % o image: the image.
3083 % o amount: Define the extent of the implosion.
3085 % o exception: return any errors or warnings in this structure.
3088 MagickExport Image *ImplodeImage(const Image *image,const double amount,
3089 ExceptionInfo *exception)
3091 #define ImplodeImageTag "Implode/Image"
3117 **restrict resample_filter;
3123 Initialize implode image attributes.
3125 assert(image != (Image *) NULL);
3126 assert(image->signature == MagickSignature);
3127 if (image->debug != MagickFalse)
3128 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3129 assert(exception != (ExceptionInfo *) NULL);
3130 assert(exception->signature == MagickSignature);
3131 implode_image=CloneImage(image,0,0,MagickTrue,exception);
3132 if (implode_image == (Image *) NULL)
3133 return((Image *) NULL);
3134 if (SetImageStorageClass(implode_image,DirectClass) == MagickFalse)
3136 InheritException(exception,&implode_image->exception);
3137 implode_image=DestroyImage(implode_image);
3138 return((Image *) NULL);
3140 if (implode_image->background_color.opacity != OpaqueOpacity)
3141 implode_image->matte=MagickTrue;
3143 Compute scaling factor.
3147 center.x=0.5*image->columns;
3148 center.y=0.5*image->rows;
3150 if (image->columns > image->rows)
3151 scale.y=(double) image->columns/(double) image->rows;
3153 if (image->columns < image->rows)
3155 scale.x=(double) image->rows/(double) image->columns;
3163 GetMagickPixelPacket(implode_image,&zero);
3164 resample_filter=AcquireResampleFilterThreadSet(image,
3165 UndefinedVirtualPixelMethod,MagickTrue,exception);
3166 image_view=AcquireCacheView(image);
3167 implode_view=AcquireCacheView(implode_image);
3168 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3169 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
3171 for (y=0; y < (ssize_t) image->rows; y++)
3185 register IndexPacket
3186 *restrict implode_indexes;
3191 register PixelPacket
3194 if (status == MagickFalse)
3196 q=GetCacheViewAuthenticPixels(implode_view,0,y,implode_image->columns,1,
3198 if (q == (PixelPacket *) NULL)
3203 implode_indexes=GetCacheViewAuthenticIndexQueue(implode_view);
3204 delta.y=scale.y*(double) (y-center.y);
3206 id=GetOpenMPThreadId();
3207 for (x=0; x < (ssize_t) image->columns; x++)
3210 Determine if the pixel is within an ellipse.
3212 delta.x=scale.x*(double) (x-center.x);
3213 distance=delta.x*delta.x+delta.y*delta.y;
3214 if (distance < (radius*radius))
3224 factor=pow(sin((double) (MagickPI*sqrt((double) distance)/
3225 radius/2)),-amount);
3226 (void) ResamplePixelColor(resample_filter[id],(double)
3227 (factor*delta.x/scale.x+center.x),(double) (factor*delta.y/
3228 scale.y+center.y),&pixel);
3229 SetPixelPacket(implode_image,&pixel,q,implode_indexes+x);
3233 if (SyncCacheViewAuthenticPixels(implode_view,exception) == MagickFalse)
3235 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3240 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3241 #pragma omp critical (MagickCore_ImplodeImage)
3243 proceed=SetImageProgress(image,ImplodeImageTag,progress++,image->rows);
3244 if (proceed == MagickFalse)
3248 implode_view=DestroyCacheView(implode_view);
3249 image_view=DestroyCacheView(image_view);
3250 resample_filter=DestroyResampleFilterThreadSet(resample_filter);
3251 if (status == MagickFalse)
3252 implode_image=DestroyImage(implode_image);
3253 return(implode_image);
3257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3261 % M o r p h I m a g e s %
3265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3267 % The MorphImages() method requires a minimum of two images. The first
3268 % image is transformed into the second by a number of intervening images
3269 % as specified by frames.
3271 % The format of the MorphImage method is:
3273 % Image *MorphImages(const Image *image,const size_t number_frames,
3274 % ExceptionInfo *exception)
3276 % A description of each parameter follows:
3278 % o image: the image.
3280 % o number_frames: Define the number of in-between image to generate.
3281 % The more in-between frames, the smoother the morph.
3283 % o exception: return any errors or warnings in this structure.
3286 MagickExport Image *MorphImages(const Image *image,
3287 const size_t number_frames,ExceptionInfo *exception)
3289 #define MorphImageTag "Morph/Image"
3305 register const Image
3315 Clone first frame in sequence.
3317 assert(image != (Image *) NULL);
3318 assert(image->signature == MagickSignature);
3319 if (image->debug != MagickFalse)
3320 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3321 assert(exception != (ExceptionInfo *) NULL);
3322 assert(exception->signature == MagickSignature);
3323 morph_images=CloneImage(image,0,0,MagickTrue,exception);
3324 if (morph_images == (Image *) NULL)
3325 return((Image *) NULL);
3326 if (GetNextImageInList(image) == (Image *) NULL)
3331 for (i=1; i < (ssize_t) number_frames; i++)
3333 morph_image=CloneImage(image,0,0,MagickTrue,exception);
3334 if (morph_image == (Image *) NULL)
3336 morph_images=DestroyImageList(morph_images);
3337 return((Image *) NULL);
3339 AppendImageToList(&morph_images,morph_image);
3340 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3345 proceed=SetImageProgress(image,MorphImageTag,(MagickOffsetType) i,
3347 if (proceed == MagickFalse)
3351 return(GetFirstImageInList(morph_images));
3354 Morph image sequence.
3359 for ( ; GetNextImageInList(next) != (Image *) NULL; next=GetNextImageInList(next))
3361 for (i=0; i < (ssize_t) number_frames; i++)
3367 beta=(MagickRealType) (i+1.0)/(MagickRealType) (number_frames+1.0);
3369 morph_image=ZoomImage(next,(size_t) (alpha*next->columns+beta*
3370 GetNextImageInList(next)->columns+0.5),(size_t) (alpha*
3371 next->rows+beta*GetNextImageInList(next)->rows+0.5),exception);
3372 if (morph_image == (Image *) NULL)
3374 morph_images=DestroyImageList(morph_images);
3375 return((Image *) NULL);
3377 if (SetImageStorageClass(morph_image,DirectClass) == MagickFalse)
3379 InheritException(exception,&morph_image->exception);
3380 morph_image=DestroyImage(morph_image);
3381 return((Image *) NULL);
3383 AppendImageToList(&morph_images,morph_image);
3384 morph_images=GetLastImageInList(morph_images);
3385 morph_image=ZoomImage(GetNextImageInList(next),morph_images->columns,
3386 morph_images->rows,exception);
3387 if (morph_image == (Image *) NULL)
3389 morph_images=DestroyImageList(morph_images);
3390 return((Image *) NULL);
3392 image_view=AcquireCacheView(morph_image);
3393 morph_view=AcquireCacheView(morph_images);
3394 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3395 #pragma omp parallel for schedule(dynamic,4) shared(status)
3397 for (y=0; y < (ssize_t) morph_images->rows; y++)
3402 register const PixelPacket
3408 register PixelPacket
3411 if (status == MagickFalse)
3413 p=GetCacheViewVirtualPixels(image_view,0,y,morph_image->columns,1,
3415 q=GetCacheViewAuthenticPixels(morph_view,0,y,morph_images->columns,1,
3417 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
3422 for (x=0; x < (ssize_t) morph_images->columns; x++)
3424 q->red=ClampToQuantum(alpha*q->red+beta*GetRedPixelComponent(p));
3425 q->green=ClampToQuantum(alpha*q->green+beta*
3426 GetGreenPixelComponent(p));
3427 q->blue=ClampToQuantum(alpha*q->blue+beta*GetBluePixelComponent(p));
3428 q->opacity=ClampToQuantum(alpha*q->opacity+beta*
3429 GetOpacityPixelComponent(p));
3433 sync=SyncCacheViewAuthenticPixels(morph_view,exception);
3434 if (sync == MagickFalse)
3437 morph_view=DestroyCacheView(morph_view);
3438 image_view=DestroyCacheView(image_view);
3439 morph_image=DestroyImage(morph_image);
3441 if (i < (ssize_t) number_frames)
3444 Clone last frame in sequence.
3446 morph_image=CloneImage(GetNextImageInList(next),0,0,MagickTrue,exception);
3447 if (morph_image == (Image *) NULL)
3449 morph_images=DestroyImageList(morph_images);
3450 return((Image *) NULL);
3452 AppendImageToList(&morph_images,morph_image);
3453 morph_images=GetLastImageInList(morph_images);
3454 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3459 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3460 #pragma omp critical (MagickCore_MorphImages)
3462 proceed=SetImageProgress(image,MorphImageTag,scene,
3463 GetImageListLength(image));
3464 if (proceed == MagickFalse)
3469 if (GetNextImageInList(next) != (Image *) NULL)
3471 morph_images=DestroyImageList(morph_images);
3472 return((Image *) NULL);
3474 return(GetFirstImageInList(morph_images));
3478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3482 % P l a s m a I m a g e %
3486 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3488 % PlasmaImage() initializes an image with plasma fractal values. The image
3489 % must be initialized with a base color and the random number generator
3490 % seeded before this method is called.
3492 % The format of the PlasmaImage method is:
3494 % MagickBooleanType PlasmaImage(Image *image,const SegmentInfo *segment,
3495 % size_t attenuate,size_t depth)
3497 % A description of each parameter follows:
3499 % o image: the image.
3501 % o segment: Define the region to apply plasma fractals values.
3503 % o attenuate: Define the plasmattenuation factor.
3505 % o depth: Limit the plasma recursion depth.
3509 static inline Quantum PlasmaPixel(RandomInfo *random_info,
3510 const MagickRealType pixel,const MagickRealType noise)
3515 plasma=ClampToQuantum(pixel+noise*GetPseudoRandomValue(random_info)-
3520 MagickExport MagickBooleanType PlasmaImageProxy(Image *image,
3521 RandomInfo *random_info,const SegmentInfo *segment,size_t attenuate,
3540 if (((segment->x2-segment->x1) == 0.0) && ((segment->y2-segment->y1) == 0.0))
3548 Divide the area into quadrants and recurse.
3552 x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5);
3553 y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5);
3554 local_info=(*segment);
3555 local_info.x2=(double) x_mid;
3556 local_info.y2=(double) y_mid;
3557 (void) PlasmaImageProxy(image,random_info,&local_info,attenuate,depth);
3558 local_info=(*segment);
3559 local_info.y1=(double) y_mid;
3560 local_info.x2=(double) x_mid;
3561 (void) PlasmaImageProxy(image,random_info,&local_info,attenuate,depth);
3562 local_info=(*segment);
3563 local_info.x1=(double) x_mid;
3564 local_info.y2=(double) y_mid;
3565 (void) PlasmaImageProxy(image,random_info,&local_info,attenuate,depth);
3566 local_info=(*segment);
3567 local_info.x1=(double) x_mid;
3568 local_info.y1=(double) y_mid;
3569 return(PlasmaImageProxy(image,random_info,&local_info,attenuate,depth));
3571 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
3572 return(MagickFalse);
3573 x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5);
3574 y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5);
3575 if ((segment->x1 == (double) x_mid) && (segment->x2 == (double) x_mid) &&
3576 (segment->y1 == (double) y_mid) && (segment->y2 == (double) y_mid))
3577 return(MagickFalse);
3579 Average pixels and apply plasma.
3581 exception=(&image->exception);
3582 plasma=(MagickRealType) QuantumRange/(2.0*attenuate);
3583 if ((segment->x1 != (double) x_mid) || (segment->x2 != (double) x_mid))
3585 register PixelPacket
3591 x=(ssize_t) ceil(segment->x1-0.5);
3592 (void) GetOneVirtualPixel(image,x,(ssize_t) ceil(segment->y1-0.5),&u,
3594 (void) GetOneVirtualPixel(image,x,(ssize_t) ceil(segment->y2-0.5),&v,
3596 q=QueueAuthenticPixels(image,x,y_mid,1,1,exception);
3597 if (q == (PixelPacket *) NULL)
3599 q->red=PlasmaPixel(random_info,(MagickRealType) (u.red+v.red)/2.0,
3601 q->green=PlasmaPixel(random_info,(MagickRealType) (u.green+v.green)/2.0,
3603 q->blue=PlasmaPixel(random_info,(MagickRealType) (u.blue+v.blue)/2.0,
3605 (void) SyncAuthenticPixels(image,exception);
3606 if (segment->x1 != segment->x2)
3611 x=(ssize_t) ceil(segment->x2-0.5);
3612 (void) GetOneVirtualPixel(image,x,(ssize_t) ceil(segment->y1-0.5),&u,
3614 (void) GetOneVirtualPixel(image,x,(ssize_t) ceil(segment->y2-0.5),&v,
3616 q=QueueAuthenticPixels(image,x,y_mid,1,1,exception);
3617 if (q == (PixelPacket *) NULL)
3619 q->red=PlasmaPixel(random_info,(MagickRealType) (u.red+v.red)/2.0,
3621 q->green=PlasmaPixel(random_info,(MagickRealType) (u.green+v.green)/
3623 q->blue=PlasmaPixel(random_info,(MagickRealType) (u.blue+v.blue)/2.0,
3625 (void) SyncAuthenticPixels(image,exception);
3628 if ((segment->y1 != (double) y_mid) || (segment->y2 != (double) y_mid))
3630 if ((segment->x1 != (double) x_mid) || (segment->y2 != (double) y_mid))
3632 register PixelPacket
3638 y=(ssize_t) ceil(segment->y2-0.5);
3639 (void) GetOneVirtualPixel(image,(ssize_t) ceil(segment->x1-0.5),y,&u,
3641 (void) GetOneVirtualPixel(image,(ssize_t) ceil(segment->x2-0.5),y,&v,
3643 q=QueueAuthenticPixels(image,x_mid,y,1,1,exception);
3644 if (q == (PixelPacket *) NULL)
3646 q->red=PlasmaPixel(random_info,(MagickRealType) (u.red+v.red)/2.0,
3648 q->green=PlasmaPixel(random_info,(MagickRealType) (u.green+v.green)/
3650 q->blue=PlasmaPixel(random_info,(MagickRealType) (u.blue+v.blue)/2.0,
3652 (void) SyncAuthenticPixels(image,exception);
3654 if (segment->y1 != segment->y2)
3656 register PixelPacket
3662 y=(ssize_t) ceil(segment->y1-0.5);
3663 (void) GetOneVirtualPixel(image,(ssize_t) ceil(segment->x1-0.5),y,&u,
3665 (void) GetOneVirtualPixel(image,(ssize_t) ceil(segment->x2-0.5),y,&v,
3667 q=QueueAuthenticPixels(image,x_mid,y,1,1,exception);
3668 if (q == (PixelPacket *) NULL)
3670 q->red=PlasmaPixel(random_info,(MagickRealType) (u.red+v.red)/2.0,
3672 q->green=PlasmaPixel(random_info,(MagickRealType) (u.green+v.green)/
3674 q->blue=PlasmaPixel(random_info,(MagickRealType) (u.blue+v.blue)/2.0,
3676 (void) SyncAuthenticPixels(image,exception);
3679 if ((segment->x1 != segment->x2) || (segment->y1 != segment->y2))
3681 register PixelPacket
3687 x=(ssize_t) ceil(segment->x1-0.5);
3688 y=(ssize_t) ceil(segment->y1-0.5);
3689 (void) GetOneVirtualPixel(image,x,y,&u,exception);
3690 x=(ssize_t) ceil(segment->x2-0.5);
3691 y=(ssize_t) ceil(segment->y2-0.5);
3692 (void) GetOneVirtualPixel(image,x,y,&v,exception);
3693 q=QueueAuthenticPixels(image,x_mid,y_mid,1,1,exception);
3694 if (q == (PixelPacket *) NULL)
3696 q->red=PlasmaPixel(random_info,(MagickRealType) (u.red+v.red)/2.0,
3698 q->green=PlasmaPixel(random_info,(MagickRealType) (u.green+v.green)/2.0,
3700 q->blue=PlasmaPixel(random_info,(MagickRealType) (u.blue+v.blue)/2.0,
3702 (void) SyncAuthenticPixels(image,exception);
3704 if (((segment->x2-segment->x1) < 3.0) && ((segment->y2-segment->y1) < 3.0))
3706 return(MagickFalse);
3709 MagickExport MagickBooleanType PlasmaImage(Image *image,
3710 const SegmentInfo *segment,size_t attenuate,size_t depth)
3718 if (image->debug != MagickFalse)
3719 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3720 assert(image != (Image *) NULL);
3721 assert(image->signature == MagickSignature);
3722 if (image->debug != MagickFalse)
3723 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3724 random_info=AcquireRandomInfo();
3725 status=PlasmaImageProxy(image,random_info,segment,attenuate,depth);
3726 random_info=DestroyRandomInfo(random_info);
3731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3735 % P o l a r o i d I m a g e %
3739 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3741 % PolaroidImage() simulates a Polaroid picture.
3743 % The format of the AnnotateImage method is:
3745 % Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
3746 % const double angle,ExceptionInfo exception)
3748 % A description of each parameter follows:
3750 % o image: the image.
3752 % o draw_info: the draw info.
3754 % o angle: Apply the effect along this angle.
3756 % o exception: return any errors or warnings in this structure.
3759 MagickExport Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
3760 const double angle,ExceptionInfo *exception)
3781 Simulate a Polaroid picture.
3783 assert(image != (Image *) NULL);
3784 assert(image->signature == MagickSignature);
3785 if (image->debug != MagickFalse)
3786 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3787 assert(exception != (ExceptionInfo *) NULL);
3788 assert(exception->signature == MagickSignature);
3789 quantum=(ssize_t) MagickMax(MagickMax((double) image->columns,(double)
3790 image->rows)/25.0,10.0);
3791 height=image->rows+2*quantum;
3792 caption_image=(Image *) NULL;
3793 value=GetImageProperty(image,"Caption");
3794 if (value != (const char *) NULL)
3798 geometry[MaxTextExtent];
3813 Generate caption image.
3815 caption_image=CloneImage(image,image->columns,1,MagickTrue,exception);
3816 if (caption_image == (Image *) NULL)
3817 return((Image *) NULL);
3818 annotate_info=CloneDrawInfo((const ImageInfo *) NULL,draw_info);
3819 caption=InterpretImageProperties((ImageInfo *) NULL,(Image *) image,
3821 (void) CloneString(&annotate_info->text,caption);
3822 count=FormatMagickCaption(caption_image,annotate_info,&metrics,&caption);
3823 status=SetImageExtent(caption_image,image->columns,(size_t)
3824 ((count+1)*(metrics.ascent-metrics.descent)+0.5));
3825 if (status == MagickFalse)
3826 caption_image=DestroyImage(caption_image);
3829 caption_image->background_color=image->border_color;
3830 (void) SetImageBackgroundColor(caption_image);
3831 (void) CloneString(&annotate_info->text,caption);
3832 (void) FormatMagickString(geometry,MaxTextExtent,"+0+%g",
3834 if (annotate_info->gravity == UndefinedGravity)
3835 (void) CloneString(&annotate_info->geometry,AcquireString(
3837 (void) AnnotateImage(caption_image,annotate_info);
3838 height+=caption_image->rows;
3840 annotate_info=DestroyDrawInfo(annotate_info);
3841 caption=DestroyString(caption);
3843 picture_image=CloneImage(image,image->columns+2*quantum,height,MagickTrue,
3845 if (picture_image == (Image *) NULL)
3847 if (caption_image != (Image *) NULL)
3848 caption_image=DestroyImage(caption_image);
3849 return((Image *) NULL);
3851 picture_image->background_color=image->border_color;
3852 (void) SetImageBackgroundColor(picture_image);
3853 (void) CompositeImage(picture_image,OverCompositeOp,image,quantum,quantum);
3854 if (caption_image != (Image *) NULL)
3856 (void) CompositeImage(picture_image,OverCompositeOp,caption_image,
3857 quantum,(ssize_t) (image->rows+3*quantum/2));
3858 caption_image=DestroyImage(caption_image);
3860 (void) QueryColorDatabase("none",&picture_image->background_color,exception);
3861 (void) SetImageAlphaChannel(picture_image,OpaqueAlphaChannel);
3862 rotate_image=RotateImage(picture_image,90.0,exception);
3863 picture_image=DestroyImage(picture_image);
3864 if (rotate_image == (Image *) NULL)
3865 return((Image *) NULL);
3866 picture_image=rotate_image;
3867 bend_image=WaveImage(picture_image,0.01*picture_image->rows,2.0*
3868 picture_image->columns,exception);
3869 picture_image=DestroyImage(picture_image);
3870 if (bend_image == (Image *) NULL)
3871 return((Image *) NULL);
3872 InheritException(&bend_image->exception,exception);
3873 picture_image=bend_image;
3874 rotate_image=RotateImage(picture_image,-90.0,exception);
3875 picture_image=DestroyImage(picture_image);
3876 if (rotate_image == (Image *) NULL)
3877 return((Image *) NULL);
3878 picture_image=rotate_image;
3879 picture_image->background_color=image->background_color;
3880 polaroid_image=ShadowImage(picture_image,80.0,2.0,quantum/3,quantum/3,
3882 if (polaroid_image == (Image *) NULL)
3884 picture_image=DestroyImage(picture_image);
3885 return(picture_image);
3887 flop_image=FlopImage(polaroid_image,exception);
3888 polaroid_image=DestroyImage(polaroid_image);
3889 if (flop_image == (Image *) NULL)
3891 picture_image=DestroyImage(picture_image);
3892 return(picture_image);
3894 polaroid_image=flop_image;
3895 (void) CompositeImage(polaroid_image,OverCompositeOp,picture_image,
3896 (ssize_t) (-0.01*picture_image->columns/2.0),0L);
3897 picture_image=DestroyImage(picture_image);
3898 (void) QueryColorDatabase("none",&polaroid_image->background_color,exception);
3899 rotate_image=RotateImage(polaroid_image,angle,exception);
3900 polaroid_image=DestroyImage(polaroid_image);
3901 if (rotate_image == (Image *) NULL)
3902 return((Image *) NULL);
3903 polaroid_image=rotate_image;
3904 trim_image=TrimImage(polaroid_image,exception);
3905 polaroid_image=DestroyImage(polaroid_image);
3906 if (trim_image == (Image *) NULL)
3907 return((Image *) NULL);
3908 polaroid_image=trim_image;
3909 return(polaroid_image);
3913 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3917 % S e p i a T o n e I m a g e %
3921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3923 % MagickSepiaToneImage() applies a special effect to the image, similar to the
3924 % effect achieved in a photo darkroom by sepia toning. Threshold ranges from
3925 % 0 to QuantumRange and is a measure of the extent of the sepia toning. A
3926 % threshold of 80% is a good starting point for a reasonable tone.
3928 % The format of the SepiaToneImage method is:
3930 % Image *SepiaToneImage(const Image *image,const double threshold,
3931 % ExceptionInfo *exception)
3933 % A description of each parameter follows:
3935 % o image: the image.
3937 % o threshold: the tone threshold.
3939 % o exception: return any errors or warnings in this structure.
3942 MagickExport Image *SepiaToneImage(const Image *image,const double threshold,
3943 ExceptionInfo *exception)
3945 #define SepiaToneImageTag "SepiaTone/Image"
3964 Initialize sepia-toned image attributes.
3966 assert(image != (const Image *) NULL);
3967 assert(image->signature == MagickSignature);
3968 if (image->debug != MagickFalse)
3969 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3970 assert(exception != (ExceptionInfo *) NULL);
3971 assert(exception->signature == MagickSignature);
3972 sepia_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
3973 if (sepia_image == (Image *) NULL)
3974 return((Image *) NULL);
3975 if (SetImageStorageClass(sepia_image,DirectClass) == MagickFalse)
3977 InheritException(exception,&sepia_image->exception);
3978 sepia_image=DestroyImage(sepia_image);
3979 return((Image *) NULL);
3982 Tone each row of the image.
3986 image_view=AcquireCacheView(image);
3987 sepia_view=AcquireCacheView(sepia_image);
3988 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3989 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
3991 for (y=0; y < (ssize_t) image->rows; y++)
3993 register const PixelPacket
3999 register PixelPacket
4002 if (status == MagickFalse)
4004 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4005 q=QueueCacheViewAuthenticPixels(sepia_view,0,y,sepia_image->columns,1,
4007 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
4012 for (x=0; x < (ssize_t) image->columns; x++)
4018 intensity=(MagickRealType) PixelIntensityToQuantum(p);
4019 tone=intensity > threshold ? (MagickRealType) QuantumRange : intensity+
4020 (MagickRealType) QuantumRange-threshold;
4021 q->red=ClampToQuantum(tone);
4022 tone=intensity > (7.0*threshold/6.0) ? (MagickRealType) QuantumRange :
4023 intensity+(MagickRealType) QuantumRange-7.0*threshold/6.0;
4024 q->green=ClampToQuantum(tone);
4025 tone=intensity < (threshold/6.0) ? 0 : intensity-threshold/6.0;
4026 q->blue=ClampToQuantum(tone);
4028 if ((MagickRealType) q->green < tone)
4029 q->green=ClampToQuantum(tone);
4030 if ((MagickRealType) q->blue < tone)
4031 q->blue=ClampToQuantum(tone);
4035 if (SyncCacheViewAuthenticPixels(sepia_view,exception) == MagickFalse)
4037 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4042 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4043 #pragma omp critical (MagickCore_SepiaToneImage)
4045 proceed=SetImageProgress(image,SepiaToneImageTag,progress++,
4047 if (proceed == MagickFalse)
4051 sepia_view=DestroyCacheView(sepia_view);
4052 image_view=DestroyCacheView(image_view);
4053 (void) NormalizeImage(sepia_image);
4054 (void) ContrastImage(sepia_image,MagickTrue);
4055 if (status == MagickFalse)
4056 sepia_image=DestroyImage(sepia_image);
4057 return(sepia_image);
4061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4065 % S h a d o w I m a g e %
4069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4071 % ShadowImage() simulates a shadow from the specified image and returns it.
4073 % The format of the ShadowImage method is:
4075 % Image *ShadowImage(const Image *image,const double opacity,
4076 % const double sigma,const ssize_t x_offset,const ssize_t y_offset,
4077 % ExceptionInfo *exception)
4079 % A description of each parameter follows:
4081 % o image: the image.
4083 % o opacity: percentage transparency.
4085 % o sigma: the standard deviation of the Gaussian, in pixels.
4087 % o x_offset: the shadow x-offset.
4089 % o y_offset: the shadow y-offset.
4091 % o exception: return any errors or warnings in this structure.
4094 MagickExport Image *ShadowImage(const Image *image,const double opacity,
4095 const double sigma,const ssize_t x_offset,const ssize_t y_offset,
4096 ExceptionInfo *exception)
4098 #define ShadowImageTag "Shadow/Image"
4120 assert(image != (Image *) NULL);
4121 assert(image->signature == MagickSignature);
4122 if (image->debug != MagickFalse)
4123 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4124 assert(exception != (ExceptionInfo *) NULL);
4125 assert(exception->signature == MagickSignature);
4126 clone_image=CloneImage(image,0,0,MagickTrue,exception);
4127 if (clone_image == (Image *) NULL)
4128 return((Image *) NULL);
4129 (void) SetImageVirtualPixelMethod(clone_image,EdgeVirtualPixelMethod);
4130 clone_image->compose=OverCompositeOp;
4131 border_info.width=(size_t) floor(2.0*sigma+0.5);
4132 border_info.height=(size_t) floor(2.0*sigma+0.5);
4135 (void) QueryColorDatabase("none",&clone_image->border_color,exception);
4136 border_image=BorderImage(clone_image,&border_info,exception);
4137 clone_image=DestroyImage(clone_image);
4138 if (border_image == (Image *) NULL)
4139 return((Image *) NULL);
4140 if (border_image->matte == MagickFalse)
4141 (void) SetImageAlphaChannel(border_image,OpaqueAlphaChannel);
4147 image_view=AcquireCacheView(border_image);
4148 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4149 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
4151 for (y=0; y < (ssize_t) border_image->rows; y++)
4156 register PixelPacket
4159 if (status == MagickFalse)
4161 q=GetCacheViewAuthenticPixels(image_view,0,y,border_image->columns,1,
4163 if (q == (PixelPacket *) NULL)
4168 for (x=0; x < (ssize_t) border_image->columns; x++)
4170 q->red=border_image->background_color.red;
4171 q->green=border_image->background_color.green;
4172 q->blue=border_image->background_color.blue;
4173 if (border_image->matte == MagickFalse)
4174 q->opacity=border_image->background_color.opacity;
4176 q->opacity=ClampToQuantum((MagickRealType) (QuantumRange-
4177 GetAlphaPixelComponent(q)*opacity/100.0));
4180 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4182 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4187 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4188 #pragma omp critical (MagickCore_ShadowImage)
4190 proceed=SetImageProgress(image,ShadowImageTag,progress++,
4191 border_image->rows);
4192 if (proceed == MagickFalse)
4196 image_view=DestroyCacheView(image_view);
4197 shadow_image=BlurImageChannel(border_image,AlphaChannel,0.0,sigma,exception);
4198 border_image=DestroyImage(border_image);
4199 if (shadow_image == (Image *) NULL)
4200 return((Image *) NULL);
4201 if (shadow_image->page.width == 0)
4202 shadow_image->page.width=shadow_image->columns;
4203 if (shadow_image->page.height == 0)
4204 shadow_image->page.height=shadow_image->rows;
4205 shadow_image->page.width+=x_offset-(ssize_t) border_info.width;
4206 shadow_image->page.height+=y_offset-(ssize_t) border_info.height;
4207 shadow_image->page.x+=x_offset-(ssize_t) border_info.width;
4208 shadow_image->page.y+=y_offset-(ssize_t) border_info.height;
4209 return(shadow_image);
4213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4217 % S k e t c h I m a g e %
4221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4223 % SketchImage() simulates a pencil sketch. We convolve the image with a
4224 % Gaussian operator of the given radius and standard deviation (sigma). For
4225 % reasonable results, radius should be larger than sigma. Use a radius of 0
4226 % and SketchImage() selects a suitable radius for you. Angle gives the angle
4229 % The format of the SketchImage method is:
4231 % Image *SketchImage(const Image *image,const double radius,
4232 % const double sigma,const double angle,ExceptionInfo *exception)
4234 % A description of each parameter follows:
4236 % o image: the image.
4238 % o radius: the radius of the Gaussian, in pixels, not counting
4241 % o sigma: the standard deviation of the Gaussian, in pixels.
4243 % o angle: Apply the effect along this angle.
4245 % o exception: return any errors or warnings in this structure.
4248 MagickExport Image *SketchImage(const Image *image,const double radius,
4249 const double sigma,const double angle,ExceptionInfo *exception)
4271 **restrict random_info;
4276 random_image=CloneImage(image,image->columns << 1,image->rows << 1,
4277 MagickTrue,exception);
4278 if (random_image == (Image *) NULL)
4279 return((Image *) NULL);
4281 GetMagickPixelPacket(random_image,&zero);
4282 random_info=AcquireRandomInfoThreadSet();
4283 random_view=AcquireCacheView(random_image);
4284 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4285 #pragma omp parallel for schedule(dynamic,4) shared(status)
4287 for (y=0; y < (ssize_t) random_image->rows; y++)
4295 register IndexPacket
4301 register PixelPacket
4304 if (status == MagickFalse)
4306 q=QueueCacheViewAuthenticPixels(random_view,0,y,random_image->columns,1,
4308 if (q == (PixelPacket *) NULL)
4313 indexes=GetCacheViewAuthenticIndexQueue(random_view);
4315 id=GetOpenMPThreadId();
4316 for (x=0; x < (ssize_t) random_image->columns; x++)
4318 pixel.red=(MagickRealType) (QuantumRange*
4319 GetPseudoRandomValue(random_info[id]));
4320 pixel.green=pixel.red;
4321 pixel.blue=pixel.red;
4322 if (image->colorspace == CMYKColorspace)
4323 pixel.index=pixel.red;
4324 SetPixelPacket(random_image,&pixel,q,indexes+x);
4327 if (SyncCacheViewAuthenticPixels(random_view,exception) == MagickFalse)
4330 random_view=DestroyCacheView(random_view);
4331 random_info=DestroyRandomInfoThreadSet(random_info);
4332 if (status == MagickFalse)
4334 random_image=DestroyImage(random_image);
4335 return(random_image);
4337 blur_image=MotionBlurImage(random_image,radius,sigma,angle,exception);
4338 random_image=DestroyImage(random_image);
4339 if (blur_image == (Image *) NULL)
4340 return((Image *) NULL);
4341 dodge_image=EdgeImage(blur_image,radius,exception);
4342 blur_image=DestroyImage(blur_image);
4343 if (dodge_image == (Image *) NULL)
4344 return((Image *) NULL);
4345 (void) NormalizeImage(dodge_image);
4346 (void) NegateImage(dodge_image,MagickFalse);
4347 (void) TransformImage(&dodge_image,(char *) NULL,"50%");
4348 sketch_image=CloneImage(image,0,0,MagickTrue,exception);
4349 if (sketch_image == (Image *) NULL)
4351 dodge_image=DestroyImage(dodge_image);
4352 return((Image *) NULL);
4354 (void) CompositeImage(sketch_image,ColorDodgeCompositeOp,dodge_image,0,0);
4355 dodge_image=DestroyImage(dodge_image);
4356 blend_image=CloneImage(image,0,0,MagickTrue,exception);
4357 if (blend_image == (Image *) NULL)
4359 sketch_image=DestroyImage(sketch_image);
4360 return((Image *) NULL);
4362 (void) SetImageArtifact(blend_image,"compose:args","20x80");
4363 (void) CompositeImage(sketch_image,BlendCompositeOp,blend_image,0,0);
4364 blend_image=DestroyImage(blend_image);
4365 return(sketch_image);
4369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4373 % S o l a r i z e I m a g e %
4377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4379 % SolarizeImage() applies a special effect to the image, similar to the effect
4380 % achieved in a photo darkroom by selectively exposing areas of photo
4381 % sensitive paper to light. Threshold ranges from 0 to QuantumRange and is a
4382 % measure of the extent of the solarization.
4384 % The format of the SolarizeImage method is:
4386 % MagickBooleanType SolarizeImage(Image *image,const double threshold)
4388 % A description of each parameter follows:
4390 % o image: the image.
4392 % o threshold: Define the extent of the solarization.
4395 MagickExport MagickBooleanType SolarizeImage(Image *image,
4396 const double threshold)
4398 #define SolarizeImageTag "Solarize/Image"
4415 assert(image != (Image *) NULL);
4416 assert(image->signature == MagickSignature);
4417 if (image->debug != MagickFalse)
4418 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4419 if (image->storage_class == PseudoClass)
4427 for (i=0; i < (ssize_t) image->colors; i++)
4429 if ((MagickRealType) image->colormap[i].red > threshold)
4430 image->colormap[i].red=(Quantum) QuantumRange-image->colormap[i].red;
4431 if ((MagickRealType) image->colormap[i].green > threshold)
4432 image->colormap[i].green=(Quantum) QuantumRange-
4433 image->colormap[i].green;
4434 if ((MagickRealType) image->colormap[i].blue > threshold)
4435 image->colormap[i].blue=(Quantum) QuantumRange-
4436 image->colormap[i].blue;
4444 exception=(&image->exception);
4445 image_view=AcquireCacheView(image);
4446 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4447 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
4449 for (y=0; y < (ssize_t) image->rows; y++)
4454 register PixelPacket
4457 if (status == MagickFalse)
4459 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
4461 if (q == (PixelPacket *) NULL)
4466 for (x=0; x < (ssize_t) image->columns; x++)
4468 if ((MagickRealType) q->red > threshold)
4469 q->red=(Quantum) QuantumRange-q->red;
4470 if ((MagickRealType) q->green > threshold)
4471 q->green=(Quantum) QuantumRange-q->green;
4472 if ((MagickRealType) q->blue > threshold)
4473 q->blue=(Quantum) QuantumRange-q->blue;
4476 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4478 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4483 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4484 #pragma omp critical (MagickCore_SolarizeImage)
4486 proceed=SetImageProgress(image,SolarizeImageTag,progress++,image->rows);
4487 if (proceed == MagickFalse)
4491 image_view=DestroyCacheView(image_view);
4496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4500 % S t e g a n o I m a g e %
4504 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4506 % SteganoImage() hides a digital watermark within the image. Recover
4507 % the hidden watermark later to prove that the authenticity of an image.
4508 % Offset defines the start position within the image to hide the watermark.
4510 % The format of the SteganoImage method is:
4512 % Image *SteganoImage(const Image *image,Image *watermark,
4513 % ExceptionInfo *exception)
4515 % A description of each parameter follows:
4517 % o image: the image.
4519 % o watermark: the watermark image.
4521 % o exception: return any errors or warnings in this structure.
4524 MagickExport Image *SteganoImage(const Image *image,const Image *watermark,
4525 ExceptionInfo *exception)
4527 #define GetBit(alpha,i) ((((size_t) (alpha) >> (size_t) \
4529 #define SetBit(alpha,i,set) (alpha)=(Quantum) ((set) != 0 ? (size_t) (alpha) \
4530 | (one << (size_t) (i)) : (size_t) (alpha) & ~(one << (size_t) (i)))
4531 #define SteganoImageTag "Stegano/Image"
4554 register PixelPacket
4562 Initialize steganographic image attributes.
4564 assert(image != (const Image *) NULL);
4565 assert(image->signature == MagickSignature);
4566 if (image->debug != MagickFalse)
4567 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4568 assert(watermark != (const Image *) NULL);
4569 assert(watermark->signature == MagickSignature);
4570 assert(exception != (ExceptionInfo *) NULL);
4571 assert(exception->signature == MagickSignature);
4573 stegano_image=CloneImage(image,0,0,MagickTrue,exception);
4574 if (stegano_image == (Image *) NULL)
4575 return((Image *) NULL);
4576 if (SetImageStorageClass(stegano_image,DirectClass) == MagickFalse)
4578 InheritException(exception,&stegano_image->exception);
4579 stegano_image=DestroyImage(stegano_image);
4580 return((Image *) NULL);
4582 stegano_image->depth=MAGICKCORE_QUANTUM_DEPTH;
4584 Hide watermark in low-order bits of image.
4589 depth=stegano_image->depth;
4591 for (i=(ssize_t) depth-1; (i >= 0) && (j < (ssize_t) depth); i--)
4593 for (y=0; (y < (ssize_t) watermark->rows) && (j < (ssize_t) depth); y++)
4595 for (x=0; (x < (ssize_t) watermark->columns) && (j < (ssize_t) depth); x++)
4597 (void) GetOneVirtualPixel(watermark,x,y,&pixel,exception);
4598 if ((k/(ssize_t) stegano_image->columns) >= (ssize_t) stegano_image->rows)
4600 q=GetAuthenticPixels(stegano_image,k % (ssize_t) stegano_image->columns,
4601 k/(ssize_t) stegano_image->columns,1,1,exception);
4602 if (q == (PixelPacket *) NULL)
4608 SetBit(q->red,j,GetBit(PixelIntensityToQuantum(&pixel),i));
4613 SetBit(q->green,j,GetBit(PixelIntensityToQuantum(&pixel),i));
4618 SetBit(q->blue,j,GetBit(PixelIntensityToQuantum(&pixel),i));
4622 if (SyncAuthenticPixels(stegano_image,exception) == MagickFalse)
4628 if (k == (ssize_t) (stegano_image->columns*stegano_image->columns))
4630 if (k == image->offset)
4634 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4639 proceed=SetImageProgress(image,SteganoImageTag,(MagickOffsetType)
4641 if (proceed == MagickFalse)
4645 if (stegano_image->storage_class == PseudoClass)
4646 (void) SyncImage(stegano_image);
4647 return(stegano_image);
4651 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4655 % S t e r e o A n a g l y p h I m a g e %
4659 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4661 % StereoAnaglyphImage() combines two images and produces a single image that
4662 % is the composite of a left and right image of a stereo pair. Special
4663 % red-green stereo glasses are required to view this effect.
4665 % The format of the StereoAnaglyphImage method is:
4667 % Image *StereoImage(const Image *left_image,const Image *right_image,
4668 % ExceptionInfo *exception)
4669 % Image *StereoAnaglyphImage(const Image *left_image,
4670 % const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
4671 % ExceptionInfo *exception)
4673 % A description of each parameter follows:
4675 % o left_image: the left image.
4677 % o right_image: the right image.
4679 % o exception: return any errors or warnings in this structure.
4681 % o x_offset: amount, in pixels, by which the left image is offset to the
4682 % right of the right image.
4684 % o y_offset: amount, in pixels, by which the left image is offset to the
4685 % bottom of the right image.
4689 MagickExport Image *StereoImage(const Image *left_image,
4690 const Image *right_image,ExceptionInfo *exception)
4692 return(StereoAnaglyphImage(left_image,right_image,0,0,exception));
4695 MagickExport Image *StereoAnaglyphImage(const Image *left_image,
4696 const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
4697 ExceptionInfo *exception)
4699 #define StereoImageTag "Stereo/Image"
4713 assert(left_image != (const Image *) NULL);
4714 assert(left_image->signature == MagickSignature);
4715 if (left_image->debug != MagickFalse)
4716 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4717 left_image->filename);
4718 assert(right_image != (const Image *) NULL);
4719 assert(right_image->signature == MagickSignature);
4720 assert(exception != (ExceptionInfo *) NULL);
4721 assert(exception->signature == MagickSignature);
4722 assert(right_image != (const Image *) NULL);
4724 if ((left_image->columns != right_image->columns) ||
4725 (left_image->rows != right_image->rows))
4726 ThrowImageException(ImageError,"LeftAndRightImageSizesDiffer");
4728 Initialize stereo image attributes.
4730 stereo_image=CloneImage(left_image,left_image->columns,left_image->rows,
4731 MagickTrue,exception);
4732 if (stereo_image == (Image *) NULL)
4733 return((Image *) NULL);
4734 if (SetImageStorageClass(stereo_image,DirectClass) == MagickFalse)
4736 InheritException(exception,&stereo_image->exception);
4737 stereo_image=DestroyImage(stereo_image);
4738 return((Image *) NULL);
4741 Copy left image to red channel and right image to blue channel.
4743 for (y=0; y < (ssize_t) stereo_image->rows; y++)
4745 register const PixelPacket
4752 register PixelPacket
4755 p=GetVirtualPixels(left_image,-x_offset,y-y_offset,image->columns,1,
4757 q=GetVirtualPixels(right_image,0,y,right_image->columns,1,exception);
4758 r=QueueAuthenticPixels(stereo_image,0,y,stereo_image->columns,1,exception);
4759 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL) ||
4760 (r == (PixelPacket *) NULL))
4762 for (x=0; x < (ssize_t) stereo_image->columns; x++)
4764 r->red=GetRedPixelComponent(p);
4767 r->opacity=(Quantum) ((p->opacity+q->opacity)/2);
4772 if (SyncAuthenticPixels(stereo_image,exception) == MagickFalse)
4774 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4779 proceed=SetImageProgress(image,StereoImageTag,(MagickOffsetType) y,
4780 stereo_image->rows);
4781 if (proceed == MagickFalse)
4785 return(stereo_image);
4789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4793 % S w i r l I m a g e %
4797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4799 % SwirlImage() swirls the pixels about the center of the image, where
4800 % degrees indicates the sweep of the arc through which each pixel is moved.
4801 % You get a more dramatic effect as the degrees move from 1 to 360.
4803 % The format of the SwirlImage method is:
4805 % Image *SwirlImage(const Image *image,double degrees,
4806 % ExceptionInfo *exception)
4808 % A description of each parameter follows:
4810 % o image: the image.
4812 % o degrees: Define the tightness of the swirling effect.
4814 % o exception: return any errors or warnings in this structure.
4817 MagickExport Image *SwirlImage(const Image *image,double degrees,
4818 ExceptionInfo *exception)
4820 #define SwirlImageTag "Swirl/Image"
4846 **restrict resample_filter;
4852 Initialize swirl image attributes.
4854 assert(image != (const Image *) NULL);
4855 assert(image->signature == MagickSignature);
4856 if (image->debug != MagickFalse)
4857 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4858 assert(exception != (ExceptionInfo *) NULL);
4859 assert(exception->signature == MagickSignature);
4860 swirl_image=CloneImage(image,0,0,MagickTrue,exception);
4861 if (swirl_image == (Image *) NULL)
4862 return((Image *) NULL);
4863 if (SetImageStorageClass(swirl_image,DirectClass) == MagickFalse)
4865 InheritException(exception,&swirl_image->exception);
4866 swirl_image=DestroyImage(swirl_image);
4867 return((Image *) NULL);
4869 if (swirl_image->background_color.opacity != OpaqueOpacity)
4870 swirl_image->matte=MagickTrue;
4872 Compute scaling factor.
4874 center.x=(double) image->columns/2.0;
4875 center.y=(double) image->rows/2.0;
4876 radius=MagickMax(center.x,center.y);
4879 if (image->columns > image->rows)
4880 scale.y=(double) image->columns/(double) image->rows;
4882 if (image->columns < image->rows)
4883 scale.x=(double) image->rows/(double) image->columns;
4884 degrees=(double) DegreesToRadians(degrees);
4890 GetMagickPixelPacket(swirl_image,&zero);
4891 resample_filter=AcquireResampleFilterThreadSet(image,
4892 UndefinedVirtualPixelMethod,MagickTrue,exception);
4893 image_view=AcquireCacheView(image);
4894 swirl_view=AcquireCacheView(swirl_image);
4895 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4896 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
4898 for (y=0; y < (ssize_t) image->rows; y++)
4912 register IndexPacket
4913 *restrict swirl_indexes;
4918 register PixelPacket
4921 if (status == MagickFalse)
4923 q=GetCacheViewAuthenticPixels(swirl_view,0,y,swirl_image->columns,1,
4925 if (q == (PixelPacket *) NULL)
4930 swirl_indexes=GetCacheViewAuthenticIndexQueue(swirl_view);
4931 delta.y=scale.y*(double) (y-center.y);
4933 id=GetOpenMPThreadId();
4934 for (x=0; x < (ssize_t) image->columns; x++)
4937 Determine if the pixel is within an ellipse.
4939 delta.x=scale.x*(double) (x-center.x);
4940 distance=delta.x*delta.x+delta.y*delta.y;
4941 if (distance < (radius*radius))
4951 factor=1.0-sqrt((double) distance)/radius;
4952 sine=sin((double) (degrees*factor*factor));
4953 cosine=cos((double) (degrees*factor*factor));
4954 (void) ResamplePixelColor(resample_filter[id],(double) ((cosine*
4955 delta.x-sine*delta.y)/scale.x+center.x),(double) ((sine*delta.x+
4956 cosine*delta.y)/scale.y+center.y),&pixel);
4957 SetPixelPacket(swirl_image,&pixel,q,swirl_indexes+x);
4961 if (SyncCacheViewAuthenticPixels(swirl_view,exception) == MagickFalse)
4963 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4968 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4969 #pragma omp critical (MagickCore_SwirlImage)
4971 proceed=SetImageProgress(image,SwirlImageTag,progress++,image->rows);
4972 if (proceed == MagickFalse)
4976 swirl_view=DestroyCacheView(swirl_view);
4977 image_view=DestroyCacheView(image_view);
4978 resample_filter=DestroyResampleFilterThreadSet(resample_filter);
4979 if (status == MagickFalse)
4980 swirl_image=DestroyImage(swirl_image);
4981 return(swirl_image);
4985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4989 % T i n t I m a g e %
4993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4995 % TintImage() applies a color vector to each pixel in the image. The length
4996 % of the vector is 0 for black and white and at its maximum for the midtones.
4997 % The vector weighting function is f(x)=(1-(4.0*((x-0.5)*(x-0.5))))
4999 % The format of the TintImage method is:
5001 % Image *TintImage(const Image *image,const char *opacity,
5002 % const PixelPacket tint,ExceptionInfo *exception)
5004 % A description of each parameter follows:
5006 % o image: the image.
5008 % o opacity: A color value used for tinting.
5010 % o tint: A color value used for tinting.
5012 % o exception: return any errors or warnings in this structure.
5015 MagickExport Image *TintImage(const Image *image,const char *opacity,
5016 const PixelPacket tint,ExceptionInfo *exception)
5018 #define TintImageTag "Tint/Image"
5047 Allocate tint image.
5049 assert(image != (const Image *) NULL);
5050 assert(image->signature == MagickSignature);
5051 if (image->debug != MagickFalse)
5052 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5053 assert(exception != (ExceptionInfo *) NULL);
5054 assert(exception->signature == MagickSignature);
5055 tint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
5056 if (tint_image == (Image *) NULL)
5057 return((Image *) NULL);
5058 if (SetImageStorageClass(tint_image,DirectClass) == MagickFalse)
5060 InheritException(exception,&tint_image->exception);
5061 tint_image=DestroyImage(tint_image);
5062 return((Image *) NULL);
5064 if (opacity == (const char *) NULL)
5067 Determine RGB values of the color.
5069 flags=ParseGeometry(opacity,&geometry_info);
5070 pixel.red=geometry_info.rho;
5071 if ((flags & SigmaValue) != 0)
5072 pixel.green=geometry_info.sigma;
5074 pixel.green=pixel.red;
5075 if ((flags & XiValue) != 0)
5076 pixel.blue=geometry_info.xi;
5078 pixel.blue=pixel.red;
5079 if ((flags & PsiValue) != 0)
5080 pixel.opacity=geometry_info.psi;
5082 pixel.opacity=(MagickRealType) OpaqueOpacity;
5083 color_vector.red=(MagickRealType) (pixel.red*tint.red/100.0-
5084 PixelIntensity(&tint));
5085 color_vector.green=(MagickRealType) (pixel.green*tint.green/100.0-
5086 PixelIntensity(&tint));
5087 color_vector.blue=(MagickRealType) (pixel.blue*tint.blue/100.0-
5088 PixelIntensity(&tint));
5094 image_view=AcquireCacheView(image);
5095 tint_view=AcquireCacheView(tint_image);
5096 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5097 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
5099 for (y=0; y < (ssize_t) image->rows; y++)
5101 register const PixelPacket
5107 register PixelPacket
5110 if (status == MagickFalse)
5112 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
5113 q=QueueCacheViewAuthenticPixels(tint_view,0,y,tint_image->columns,1,
5115 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
5120 for (x=0; x < (ssize_t) image->columns; x++)
5128 weight=QuantumScale*p->red-0.5;
5129 pixel.red=(MagickRealType) p->red+color_vector.red*(1.0-(4.0*
5131 SetRedPixelComponent(q,ClampRedPixelComponent(&pixel));
5132 weight=QuantumScale*p->green-0.5;
5133 pixel.green=(MagickRealType) p->green+color_vector.green*(1.0-(4.0*
5135 SetGreenPixelComponent(q,ClampGreenPixelComponent(&pixel));
5136 weight=QuantumScale*p->blue-0.5;
5137 pixel.blue=(MagickRealType) p->blue+color_vector.blue*(1.0-(4.0*
5139 SetBluePixelComponent(q,ClampBluePixelComponent(&pixel));
5140 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
5144 if (SyncCacheViewAuthenticPixels(tint_view,exception) == MagickFalse)
5146 if (image->progress_monitor != (MagickProgressMonitor) NULL)
5151 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5152 #pragma omp critical (MagickCore_TintImage)
5154 proceed=SetImageProgress(image,TintImageTag,progress++,image->rows);
5155 if (proceed == MagickFalse)
5159 tint_view=DestroyCacheView(tint_view);
5160 image_view=DestroyCacheView(image_view);
5161 if (status == MagickFalse)
5162 tint_image=DestroyImage(tint_image);
5167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5171 % V i g n e t t e I m a g e %
5175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5177 % VignetteImage() softens the edges of the image in vignette style.
5179 % The format of the VignetteImage method is:
5181 % Image *VignetteImage(const Image *image,const double radius,
5182 % const double sigma,const ssize_t x,const ssize_t y,ExceptionInfo *exception)
5184 % A description of each parameter follows:
5186 % o image: the image.
5188 % o radius: the radius of the pixel neighborhood.
5190 % o sigma: the standard deviation of the Gaussian, in pixels.
5192 % o x, y: Define the x and y ellipse offset.
5194 % o exception: return any errors or warnings in this structure.
5197 MagickExport Image *VignetteImage(const Image *image,const double radius,
5198 const double sigma,const ssize_t x,const ssize_t y,ExceptionInfo *exception)
5201 ellipse[MaxTextExtent];
5212 assert(image != (Image *) NULL);
5213 assert(image->signature == MagickSignature);
5214 if (image->debug != MagickFalse)
5215 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5216 assert(exception != (ExceptionInfo *) NULL);
5217 assert(exception->signature == MagickSignature);
5218 canvas_image=CloneImage(image,0,0,MagickTrue,exception);
5219 if (canvas_image == (Image *) NULL)
5220 return((Image *) NULL);
5221 if (SetImageStorageClass(canvas_image,DirectClass) == MagickFalse)
5223 InheritException(exception,&canvas_image->exception);
5224 canvas_image=DestroyImage(canvas_image);
5225 return((Image *) NULL);
5227 canvas_image->matte=MagickTrue;
5228 oval_image=CloneImage(canvas_image,canvas_image->columns,
5229 canvas_image->rows,MagickTrue,exception);
5230 if (oval_image == (Image *) NULL)
5232 canvas_image=DestroyImage(canvas_image);
5233 return((Image *) NULL);
5235 (void) QueryColorDatabase("#000000",&oval_image->background_color,exception);
5236 (void) SetImageBackgroundColor(oval_image);
5237 draw_info=CloneDrawInfo((const ImageInfo *) NULL,(const DrawInfo *) NULL);
5238 (void) QueryColorDatabase("#ffffff",&draw_info->fill,exception);
5239 (void) QueryColorDatabase("#ffffff",&draw_info->stroke,exception);
5240 (void) FormatMagickString(ellipse,MaxTextExtent,
5241 "ellipse %g,%g,%g,%g,0.0,360.0",image->columns/2.0,
5242 image->rows/2.0,image->columns/2.0-x,image->rows/2.0-y);
5243 draw_info->primitive=AcquireString(ellipse);
5244 (void) DrawImage(oval_image,draw_info);
5245 draw_info=DestroyDrawInfo(draw_info);
5246 blur_image=BlurImage(oval_image,radius,sigma,exception);
5247 oval_image=DestroyImage(oval_image);
5248 if (blur_image == (Image *) NULL)
5250 canvas_image=DestroyImage(canvas_image);
5251 return((Image *) NULL);
5253 blur_image->matte=MagickFalse;
5254 (void) CompositeImage(canvas_image,CopyOpacityCompositeOp,blur_image,0,0);
5255 blur_image=DestroyImage(blur_image);
5256 vignette_image=MergeImageLayers(canvas_image,FlattenLayer,exception);
5257 canvas_image=DestroyImage(canvas_image);
5258 return(vignette_image);
5262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5266 % W a v e I m a g e %
5270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5272 % WaveImage() creates a "ripple" effect in the image by shifting the pixels
5273 % vertically along a sine wave whose amplitude and wavelength is specified
5274 % by the given parameters.
5276 % The format of the WaveImage method is:
5278 % Image *WaveImage(const Image *image,const double amplitude,
5279 % const double wave_length,ExceptionInfo *exception)
5281 % A description of each parameter follows:
5283 % o image: the image.
5285 % o amplitude, wave_length: Define the amplitude and wave length of the
5288 % o exception: return any errors or warnings in this structure.
5291 MagickExport Image *WaveImage(const Image *image,const double amplitude,
5292 const double wave_length,ExceptionInfo *exception)
5294 #define WaveImageTag "Wave/Image"
5318 **restrict resample_filter;
5324 Initialize wave image attributes.
5326 assert(image != (Image *) NULL);
5327 assert(image->signature == MagickSignature);
5328 if (image->debug != MagickFalse)
5329 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5330 assert(exception != (ExceptionInfo *) NULL);
5331 assert(exception->signature == MagickSignature);
5332 wave_image=CloneImage(image,image->columns,(size_t) (image->rows+2.0*
5333 fabs(amplitude)),MagickTrue,exception);
5334 if (wave_image == (Image *) NULL)
5335 return((Image *) NULL);
5336 if (SetImageStorageClass(wave_image,DirectClass) == MagickFalse)
5338 InheritException(exception,&wave_image->exception);
5339 wave_image=DestroyImage(wave_image);
5340 return((Image *) NULL);
5342 if (wave_image->background_color.opacity != OpaqueOpacity)
5343 wave_image->matte=MagickTrue;
5347 sine_map=(MagickRealType *) AcquireQuantumMemory((size_t) wave_image->columns,
5349 if (sine_map == (MagickRealType *) NULL)
5351 wave_image=DestroyImage(wave_image);
5352 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
5354 for (i=0; i < (ssize_t) wave_image->columns; i++)
5355 sine_map[i]=fabs(amplitude)+amplitude*sin((2*MagickPI*i)/wave_length);
5361 GetMagickPixelPacket(wave_image,&zero);
5362 resample_filter=AcquireResampleFilterThreadSet(image,
5363 BackgroundVirtualPixelMethod,MagickTrue,exception);
5364 wave_view=AcquireCacheView(wave_image);
5365 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5366 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
5368 for (y=0; y < (ssize_t) wave_image->rows; y++)
5376 register IndexPacket
5382 register PixelPacket
5385 if (status == MagickFalse)
5387 q=QueueCacheViewAuthenticPixels(wave_view,0,y,wave_image->columns,1,
5389 if (q == (PixelPacket *) NULL)
5394 indexes=GetCacheViewAuthenticIndexQueue(wave_view);
5396 id=GetOpenMPThreadId();
5397 for (x=0; x < (ssize_t) wave_image->columns; x++)
5399 (void) ResamplePixelColor(resample_filter[id],(double) x,(double) (y-
5400 sine_map[x]),&pixel);
5401 SetPixelPacket(wave_image,&pixel,q,indexes+x);
5404 if (SyncCacheViewAuthenticPixels(wave_view,exception) == MagickFalse)
5406 if (image->progress_monitor != (MagickProgressMonitor) NULL)
5411 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5412 #pragma omp critical (MagickCore_WaveImage)
5414 proceed=SetImageProgress(image,WaveImageTag,progress++,image->rows);
5415 if (proceed == MagickFalse)
5419 wave_view=DestroyCacheView(wave_view);
5420 resample_filter=DestroyResampleFilterThreadSet(resample_filter);
5421 sine_map=(MagickRealType *) RelinquishMagickMemory(sine_map);
5422 if (status == MagickFalse)
5423 wave_image=DestroyImage(wave_image);